首页 > 解决方案 > 在 SQL 中的部分字符串上使用 levenshtein

问题描述

我试图找出一种使用 Levenshtein 方法将一些模糊搜索方法用于我们的店面搜索字段的方法,但我遇到了如何仅搜索部分产品名称的问题。

例如,客户搜索scisors,但我们有一个名为 的产品electric scissor。使用 Levenshtein 方法levenshtein("scisors","electric scissor"),我们将得到 11 的结果,因为电气部分将被计为差异。

我正在寻找的是一种查看产品名称子字符串的方法,因此它将与它进行比较levenshtein("scisors","electric"),然后还levenshtein("scisors","scissor")可以看到我们在第二个子字符串中只能得到 2 的结果,从而将该产品显示为他们的搜索结果的一部分。

非工作示例让您了解我所追求的:

SELECT * FROM products p WHERE levenshtein("scisors", p.name) < 5

问题:有没有办法编写一个处理检查字符串部分的 SQL 语句?我是否需要在我的数据库中创建更多函数才能处理它或修改我现有的函数,如果是这样,它会是什么样子?

我目前正在使用 levenshtein 方法的这个实现:

//levenshtein(s1 as VARCHAR(255), s2 as VARCHAR(255))
//returns int


  BEGIN
    DECLARE s1_len, s2_len, i, j, c, c_temp, cost INT;
    DECLARE s1_char CHAR;
    -- max strlen=255
    DECLARE cv0, cv1 VARBINARY(256);
    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

标签: sqllevenshtein-distance

解决方案


这是一个有点长的评论。

首先,我建议使用带有同义词列表的全文搜索。也就是说,您的用户可能拼写能力很差,因此同义词列表可能难以维护。

如果您使用 Levenshtein 距离,那么我建议您按单词进行。对于用户输入中的每个单词,计算字段中最接近的单词name。然后将它们加在一起以获得最佳匹配。

在您的示例中,您将进行以下比较:

  • levenshtein('剪刀','电动')
  • levenshtein('剪刀', '剪刀')

最小值将是第二个。如果用户键入多个单词,例如'electrk scisors',那么你会做

  • levenshtein('electrk', 'electric') <-- 最小值
  • levenshtein('electrk', '剪刀')
  • levenshtein('剪刀','电动')
  • levenshtein('scisors', 'scissor') <-- 最小值

这可能是一种接近搜索的直观方式。


推荐阅读