【问题标题】:Pagination search in Erlang MnesiaErlang Mnesia 中的分页搜索
【发布时间】:2015-06-17 18:29:18
【问题描述】:

例如,给定记录

-record(item, {
  id,
  time,
  status}).

我要搜索 1000 到 1100 项,按时间和status =:= <<"finished">>排序

有什么建议吗?

【问题讨论】:

    标签: search pagination erlang mnesia


    【解决方案1】:

    这取决于您的查询是什么样的。如果您需要按很多不同的列排序,那么我会考虑使用 SQL 而不是 Mnesia。

    但如果您只需要您描述的那种查询,您应该能够使用ordered_set 类型的表来处理排序和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 = '$1', status = <<"finished">>, _ = '_'}, [], ['$1']},
      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 DB 那样跳转到第 1000 个结果的内置方法,因此如果您需要该功能,您可以自己构建它(保留时间索引,以便您可以快速查找表中的第 1000 个结果是{{2015,4,12},{23,53,8}},然后在运行select 时将其用作警卫。

    【讨论】:

    • 非常有帮助。无法直接跳转到第 1000 个结果的有效方法
    • 我(相对缺乏经验)对 Mnesia 的印象是,您可以将其视为 NoSQL 数据库(完全有道理,您不能要求第 1000 页),或者您可以将其视为关系数据库DB,但没有您从像 Postgres 这样的 SQL DB 获得的顶层接口。所以如果你想要 Mnesia 这些层,你需要自己构建它们。 (这基本上就是 BlackMamba 对 fetch/sort/slice 操作所做的事情。想象一下将其写入一个进行少量缓存的 gen_server。)
    【解决方案2】:

    我想,你应该使用mnesia:select/2来选择status =:= &lt;&lt;"finished"&gt;&gt;的对象,然后你可以使用lists:sort将结果按time排序,最后你可以使用lists:sublist/3减去元素10001100

    这里是链接: 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

    【讨论】:

    • 您可以使用dirty_match_object vs select/2 来获得不错的加速。因为您可能不关心分页用例的一致性。如果您的数据集特别大,您将用完 RAM 来执行此操作。你需要使用像dirty_/next/2这样的东西。
    【解决方案3】:

    您可能会使用 QLC 光标,如下所示:

    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 个连接),但是更多的你会在内存可用空间中遇到问题,你需要提高它

    【讨论】:

      猜你喜欢
      • 2018-01-21
      • 2017-02-15
      • 1970-01-01
      • 2010-09-16
      • 2012-01-10
      • 2013-02-11
      • 2013-05-20
      • 2014-06-06
      • 2012-03-22
      相关资源
      最近更新 更多