2011-03-16 113 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」,看看他們真的有多相似,儘管這對於英語以外的語言並不可靠。

相關問題