Erlang-ETS表之间的比较

问题描述 投票:4回答:2

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

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

erlang elixir otp ets
2个回答
1
投票

很难回答您的问题,因为我们不知道表的大小,其内容的结构,执行上下文(并行度,频率...)

您是否使用list: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表,该键是表的完整记录,然后使用过滤第二个表的记录函数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表的任何方法。


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]}]).
[]

我不确定性能是否100%,但是我认为,因为我们要匹配密钥,所以查找的长度为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进行迭代,以避免一次复制所有数据。

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

© www.soinside.com 2019 - 2024. All rights reserved.