Erlang Mnesia 中的分页搜索
Pagination search in Erlang Mnesia
例如给定记录
-record(item, {
id,
time,
status}).
我要搜索 1000 到 1100 项,按时间排序 status =:= <<"finished">>
有什么建议吗?
我觉得,你应该用mnesia:select/2
到selectstatus =:= <<"finished">>
的对象,然后你可以用lists:sort
把结果按time
排序,最后可以用lists:sublist/3
把1000
的元素减到1100
.
这是 link:
http://www.erlang.org/doc/man/mnesia.html#select-2
http://www.erlang.org/doc/man/lists.html#sort-2
http://www.erlang.org/doc/man/lists.html#sublist-3
这取决于您的查询内容。如果您需要按许多不同的列进行排序,那么我会考虑使用 SQL 而不是 Mnesia。
但是如果您只需要您描述的那种查询,您应该能够使用 ordered_set
type of table to handle the ordering and mnesia:select/4
来处理分页和约束。
这里有一些未经测试的代码可以为您提供要点:
% time goes first because it's our primary sort key
-record(statuses, {time, id, status}).
...
create_table() ->
mnesia:create_table(statuses, [
{attributes, record_info(fields, statuses)}
,{type, ordered_set}
]).
-spec fetch_paged(integer()) -> {[tuple()], continuation()}|'$end_of_table'.
fetch_paged(PageSize) ->
MatchSpec = {#statuses{id = '', status = <<"finished">>, _ = '_'}, [], ['']},
mnesia:select(statuses, [MatchSpec], PageSize, read).
-spec next_page(continuation()) -> {[tuple()], continuation()}|'$end_of_table'.
next_page(Cont) ->
mnesia:select(Cont).
基本上,mnesia:select/4
会为您提供一页结果和下一页结果的延续。没有像 SQL 数据库那样跳到第 1000 个结果的内置方法,所以如果你需要这种能力,你可以自己构建它(保留一个时间索引,以便你可以快速查找第 1000 个结果table 中的时间是 {{2015,4,12},{23,53,8}}
,然后在 运行 select
.
时将其用作守卫
你可能会使用 QLC Cursor,像这样:
order(table_name,[id,Direction]) ->
case Direction of
descent -> fun(A,B) -> A#table_name.id > B#table_name.id end;
ascent -> fun(A,B) -> A#table_name.id < B#table_name.id end
end;
select(universal,[Data_module,Table,Minor,Major,Order_by,Direction,Query]) ->
try
if
Minor == Major -> {error};
Minor == 0; Major == 0 -> {error};
true ->
case apply(Data_module,order,[Table,[Order_by,Direction]]) of
error -> {error};
Order ->
Transaction = fun() ->
Query = qlc:q([X||X <- mnesia:table(Table)]),
Handler = qlc:sort(Query,[{order,Order}]),
Cursor = qlc:cursor(Handler),
if
Minor == 1 ->
Result = qlc:next_answers(Cursor,Major),
qlc:delete_cursor(Cursor),
Result;
true ->
qlc:next_answers(Cursor,Minor-1),
Result = qlc:next_answers(Cursor,Major-Minor+1),
qlc:delete_cursor(Cursor),
Result
end
end,
mnesia:transaction(Transaction)
end
end
catch
Exception:Reason -> {error}
end.
QLC的说明书在这里Qlc:reference
但是这种方式在生产中并不是最快的方式,因为中等重负载就足够了(它测试了每秒 10000 个连接),但更多的时候你会在内存空闲 space 内遇到问题,你需要提高它
例如给定记录
-record(item, {
id,
time,
status}).
我要搜索 1000 到 1100 项,按时间排序 status =:= <<"finished">>
有什么建议吗?
我觉得,你应该用mnesia:select/2
到selectstatus =:= <<"finished">>
的对象,然后你可以用lists:sort
把结果按time
排序,最后可以用lists:sublist/3
把1000
的元素减到1100
.
这是 link: http://www.erlang.org/doc/man/mnesia.html#select-2 http://www.erlang.org/doc/man/lists.html#sort-2 http://www.erlang.org/doc/man/lists.html#sublist-3
这取决于您的查询内容。如果您需要按许多不同的列进行排序,那么我会考虑使用 SQL 而不是 Mnesia。
但是如果您只需要您描述的那种查询,您应该能够使用 ordered_set
type of table to handle the ordering and mnesia:select/4
来处理分页和约束。
这里有一些未经测试的代码可以为您提供要点:
% time goes first because it's our primary sort key
-record(statuses, {time, id, status}).
...
create_table() ->
mnesia:create_table(statuses, [
{attributes, record_info(fields, statuses)}
,{type, ordered_set}
]).
-spec fetch_paged(integer()) -> {[tuple()], continuation()}|'$end_of_table'.
fetch_paged(PageSize) ->
MatchSpec = {#statuses{id = '', status = <<"finished">>, _ = '_'}, [], ['']},
mnesia:select(statuses, [MatchSpec], PageSize, read).
-spec next_page(continuation()) -> {[tuple()], continuation()}|'$end_of_table'.
next_page(Cont) ->
mnesia:select(Cont).
基本上,mnesia:select/4
会为您提供一页结果和下一页结果的延续。没有像 SQL 数据库那样跳到第 1000 个结果的内置方法,所以如果你需要这种能力,你可以自己构建它(保留一个时间索引,以便你可以快速查找第 1000 个结果table 中的时间是 {{2015,4,12},{23,53,8}}
,然后在 运行 select
.
你可能会使用 QLC Cursor,像这样:
order(table_name,[id,Direction]) ->
case Direction of
descent -> fun(A,B) -> A#table_name.id > B#table_name.id end;
ascent -> fun(A,B) -> A#table_name.id < B#table_name.id end
end;
select(universal,[Data_module,Table,Minor,Major,Order_by,Direction,Query]) ->
try
if
Minor == Major -> {error};
Minor == 0; Major == 0 -> {error};
true ->
case apply(Data_module,order,[Table,[Order_by,Direction]]) of
error -> {error};
Order ->
Transaction = fun() ->
Query = qlc:q([X||X <- mnesia:table(Table)]),
Handler = qlc:sort(Query,[{order,Order}]),
Cursor = qlc:cursor(Handler),
if
Minor == 1 ->
Result = qlc:next_answers(Cursor,Major),
qlc:delete_cursor(Cursor),
Result;
true ->
qlc:next_answers(Cursor,Minor-1),
Result = qlc:next_answers(Cursor,Major-Minor+1),
qlc:delete_cursor(Cursor),
Result
end
end,
mnesia:transaction(Transaction)
end
end
catch
Exception:Reason -> {error}
end.
QLC的说明书在这里Qlc:reference 但是这种方式在生产中并不是最快的方式,因为中等重负载就足够了(它测试了每秒 10000 个连接),但更多的时候你会在内存空闲 space 内遇到问题,你需要提高它