如何解决Levenshtein距离的模糊连接
我有一个表,其中包含名为“ potential_users”的用户名(约1000行)和另一个名为“ actual_users”的表(约1000万行)。所有记录仅由[a-z]字符组成,没有空格。另外,我知道Actual_users表中都没有电位用户。
我希望能够根据Levenshtein距离,为电位用户中的每一行计算出实际用户中最接近的记录。例如:
| potential_users|
|----------------|
| user1 |
| kajd |
| bbbbb |
和
| actual_users |
|--------------|
| kaj |
| bbbbbbb |
| user |
会返回:
| potential_users | actual_users | levenshtein_distance |
|-----------------|--------------|----------------------|
| user1 | user | 1 |
| kajd | kaj | 1 |
| bbbbb | bbbbbbb | 2 |
如果表很短,我可以做一个交叉连接,该交叉连接将为potential_users中的每条记录计算实际_users中的Levenshtein距离,然后返回最小值。但是,在我的情况下,这将创建一个包含1000 x 10000000行的中间表,这有点不切实际。
是否存在创建交叉连接的更清洁方法?
解决方法
不幸的是,没有交叉联接就无法做到这一点。最终,每个潜在用户都需要针对每个实际用户进行测试。
但是,Presto将在许多线程和机器上并行执行联接,因此只要有足够的硬件,它就可以非常快地执行。请注意,在Presto中,中间结果在运算符之间流传输,因此对于该查询,没有“中间表”具有10M x 1k行。
对于类似
的查询SELECT potential,min_by(actual,distance),min(distance)
FROM (
SELECT *,levenshtein_distance(potential,actual) distance
FROM actual_users,potential_users
)
GROUP BY potential
这是查询计划:
Query Plan
----------------------------------------------------------------------------------------------------------------
Fragment 0 [SINGLE]
Output layout: [potential,min_by,min]
Output partitioning: SINGLE []
Stage Execution Strategy: UNGROUPED_EXECUTION
Output[potential,_col1,_col2]
│ Layout: [potential:varchar(5),min_by:varchar(7),min:bigint]
│ Estimates: {rows: ? (?),cpu: ?,memory: ?,network: ?}
│ _col1 := min_by
│ _col2 := min
└─ RemoteSource[1]
Layout: [potential:varchar(5),min:bigint]
Fragment 1 [HASH]
Output layout: [potential,min]
Output partitioning: SINGLE []
Stage Execution Strategy: UNGROUPED_EXECUTION
Aggregate(FINAL)[potential]
│ Layout: [potential:varchar(5),min:bigint,min_by:varchar(7)]
│ Estimates: {rows: ? (?),network: ?}
│ min := min("min_1")
│ min_by := min_by("min_by_0")
└─ LocalExchange[HASH] ("potential")
│ Layout: [potential:varchar(5),min_1:bigint,min_by_0:row(boolean,boolean,bigint,varchar(7))]
│ Estimates: {rows: ? (?),network: ?}
└─ RemoteSource[2]
Layout: [potential:varchar(5),varchar(7))]
Fragment 2 [SOURCE]
Output layout: [potential,min_1,min_by_0]
Output partitioning: HASH [potential]
Stage Execution Strategy: UNGROUPED_EXECUTION
Aggregate(PARTIAL)[potential]
│ Layout: [potential:varchar(5),varchar(7))]
│ min_1 := min("levenshtein_distance")
│ min_by_0 := min_by("actual","levenshtein_distance")
└─ Project[]
│ Layout: [actual:varchar(7),potential:varchar(5),levenshtein_distance:bigint]
│ Estimates: {rows: ? (?),network: ?}
│ levenshtein_distance := levenshtein_distance("potential","actual")
└─ CrossJoin
│ Layout: [actual:varchar(7),potential:varchar(5)]
│ Estimates: {rows: ? (?),network: ?}
│ Distribution: REPLICATED
├─ TableScan[memory:9,grouped = false]
│ Layout: [actual:varchar(7)]
│ Estimates: {rows: ? (?),memory: 0B,network: 0B}
│ actual := 0
└─ LocalExchange[SINGLE] ()
│ Layout: [potential:varchar(5)]
│ Estimates: {rows: ? (?),network: ?}
└─ RemoteSource[3]
Layout: [potential:varchar(5)]
Fragment 3 [SOURCE]
Output layout: [potential]
Output partitioning: BROADCAST []
Stage Execution Strategy: UNGROUPED_EXECUTION
TableScan[memory:8,grouped = false]
Layout: [potential:varchar(5)]
Estimates: {rows: ? (?),network: 0B}
potential := 0
(1 row)
尤其是对于此部分,只要通过交叉连接生成一行,就会将其馈入到投影运算符中,该运算符将计算两个值之间的Levenshtein距离,然后馈入聚合中,每个聚合中仅存储一组“潜在”用户。因此,此查询所需的内存量应该少。
Aggregate(PARTIAL)[potential]
│ Layout: [potential:varchar(5),network: ?}
│ Distribution: REPLICATED
,
我认为您不能通过简单的join来做到这一点,有整个算法可以计算出来。看这篇文章显示了Levenshtein距离算法在sql中的实现:
https://www.sqlteam.com/forums/topic.asp?TOPIC_ID=51540&whichpage=1
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。