まず、シナリオを見てみましょう。Web サイトでは、1 週間以内に継続的にログインしたユーザーと、1 か月以内にログインしたユーザーをカウントする必要があります。
Mysql などの従来のデータベースを使用して実装した場合、実現は困難です。しかし、Redis を使用すると、それは非常に簡単になります。 Redisのコレクション型とビットマップ型を簡単に実現できます。今日は主に、ビットマップを使用してアクティブユーザーをカウントする機能を実装する方法について説明します。
ビットマップ
コンピューター システムでは、情報の最小単位はバイトです。1 バイトは 8 ビットに相当します。各ビットは、 0 または 1 のみを指定できます (コンピュータはこれら 2 つの数値のみを認識します)。ビットマップを使用すると、ビットを直接操作できます。
ビッグマップは配列と見なされます。配列内の各ビットは 0 または 1 のみです。ここでは配列の添え字がオフセットとみなされます。
ビットマップに関連するいくつかのコマンドを紹介します。
setbit
#setbit キー オフセット値:対応するビットの値を設定します。
たとえば、ユーザー 3、8、23、および 32 が今日 Web サイトにアクセスした場合、setbit user:view:2020-5-17 3 1 setbit user:view:2020-5-17 8 1 setbit user:view:2020-5-17 23 1 setbit user:view:2020-5-17 32 1
開発のヒント: 多くのアプリケーション ID は 1 から始まりませんが、多くは 1001、10001 などの指定された番号から始まります。これらについては、スペースの無駄を防ぐために、設定時に初期値を減算することができます。
getbit
#getbit キー オフセットは、指定したビットの値ユーザー No. 8 とユーザー No. 45 が今日ログインしているかどうかを知りたい場合は、
127.0.0.1:6379> getbit user:view:2020-5-17 8 (integer) 1 127.0.0.1:6379> getbit user:view:2020-5-17 45 (integer) 0
ユーザー No. 8 が表示されます。は今日ログインしましたが、ユーザー番号 45 は今日ログインしていません。
#bitcountbitcount key [start] [end] 指定範囲 1
## の数値を取得します#今日ログインしたユーザーの数を知りたいので、127.0.0.1:6379> bitcount user:view:2020-5-17
(integer) 4
ビットマップ間の操作
bitop op destkey key [key ...]
bitop コマンドは、複数のビットマップに対して論理積 (and)、結合 (or)、非 (not)、排他的論理和 (xor) を実行でき、演算結果を返します。 destkeyに保存されます。 3日連続でログインしたユーザー数、つまり5月17日、18日、19日にログインしたユーザー数を知りたい場合。
過去 3 日間のログイン状況は次のとおりです。
5 月 17 日、3 日、8 日、23 日、32 人のユーザーがログインしました
ユーザー No. 3、23、43、および 54 は 5 月 18 日にログインしました
ユーザー No.3、5、23、32、56、および 78 5 月 19 日にログインしました
127.0.0.1:6379> bitop and three:and user:view:2020-5-17 user:view:2020-5-18 user:view:2020-5-19 127.0.0.1:6379> bitcount three:and (integer) 2
過去 3 日間にログインしたユーザーの数を知りたい場合。
127.0.0.1:6379> bitop or three:or user:view:2020-5-17 user:view:2020-5-18 user:view:2020-5-19 (integer) 10 127.0.0.1:6379> bitcount three:or (integer) 9
実践的な戦闘
上記の知識を完了したら、必要な要件を完了できます。つまり、一定期間内の連続ログイン数をカウントする必要があります。週単位のユーザー、および 1 か月以内にログインしたユーザー。 まず、30 日以内のユーザーのログイン状況をシミュレートします。疑似コードは次のとおりです:
for ($i = 0; $i < 20000; $i++) { $userId = mt_rand(1, 10000); $date = time() - 86400 * mt_rand(0, 30); $key = 'userlogin_'.date('Ymd', $date); $redis->setBit($key, $userId, 1); }
1 週間以内にログインしたユーザーを取得します。もちろん、すべてを取得するわけではありません。ある数値だけをまとめて取得したいのですが、ページングのように一度に取得したいので、ある程度の数の疑似コードは次のとおりです:
for ($i = 1; $i <= 7; $i ++) { $key = "userlogin_".date('Ymd', time() - (86400*$i)); if ($i == 1) { $redis->bitOp('and', 'week_logined', $key); } else { $redis->bitOp('and', 'week_logined', 'week_logined', $key); } } // 获取前50个用户 $userIds = []; for ($i=1; $i<=10000; $i++) { $ret = $redis->getBit('week_logined', $i); $ret && $userIds[] = $i; if (count($userIds) >=50) break; }注意点があり、エラーでもあります。初回のビトップ時は、week_logined がまだ存在しないため、操作が実行されます。キーは 1 つだけです。 2回目から始める場合はopのキーが2つあります。
1 か月以内にログインしたユーザーを取得する場合、考え方は基本的に上記と同じですが、and が orfor ($i = 1; $i <= 3; $i ++) {
$key = "userlogin_".date('Ymd', time() - (86400*$i));
$redis->bitOp('or', 'month_loginOnce', 'month_loginOnce', $key);
}
// 获取一个月内登陆过的用户
$userIds = [];
for ($i=1; $i<=10000; $i++) {
$ret = $redis->getBit('month_loginOnce', $i);
$ret && $userIds[] = $i;
}
に変更される点が異なります。ご覧のとおり、 doing or と and.of にはまだいくつかの違いがあります。または、最初から判断する必要はありません。理由は誰でも理解できるからです。
以上がRedis ビットマップを使用してアクティブ ユーザーをカウントするの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。