我们想知道如何有效地找到两个ets表之间的相互元素,我们尝试了ETS和QLC模块,但找不到解决方法,我们在[bag]选项上使用ets,这意味着我们为同一个键具有多个值。
我们正在寻找最快,最有效的解决方案。
很难回答您的问题,因为我们不知道表的大小,其内容的结构,执行上下文(并行度,频率...)
您是否使用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表的任何方法。
您可以迭代一个表,并为每个元素检查它是否在第二个表中。使用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:first
,ets:next
和ets:lookup
进行迭代,以避免一次复制所有数据。
当然,最好衡量和验证哪种方法最适合您的情况。