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.
优点:避免了对大量玩家的排序操作,当有数据更新时仅排序分片的数据。