Redis排行榜的實現
阿新 • • 發佈:2020-09-10
場景
- 使用者邀請排行榜
users測試表結構
- 基本的資料結構
欄位 | 備註 |
id | 使用者 id |
name | 暱稱 |
invite_count | 邀請人數 |
created_at | 建立時間 |
updated_at | 更新時間 |
程式碼說明
return $this->response->paginator($data, new UserTransformer())->setMeta($userInfo);
- 使用了Dingo API
- https://learnku.com/docs/dingo-api/2.0.0/Responses/1446
常規的做法
SQL排序 --》存Redis(設定過期時間)
/** * 走資料庫 [排行榜] * @return \Dingo\Api\Http\Response */ public function rankingList() { $currentUserId = 1; if (!\Cache::has('ranking-list')) { \Cache::remember('ranking-list', 1, function (){ //laravel5.6是1分鐘, laravel5.8之後是1s // 先取排名 return User::selectRaw('id, name, email, invite_count, if(@rowNum,@rowNum := @rowNum +1,@rowNum := 1) as rank_num')->where('invite_count', '>=', 1) ->orderBy('invite_count', 'desc') ->orderBy('updated_at', 'asc') //invite_count和updated_at建聯合索引 ->paginate(); }); } $data = \Cache::get('ranking-list'); // 集合生成陣列 $result = $data->pluck('rank_num', 'id')->toArray();// 使用者名稱次 $currentUser = User::find($currentUserId); $userInfo = [ 'user_id' => $currentUserId, 'user_rank' => $result[$currentUserId] ?? '--', //取使用者名稱次,注意下標沒有的情況 'phone' => $currentUser->phone, 'invite_count' => $currentUser->invite_count, ]; return $this->response->paginator($data, new UserTransformer())->setMeta($userInfo); }
利用Zset有序集合
/** * Rides的zSet [排行榜] * $invite_count[邀請次數] , $user_id[使用者ID] * @return \Dingo\Api\Http\Response */ public function rankingList() { // 使用者建立時記錄 zAdd($key, $invite_count, $user_id) // 邀請成功時記錄 zIncrBy($key, 1, $user_id) // 檢視總的條數 zCard($key) // 查詢所有的記錄 zRevRange($key, 0, $num-1 , false); // 檢視自己的名次 zRevRank($key, $user_id) // 得到排序好的 user_ids $redis_store = \Cache::store('redis'); $store_key = $redis_store->getPrefix(); // 獲取字首 $redis = $redis_store->getRedis(); // 例項化redis $key = $store_key . 'test-ranking-list:'; /** * Mock加資料 */ $users = User::all()->toArray(); foreach ($users as $item){ $redis->zAdd($key, $item['invite_count'], $item['id']); } /** * 總排行(從大到小排序好) */ $user_ids = $redis->zRevRange($key, 0, 9 , false); // 取前10名,全部的話end為num-1,zCard($key) $ids_ordered = implode(',', $user_ids); $rankingBoard = User::whereIn('id', $user_ids) ->orderByRaw(DB::raw("FIELD(id, $ids_ordered)")) // whereIn按user_id排序返回 ->paginate(); /** * 使用者所屬排名 */ $currentUserId = 1; //當前使用者 $rank = $redis->zRevRank($key, $currentUserId); $myInfo = [ 'rank' => $rank + 1, 'user_id' => $currentUserId, ]; return $this->response->paginator($rankingBoard, new UserTransformer())->setMeta($myInfo); }