猿问

为mysql /模糊搜索实现Levenshtein距离?

为mysql /模糊搜索实现Levenshtein距离?

我希望能够按照以下方式搜索一个表格,因为它可以获得1个方差范围内的所有内容。


数据:


奥布莱恩

Smithe

杜兰

Smuth

Smoth

冈瑟

Smiht

我已经研究过使用Levenshtein距离有没有人知道如何实现它?


繁星点点滴滴
浏览 607回答 3
3回答

慕姐8265434

上面给出的levenshtein <= 1的函数不正确 - 它给出了不正确的结果,例如“床”和“出价”。我在第一个答案中修改了上面给出的“MySQL Levenshtein距离查询”,以接受一个“限制”,这将加快它的速度。基本上,如果你只关心Levenshtein <= 1,将极限设置为“2”,如果它是0或1,函数将返回精确的levenshtein距离;&nbsp;如果精确的levenshtein距离为2或更大,则为2。这个mod使它快15%到50% - 搜索词越长,优势越大(因为算法可以提前保释。)例如,搜索200,000个单词以查找距离1的所有匹配项“傻笑”,原版在我的笔记本电脑上花了3分47秒,而“极限”版本需要1:39。当然,这些对于任何实时使用来说都太慢了。码:DELIMITER&nbsp;$$CREATE&nbsp;FUNCTION&nbsp;levenshtein_limit_n(&nbsp;s1&nbsp;VARCHAR(255),&nbsp;s2&nbsp;VARCHAR(255),&nbsp;n&nbsp;INT)&nbsp; &nbsp;&nbsp;RETURNS&nbsp;INT&nbsp; &nbsp;&nbsp;DETERMINISTIC&nbsp; &nbsp;&nbsp;BEGIN&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;DECLARE&nbsp;s1_len,&nbsp;s2_len,&nbsp;i,&nbsp;j,&nbsp;c,&nbsp;c_temp,&nbsp;cost,&nbsp;c_min&nbsp;INT;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;DECLARE&nbsp;s1_char&nbsp;CHAR;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;max&nbsp;strlen=255&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;DECLARE&nbsp;cv0,&nbsp;cv1&nbsp;VARBINARY(256);&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;s1_len&nbsp;=&nbsp;CHAR_LENGTH(s1),&nbsp;s2_len&nbsp;=&nbsp;CHAR_LENGTH(s2),&nbsp;cv1&nbsp;=&nbsp;0x00,&nbsp;j&nbsp;=&nbsp;1,&nbsp;i&nbsp;=&nbsp;1,&nbsp;c&nbsp;=&nbsp;0,&nbsp;c_min&nbsp;=&nbsp;0;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;s1&nbsp;=&nbsp;s2&nbsp;THEN&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN&nbsp;0;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;ELSEIF&nbsp;s1_len&nbsp;=&nbsp;0&nbsp;THEN&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN&nbsp;s2_len;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;ELSEIF&nbsp;s2_len&nbsp;=&nbsp;0&nbsp;THEN&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN&nbsp;s1_len;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;ELSE&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHILE&nbsp;j&nbsp;<=&nbsp;s2_len&nbsp;DO&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;cv1&nbsp;=&nbsp;CONCAT(cv1,&nbsp;UNHEX(HEX(j))),&nbsp;j&nbsp;=&nbsp;j&nbsp;+&nbsp;1;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END&nbsp;WHILE;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHILE&nbsp;i&nbsp;<=&nbsp;s1_len&nbsp;and&nbsp;c_min&nbsp;<&nbsp;n&nbsp;DO&nbsp;--&nbsp;if&nbsp;actual&nbsp;levenshtein&nbsp;dist&nbsp;>=&nbsp;limit,&nbsp;don't&nbsp;bother&nbsp;computing&nbsp;it &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;s1_char&nbsp;=&nbsp;SUBSTRING(s1,&nbsp;i,&nbsp;1),&nbsp;c&nbsp;=&nbsp;i,&nbsp;c_min&nbsp;=&nbsp;i,&nbsp;cv0&nbsp;=&nbsp;UNHEX(HEX(i)),&nbsp;j&nbsp;=&nbsp;1;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHILE&nbsp;j&nbsp;<=&nbsp;s2_len&nbsp;DO&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;c&nbsp;=&nbsp;c&nbsp;+&nbsp;1;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;s1_char&nbsp;=&nbsp;SUBSTRING(s2,&nbsp;j,&nbsp;1)&nbsp;THEN&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;cost&nbsp;=&nbsp;0;&nbsp;ELSE&nbsp;SET&nbsp;cost&nbsp;=&nbsp;1;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END&nbsp;IF;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;c_temp&nbsp;=&nbsp;CONV(HEX(SUBSTRING(cv1,&nbsp;j,&nbsp;1)),&nbsp;16,&nbsp;10)&nbsp;+&nbsp;cost;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;c&nbsp;>&nbsp;c_temp&nbsp;THEN&nbsp;SET&nbsp;c&nbsp;=&nbsp;c_temp;&nbsp;END&nbsp;IF;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;c_temp&nbsp;=&nbsp;CONV(HEX(SUBSTRING(cv1,&nbsp;j+1,&nbsp;1)),&nbsp;16,&nbsp;10)&nbsp;+&nbsp;1;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;c&nbsp;>&nbsp;c_temp&nbsp;THEN&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;c&nbsp;=&nbsp;c_temp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END&nbsp;IF;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;cv0&nbsp;=&nbsp;CONCAT(cv0,&nbsp;UNHEX(HEX(c))),&nbsp;j&nbsp;=&nbsp;j&nbsp;+&nbsp;1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;c&nbsp;<&nbsp;c_min&nbsp;THEN &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;c_min&nbsp;=&nbsp;c; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END&nbsp;IF;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END&nbsp;WHILE;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;cv1&nbsp;=&nbsp;cv0,&nbsp;i&nbsp;=&nbsp;i&nbsp;+&nbsp;1;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END&nbsp;WHILE;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;END&nbsp;IF; &nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;i&nbsp;<=&nbsp;s1_len&nbsp;THEN&nbsp;--&nbsp;we&nbsp;didn't&nbsp;finish,&nbsp;limit&nbsp;exceeded&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;c&nbsp;=&nbsp;c_min;&nbsp;--&nbsp;actual&nbsp;distance&nbsp;is&nbsp;>=&nbsp;c_min&nbsp;(i.e.,&nbsp;the&nbsp;smallest&nbsp;value&nbsp;in&nbsp;the&nbsp;last&nbsp;computed&nbsp;row&nbsp;of&nbsp;the&nbsp;matrix)&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;END&nbsp;IF; &nbsp;&nbsp;&nbsp;&nbsp;RETURN&nbsp;c; &nbsp;&nbsp;END$$

绝地无双

为了使用levenshtein距离进行有效搜索,您需要一个有效的专用索引,例如bk-tree。不幸的是,我所知道的数据库系统,包括MySQL,都没有实现bk-tree索引。如果您正在寻找全文搜索,而不是每行只有一个术语,这将更加复杂。另一方面,我想不出任何可以以允许基于levenshtein距离进行搜索的方式进行全文索引的方式。

侃侃尔雅

damerau-levenshtein距离的实现可以在这里找到:&nbsp;Damerau-Levenshtein算法:具有转置&nbsp;的Levenshtein对纯Levenshtein距离的改进是考虑字符的交换。我在schnaader链接的评论中找到了它,谢谢!
随时随地看视频慕课网APP
我要回答