You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

MySQL SELECT查询:如何获取与搜索文本最相似的行

在MySQL中查询与搜索文本最相似的行

刚好碰到过类似的需求,给你整理几个实用方法,完美解决你说的搜'rakul'匹配'rahul'这类场景:

方法1:用Levenshtein距离(精准字符相似度匹配首选)

Levenshtein距离能算出两个字符串之间的编辑次数(插入、删除、替换字符),次数越少,字符串越相似。不过MySQL默认没内置这个函数,得先自定义一个:

DELIMITER //
CREATE FUNCTION LEVENSHTEIN(str1 VARCHAR(255), str2 VARCHAR(255)) 
RETURNS INT
DETERMINISTIC
BEGIN
    DECLARE len1, len2, i, j, cost INT;
    DECLARE str1_char CHAR;
    DECLARE cv0, cv1 VARBINARY(256);
    
    SET len1 = CHAR_LENGTH(str1);
    SET len2 = CHAR_LENGTH(str2);
    SET cv0 = 0x00;
    SET i = 0;
    
    WHILE i <= len2 DO
        SET cv0 = CONCAT(cv0, UNHEX(HEX(i)));
        SET i = i + 1;
    END WHILE;
    
    SET i = 0;
    WHILE i < len1 DO
        SET str1_char = SUBSTRING(str1, i + 1, 1);
        SET cv1 = UNHEX(HEX(i + 1));
        SET j = 0;
        
        WHILE j < len2 DO
            SET cost = IF(str1_char = SUBSTRING(str2, j + 1, 1), 0, 1);
            SET cv1 = CONCAT(cv1, UNHEX(HEX(LEAST(
                ORD(SUBSTRING(cv0, j + 2, 1)) + 1,
                ORD(SUBSTRING(cv1, j + 1, 1)) + 1,
                ORD(SUBSTRING(cv0, j + 1, 1)) + cost
            ))));
            SET j = j + 1;
        END WHILE;
        
        SET cv0 = cv1;
        SET i = i + 1;
    END WHILE;
    
    RETURN ORD(SUBSTRING(cv0, len2 + 1, 1));
END //
DELIMITER ;

函数定义好后,就可以用它来查询了。假设你的表是users,要匹配的字段是name,搜索文本是'rakul',想取最相似的前10条:

SELECT name, LEVENSHTEIN(name, 'rakul') AS distance
FROM users
ORDER BY distance ASC
LIMIT 10;

这里的distance就是编辑次数,像'rahul'和'rakul'的距离是1,会排在最前面,完全符合你的需求。

方法2:用SOUNDEX/SOUNDS LIKE(适合发音相似的场景)

如果你的需求是找发音相近的字符串,MySQL自带的工具就够用了。SOUNDEX会把字符串转换成发音编码,发音相似的字符串编码一致:

SELECT name
FROM users
WHERE SOUNDEX(name) = SOUNDEX('rakul');

或者用更简洁的SOUNDS LIKE语法:

SELECT name
FROM users
WHERE name SOUNDS LIKE 'rakul';

这个方法对发音接近的词效果很好,'rakul'和'rahul'发音差不多,肯定能匹配到。

方法3:全文搜索(适合长文本字段)

如果你的字段是较长的文本内容,还可以用MySQL的全文索引来做匹配。首先得给字段加个全文索引:

ALTER TABLE users ADD FULLTEXT INDEX ft_name (name);

然后用MATCH AGAINST查询匹配度:

SELECT name, MATCH(name) AGAINST('rakul' IN NATURAL LANGUAGE MODE) AS relevance
FROM users
ORDER BY relevance DESC;

这里的relevance是匹配得分,得分越高越相似。不过这个方法对短字符串的匹配效果不如前两种,更适合大段文本的场景。


内容的提问来源于stack exchange,提问作者sahil sanwal

火山引擎 最新活动