大数据排行榜分区排序--erlang实现
db表:以玩家id为主键
-record(r_ranking_partition, { id = 0, %% 玩家id section = 0, %% 区id rank = 0, %% 排名 value = 0, %% 值 time = 0, %% 时间 info, %% r_ranking_info extra = [] }).
分区ets表:
-record(r_rank_section, { section_id = 0, rank = [] %% 排行榜 仅有玩家id,按值排序 }).
进程字典区人数:key(区id)-value(该区的人数),根据区id进行排序
原理:
当有玩家更新时,将数据存放在cache列表,以玩家Id为主键,每隔一段时间执行刷新。刷新时,取旧的区id,根据value值计算新的区id,对两个区内的数据进行排序,并将排名和区间人数更新db表、分区表、区人数。
取排行榜时,根据范围取数据,假设取的是{3,50}排名范围的玩家,只要根据区人数进行计算,获得所在区,从分区表内获得玩家id以及排序,就能获取到玩家具体的排行榜信息。
%% 获取排行榜列表 get_rank_lst_detail(RankKey, StartN, EndN) -> RoleIds = get_rank_lst(RankKey, StartN, EndN), {_, Lst} = lists:foldl( fun(RoleId, {N, Acc}) -> Role = get_role(RankKey, RoleId), {N+1, [setelement(?RANK_CROSS_RANK, Role, N) | Acc]} end, {StartN, []}, RoleIds), Lst. get_rank_lst(RankKey, StartN, EndN) when EndN>=StartN -> CountLst = get_count(RankKey), Len = EndN-StartN+1, Ets = get_ets(RankKey), get_rank_lst(CountLst, Ets, StartN, Len, []). get_rank_lst(_, _Ets, _StartN, 0, Acc) -> Acc; get_rank_lst([], _Ets, _StartN, _, Acc) -> Acc; get_rank_lst([{SectionId, Count} | T], Ets, StartN, Len, Acc) -> if Count>=StartN -> RoleIds = get_section(Ets, SectionId), SubLst = lists:sublist(RoleIds, StartN, Len), get_rank_lst(T, Ets, 1, Len-length(SubLst), Acc++SubLst); true -> get_rank_lst(T, Ets, StartN-Count, Len, Acc) end.
优点:避免了对大量玩家的排序操作,当有数据更新时仅排序分片的数据。