繁体   English   中英

查询使用元组键的 erlang ETS 表

[英]Querying an erlang ETS table that uses a tuple key

我有一个 ETS 表,其中的键由 {shell,TIME,NAME,ID} 之类的记录组成,我希望允许用户使用其中任何一个组合来搜索条目。 即:在哪里

  • TIME < LOW_VALUE 和 TIME > HIGH_VALUE 或
  • TIME < 40 并且 NAME == "SAM" 或
  • 编号 == 123

我了解如何使用 fun2ms,但还不足以知道是否有一些干净的单线方法可以做到这一点。 我当前的解决方案是将搜索请求与 6 种可能的搜索类型组合进行匹配,与我所有其他广泛使用模式匹配的 erlang 代码相比,它感觉很脏。

你们能帮助我以更智能的方式使用 fun2ms 或 ETS 表吗? 我很确定这个查询可以用一行来完成。 这是我用来向您展示我拥有的 6 个函数之一的示例:

  getShells_by_Time(Tstart, Tend) ->
  Results = ets:select(schedule_row1,ets:fun2ms(
    fun(A = #activity{shell = ActivityShell,activity_data = S1Data})
      when (ActivityShell#activity_shell.tsched < Tend)
      andalso (ActivityShell#activity_shell.tsched > Tstart)  ->
      ActivityShell
    end)),

编辑:

所以这就是我目前正在尝试做的事情:

我有一条记录,我想默认为:-record(s1shell_query,{tsched = {_ScLow,_ScHigh}, id = _ID, type = _Type})。

这意味着用户可以更改他们想要匹配的任何记录条款。 问题是您不能在记录中默认未绑定变量。

我的比赛规格 function 看起来像这样:

    {ScLow,ScHigh} = ShellQuery#s3shell_query.tsched,
  ets:select(Table, ets:fun2ms(
    fun(#stage3Activity{shell = #activity_shell{tsched = Tsched, id = ID, type = Type}})
      when Tsched < ScLow, Tsched>ScHigh,ID == ID, Type == Type ->
      #activity_shell{tsched = Tsched,id = ID,type = Type}
    end)).

所以我一直在试图弄清楚如何忽略用户没有放入 shell 查询记录的匹配内容。

您可以使用自定义匹配规范守卫代替ets:fun2ms/1进行搜索,例如:

-module(match_spec_guards).
-export([new/0, populate/0, search/1]).

-record(row, {
          key :: {shell, Time :: integer(), Name :: string(), ID :: term()},
          value :: term()
         }).

new() ->
    ets:new(?MODULE, [set, named_table, {keypos, #row.key}]).

populate() ->
    [ets:insert(?MODULE, #row{key = {shell, I, integer_to_list(I), I * 1000}, value = I * 1000})
     || I <- lists:seq(1,1000)].

search(Filters) ->
    Guards = [filter_to_guard(Filter) || Filter <- Filters],
    MatchHead = {row, {shell, '$1', '$2', '$3'}, '_'},
    Result = ['$_'],
    ets:select(?MODULE, [{MatchHead, Guards, Result}]).

filter_to_guard({time_higher_than, X}) -> {'<', X, '$1'};
filter_to_guard({time_lower_than, X}) -> {'>', X, '$1'};
filter_to_guard({name_is, X}) -> {'==', '$2', X};
filter_to_guard({id_is, X}) -> {'==', '$3', X}.

你可以像这样使用它:

Erlang/OTP 22 [erts-10.7.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1]

Eshell V10.7.1  (abort with ^G)
1> c(match_spec_guards).
{ok,match_spec_guards}
2>  match_spec_guards:new().
match_spec_guards
3> match_spec_guards:populate().
[true,true,true,true,true,true,true,true,true,true,true,
 true,true,true,true,true,true,true,true,true,true,true,true,
 true,true,true,true,true,true|...]
4> match_spec_guards:search([{time_higher_than, 10}, {time_lower_than, 20}]).
[{row,{shell,15,"15",15000},15000},
 {row,{shell,16,"16",16000},16000},
 {row,{shell,17,"17",17000},17000},
 {row,{shell,12,"12",12000},12000},
 {row,{shell,13,"13",13000},13000},
 {row,{shell,11,"11",11000},11000},
 {row,{shell,19,"19",19000},19000},
 {row,{shell,14,"14",14000},14000},
 {row,{shell,18,"18",18000},18000}]
5> match_spec_guards:search([{id_is, 15000}]).
[{row,{shell,15,"15",15000},15000}]
6> match_spec_guards:search([{name_is, "15000"}]).
[]
7> match_spec_guards:search([{name_is, "15"}]).   
[{row,{shell,15,"15",15000},15000}]

您在ets:select/2中有更多关于匹配规范语法的信息

我建议使用

MatchHead = #row{key = {shell, '$1', '$2', '$3'}, value = '_'},

即使您需要调整记录定义以允许'$x''_'原子。

此外,如果您使用大表,请考虑编译匹配规范和/或使用延续。

编辑通过滥用 erlang 术语和搜索记录中有用'_'默认值之间的完整顺序,您可以获得所需的内容:


-module(match_spec_guards).
-export([new/0, populate/0, search/1]).

-record(row, {
          key :: {shell, Time :: integer(), Name :: string(), ID :: term()},
          value :: term()
         }).

-record(s1shell_query, {
          tsched_low = 0,
          tsched_high = undefined,
          id = '_',
          name = '_'
         }).

new() ->
    ets:new(?MODULE, [set, named_table, {keypos, #row.key}]).

populate() ->
    [ets:insert(?MODULE, #row{key = {shell, I, integer_to_list(I), I * 1000}, value = I * 1000})
     || I <- lists:seq(1,1000)].

search(#s1shell_query{tsched_low = Low, tsched_high = High} = Query) ->
    MatchHead = #row{key = {shell, '$1', Query#s1shell_query.name, Query#s1shell_query.id}, value = '_'},
    Guards = [{'>', High, '$1'}, {'=<', Low, '$1'}],
    ets:select(?MODULE, [{MatchHead, Guards, ['$_']}]).

idname如果已定义,将从记录中获取(如果未定义则使用'_' ),如果已定义,则守卫将自然执行过滤,如果未定义,则使用完整顺序作为上限(原子总是高于数字,无论原子和数字如何)。

使用示例如下:

Erlang/OTP 22 [erts-10.7.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1]

Eshell V10.7.1  (abort with ^G)
1>  c(match_spec_guards).
{ok,match_spec_guards}
2> match_spec_guards:new().
match_spec_guards
3> match_spec_guards:populate().
[true,true,true,true,true,true,true,true,true,true,true,
 true,true,true,true,true,true,true,true,true,true,true,true,
 true,true,true,true,true,true|...]
4>  rr(match_spec_guards).
[row,s1shell_query]
7> match_spec_guards:search(#s1shell_query{id = 14000}).
[#row{key = {shell,14,"14",14000},value = 14000}]
8> match_spec_guards:search(#s1shell_query{name = "14"}).
[#row{key = {shell,14,"14",14000},value = 14000}]
9> match_spec_guards:search(#s1shell_query{tsched_high = 20}).                 
[#row{key = {shell,1,"1",1000},value = 1000},
 #row{key = {shell,15,"15",15000},value = 15000},
 #row{key = {shell,6,"6",6000},value = 6000},
 #row{key = {shell,16,"16",16000},value = 16000},
 #row{key = {shell,8,"8",8000},value = 8000},
 #row{key = {shell,2,"2",2000},value = 2000},
 #row{key = {shell,9,"9",9000},value = 9000},
 #row{key = {shell,17,"17",17000},value = 17000},
 #row{key = {shell,12,"12",12000},value = 12000},
 #row{key = {shell,7,"7",7000},value = 7000},
 #row{key = {shell,13,"13",13000},value = 13000},
 #row{key = {shell,10,"10",10000},value = 10000},
 #row{key = {shell,3,"3",3000},value = 3000},
 #row{key = {shell,11,"11",11000},value = 11000},
 #row{key = {shell,19,"19",19000},value = 19000},
 #row{key = {shell,14,"14",14000},value = 14000},
 #row{key = {shell,5,"5",5000},value = 5000},
 #row{key = {shell,4,"4",4000},value = 4000},
 #row{key = {shell,18,"18",18000},value = 18000}]
10> match_spec_guards:search(#s1shell_query{tsched_low = 998}).
[#row{key = {shell,998,"998",998000},value = 998000},
 #row{key = {shell,999,"999",999000},value = 999000},
 #row{key = {shell,1000,"1000",1000000},value = 1000000}]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM