Mysql全文搜索,自然语言模式 : order by "closeness"

标签 mysql pattern-matching full-text-search levenshtein-distance

我正在使用 MYSQL 的全文搜索功能(在 Mysql 5.6.33 中)。

如果我在 NATURAL LANGUAGE 模式下进行匹配,对于邮政编码,有一个字符的拼写错误,我会得到一些不错的结果,包括带有“正确”邮政编码的结果,但它们并不接近顶部。

例如,有 10 所学校的邮政编码为 “BN2 1TL”。我故意将其拼错为 "BN2 1TM" 并按如下方式进行搜索:

SELECT record_id, address_string, 
  MATCH (address_string) AGAINST ("BN2 1TM" IN NATURAL LANGUAGE MODE) AS score 
  FROM schools 
  WHERE MATCH (address_string) AGAINST ("BN2 1TM" IN NATURAL LANGUAGE MODE) > 0 
  ORDER BY score DESC;

仔细检查,这是因为搜索已经 repo 了所有在其 address_string 中包含 "BN2""1TM" 的结果列,它们都具有完全相同的分数,因此实际上是随机排列的。 .

这是完全合理的行为,但如果我能得到将“接近度”考虑在内的分数,那就太好了,这意味着,对于 “BN2 1TM” 的搜索, “BN2 1TL”“BN2 3PQ” 得分更高。有没有办法做到这一点?

编辑:我记得这种类型的接近度在技术上称为“Levenshtein 距离”,这是对 Levenshtein algorithm 的引用。用于确定将一个字符串变成另一个字符串需要多少次替换。所以我想我的问题可能是“我能否获得 MYSQL 全文自然语言模式评分以考虑 Levenshtein 距离”

最佳答案

首先,MySQL 全文在开放式搜索方面不如像 Lucene 这样的专用系统那么好。

有一种称为Levenshtein 距离 的算法,它计算将一个字符串更改为另一个字符串的字符转换次数(距离)。

因此,将“BN2 1TM”更改为“BN2 1MT”(换位)的距离为 2。将其更改为“BN2 1TX”的距离为 1。

编辑距离对短语不是很有用,除非它们几乎完全相同。将“Apache Sphinx”更改为“MySQL FULLTEXT”,距离为 14,即较长字符串的长度。但它对于邮政编码、部件号和其他短结构词很有用。

你可以尝试这样的事情来首先获得最接近的值。

  SELECT city, county, postcode
    FROM table
   ORDER BY levenshtein(postcode, 'BN2 1MT') ASC

然后,您只需要一个存储函数来计算 Levenshtein 距离。 (这不是内置于 FULLTEXT 中。)

来自 this source ,这里就是这样一个存储函数。但要注意,它速度不快,而且不能使用索引。因此,如果您可以在执行此操作之前缩小搜索范围,您将获得更好的性能。

DELIMITER $$
CREATE FUNCTION levenshtein( s1 VARCHAR(255), s2 VARCHAR(255) )
    RETURNS INT
    DETERMINISTIC
    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$$
DELIMITER ;

关于Mysql全文搜索,自然语言模式 : order by "closeness",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55100524/

相关文章:

PostgreSQL 串行模式

python - 纠正文本中错别字的最佳算法

java - MySQL LIKE 与 BOOLEAN MODE (FULLTEXT) 何时何地使用?

php - 将 Rails 模型连接到非 Rails 数据库

Mysql,每N行删除几行

Mysql每行求和

regex - 在Visual Studio中替换正则表达式

database - 比较 : DB Full Text search to Search engine (Lucene)

postgresql - 了解全文搜索查询中子句顺序的影响

mysql - ActiveRecord 连接和位置