Erlang - 比较ETS表

时间:2015-08-04 17:39:56

标签: sql erlang elixir otp ets

我们想知道如何有效地找到两个ets表之间的相互元素,我们尝试了ETS和QLC模块但是却找不到如何去做, 我们在[bag]选项上使用ets,这意味着我们对同一个键有几个值。

我们正在寻找最快,最有效的解决方案。

2 个答案:

答案 0 :(得分:1)

很难回答你的问题,因为我们对表格大小,内容结构,执行环境(并行度,频率......)一无所知。

您是否使用列表测试基本解决方案:filter / 2?

1> ets:new(t,[bag,named_table]).
t
2> ets:new(s,[bag,named_table]).
s
3> ets:insert(t,[{1,a},{1,b},{2,c}]).
true
4> ets:insert(s,[{3,a},{1,b},{2,d}]).
true
5> lists:filter(fun(X) -> lists:member(X,ets:tab2list(s)) end, ets:tab2list(t)).
[{1,b}]
6> 

如果(我猜)您的表格很大和/或内容复杂,您可以创建一个新的ets set table,其中key是表的完整记录,然后使用过滤第二个表的记录函数ets:insert_new / 2作为谓词,创建的开销可能值得与元素的搜索相比:

6> ets:new(r,[set,named_table]).                                                
r
7> lists:foreach(fun(X) -> ets:insert(r,{X}) end,ets:tab2list(s)).
ok
8> ets:tab2list(r).
[{{3,a}},{{2,d}},{{1,b}}]
9> lists:filter(fun(Y) -> ets:insert_new(r,{Y}) == false end,ets:tab2list(t)).
[{1,b}]
10> 

我在本例中使用了ets:tab2list / 1来轻松地在shell中进行演示,但是可以使用任何遍历ets表的方法。

答案 1 :(得分:0)

您可以迭代一个表,并为每个元素检查它是否在第二个表中。使用ets:select可以减少要复制的数据。

例如,假设我们构建了一个下表:

1> Tab = ets:new(foo, [bag]).
2> [ets:insert(Tab, {X, Y}) || X <- lists:seq(1,10), Y <- lists:seq(1, 10)].

要检查表中是否有{3, 4}对,您可以执行以下操作:

3> ets:select(Tab, [{{3, 4}, [], [true]}]).
[true]

如果该对不在表中,您将获得一个空列表:

4> ets:select(Tab, [{{3, 11}, [], [true]}]).
[]

我不是百分之百地确定性能,但我认为,因为我们匹配密钥,查找将是O(M),其中M是同一密钥下的平均项目数。

最后一部分是从另一个表中获取所有内容并迭代地调用ets:select。由于您需要从第一个表中获取所有数据,ets:tab2list可能没问题,但需要注意的是它会导致所有数据被复制。这是一个简单的例子:

5> Tab2 = ets:new(bar, [bag]),
[ets:insert(Tab2, {X, Y}) || X <- lists:seq(7,12), Y <- lists:seq(7, 12)].

% iterate Tab2, return only tuples which exist in Tab
6> [Element || Element <- ets:tab2list(Tab2), ets:select(Tab, [{Element, [], [true]}]) =:= [true]].

如果两个表都非常大,您可能需要考虑使用ets:firstets:nextets:lookup进行手动迭代,以避免一次复制所有数据。

当然,最好衡量并验证哪种方法最适合您的情况。