Erlang - ETS 表之间的比较

Posted

技术标签:

【中文标题】Erlang - ETS 表之间的比较【英文标题】:Erlang - Comparing between ETS tables 【发布时间】:2015-10-27 05:52:11 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

很难回答您的问题,因为我们对表格大小、内容结构、执行上下文(并行度?频率...)一无所知

您是否使用 lists: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 表的方法。

【讨论】:

【参考方案2】:

您可以迭代一个表并为每个元素检查它是否在第二个表中。使用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 手动迭代,以避免一次复制所有数据。

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

【讨论】:

以上是关于Erlang - ETS 表之间的比较的主要内容,如果未能解决你的问题,请参考以下文章

从 ets:lookup() 中提取值 - Erlang

在不使用保护子句的情况下过滤 erlang ets 表

Erlang ETS 内存碎片

Erlang ets 移除/过滤元素

如何检查 ETS Erlang/Elixir 中是不是存在命名表

查询使用元组键的 erlang ETS 表