2011-03-16 82 views
30

如果我有mysql中两个字符串:如何计算两个字符串之间的相似性MYSQL

 
@a="Welcome to Stack Overflow" 
@b=" Hello to stack overflow"; 

有没有办法让使用MYSQL这两个字符串之间的相似性百分比是多少? 这里例如3个单词是相似的,因此相似性应该类似于:
count(@a和@b之间的相似词)/(count(@a)+ count(@b) - count(intersection))
因此结果是3 /(4 + 4 - 3)= 0.6
任何想法高度赞赏!

+2

A [的Levenshtein](HTTP ://en.wikipedia.org/wiki/Levenshtein_distance)基于(在字级)距离似乎是一个很好的算法 – RichardTheKiwi 2011-03-16 09:45:33

回答

31

可以使用此函数(COP^H^H^Hadapted从http://www.artfulsoftware.com/infotree/queries.php#552):

CREATE FUNCTION `levenshtein`(s1 text, s2 text) RETURNS int(11) 
    DETERMINISTIC 
BEGIN 
    DECLARE s1_len, s2_len, i, j, c, c_temp, cost INT; 
    DECLARE s1_char CHAR; 
    DECLARE cv0, cv1 text; 
    SET s1_len = CHAR_LENGTH(s1), s2_len = CHAR_LENGTH(s2), cv1 = 0x00, j = 1, i = 1, c = 0; 
    IF s1 = s2 THEN 
     RETURN 0; 
    ELSEIF s1_len = 0 THEN 
     RETURN s2_len; 
    ELSEIF s2_len = 0 THEN 
     RETURN s1_len; 
    ELSE 
     WHILE j <= s2_len DO 
     SET cv1 = CONCAT(cv1, UNHEX(HEX(j))), j = j + 1; 
     END WHILE; 
     WHILE i <= s1_len DO 
     SET s1_char = SUBSTRING(s1, i, 1), c = i, cv0 = UNHEX(HEX(i)), j = 1; 
     WHILE j <= s2_len DO 
      SET c = c + 1; 
      IF s1_char = SUBSTRING(s2, j, 1) THEN 
      SET cost = 0; ELSE SET cost = 1; 
      END IF; 
      SET c_temp = CONV(HEX(SUBSTRING(cv1, j, 1)), 16, 10) + cost; 
      IF c > c_temp THEN SET c = c_temp; END IF; 
      SET c_temp = CONV(HEX(SUBSTRING(cv1, j+1, 1)), 16, 10) + 1; 
      IF c > c_temp THEN 
       SET c = c_temp; 
      END IF; 
      SET cv0 = CONCAT(cv0, UNHEX(HEX(c))), j = j + 1; 
     END WHILE; 
     SET cv1 = cv0, i = i + 1; 
     END WHILE; 
    END IF; 
    RETURN c; 
    END 

和用于得到它作为XX%使用此功能

CREATE FUNCTION `levenshtein_ratio`(s1 text, s2 text) RETURNS int(11) 
    DETERMINISTIC 
BEGIN 
    DECLARE s1_len, s2_len, max_len INT; 
    SET s1_len = LENGTH(s1), s2_len = LENGTH(s2); 
    IF s1_len > s2_len THEN 
     SET max_len = s1_len; 
    ELSE 
     SET max_len = s2_len; 
    END IF; 
    RETURN ROUND((1 - LEVENSHTEIN(s1, s2)/max_len) * 100); 
    END 
+2

对于初学者:如果您想正确运行CREATE FUNCTION语句,则必须提前设置DELIMITER。请参阅http://stackoverflow.com/a/6740975/2293304 – Rockallite 2015-06-10 09:10:33

+1

更新后的版本位于此处:http://www.artfulsoftware.com/infotree/qrytip.php?id=552 – Rockallite 2015-06-11 03:53:18

+0

@Rockallite请注意,更新后的版本仅使用VARCHAR(255),因此只比较前255个字符 – 2017-07-28 10:21:54

4

你可以尝试SOUNDEX算法,采取这里看看:)

SOUNDEX MySQL

编辑1:

也许关于MySQL的自然语言处理这个环节可能是有用的

Natural Language Full-Text Searches

How to find similar results and sort by similarity?

HTH!

+0

SELECT SOUNDEX('Welcome to Stack Overflow');是W42532321614 \ n SELECT SOUNDEX('Hello to Stack Overflow');是H432321614 \ n 所以什么!!这是什么意思:( – Lina 2011-03-16 09:10:37

+0

具有相同的价值发音的单词是相同的,你可以看看这里的更多细节https://secure.wikimedia.org/wikipedia/ en/wiki/Soundex,你可以尝试Levenshtein距离aswel来获得一个数字值,代表你在句子中必须做出的变化数量(插入,删除和修改),看起来像其他。https://secure.wikimedia。 org/wikipedia/en/wiki/Levenshtein_distance – SubniC 2011-03-16 09:14:43

+2

考虑到SOUNDEX只适用于英文。 – SubniC 2011-03-16 09:16:13

5

我不认为有一个不错的,单步查询的方式来做到这一点 - 自然语言的东西主要是为了“谷歌般”搜索而设计的,这听起来与你正在尝试做的不同。

取决于你实际上要做的 - 我想你忽略了很多细节 - 我:

  • 创建成拆分每个串入字表中,所有在较低的情况下,剥离出空格和标点 - 在你的榜样,你会结束:

    string_id    word 
    
    1      hello 
    1      from 
    1      stack 
    1      overflow 
    2      welcome 
    2      from 
    2      stack 
    2      overflow 
    

然后,您可以运行查询对这个表 - 例如,

select count(*) 
from stringWords 
where string_id = 2 
and word in 
    (select word 
    from stringWords 
    where string_id = 1); 

给你的交集。

然后,您可以创建一个函数或类似的按照您的公式计算相似度。

不是很干净,但它应该表现得相当快,它主要是关系型的,它应该基本上与语言无关。 为了处理可能的拼写错误,你可以计算soundex--这将允许你比较“stack”和“stak”,看看他们真的有多相似,尽管这对于英语以外的语言并不可靠。

相关问题