web-dev-qa-db-fra.com

comment calculer la similitude entre deux chaînes dans MYSQL

si j'ai deux chaînes dans mysql:

 @ a = "Bienvenue dans Stack Overflow" 
 @ b = "Bonjour pour déborder la pile"; 

existe-t-il un moyen d'obtenir le pourcentage de similitude entre ces deux chaînes en utilisant MYSQL? ici par exemple 3 mots sont similaires et donc la similitude devrait être quelque chose comme:
count (mots similaires entre @a et @b)/(count (@a) + count (@b) - count (intersection))
et donc le résultat est 3/(4 + 4 - 3) = 0,6
toute idée est très appréciée!

34
Lina

vous pouvez utiliser cette fonction (cop ^ H ^ H ^ Hadapted from 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

et pour l'obtenir comme XX% utilisez cette fonction

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
38
Alaa

Je ne pense pas qu'il existe une méthode de requête agréable en une seule étape pour le faire - le langage naturel est principalement conçu pour la recherche "de type Google", ce qui semble différent de ce que vous essayez de faire.

Selon ce que vous essayez réellement de faire - je suppose que vous avez omis beaucoup de détails - je voudrais:

  • créez un tableau dans lequel vous divisez chaque chaîne en mots, tout en minuscules, en supprimant les espaces et la ponctuation - dans votre exemple, vous vous retrouvez avec:

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

Vous pouvez ensuite exécuter des requêtes sur cette table - par exemple.

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

vous donne l'intersection.

Vous pouvez ensuite créer une fonction ou similaire pour calculer la similitude selon votre formule.

Pas très propre, mais il devrait fonctionner assez rapidement, il est principalement relationnel et devrait être largement indépendant de la langue. Pour faire face à d'éventuelles fautes de frappe, vous pouvez calculer le soundex - cela vous permettrait de comparer "stack" avec "stak" et de voir à quel point ils sont similaires, bien que cela ne fonctionne pas de manière fiable pour des langues autres que l'anglais.

7
Neville Kuyt

Vous pouvez essayer l'algorithme SOUNDEX, jetez un œil ici :)

SOUNDEX MySQL

EDIT 1:

Peut-être que ce lien sur le traitement du langage naturel avec MySQL pourrait être utile

Recherches en texte intégral en langage naturel

Comment trouver des résultats similaires et trier par similitude?

HTH!

5
SubniC

Cela pourrait vous être utile si vous ne souhaitez pas écrire vos propres algorithmes:

http://dev.mysql.com/doc/refman/5.0/en/fulltext-natural-language.html

1
DhruvPathak