【问题标题】:Match similar/variations of words / suffixes in MySQL匹配 MySQL 中单词/后缀的相似/变体
【发布时间】:2012-09-11 20:03:27
【问题描述】:

如何匹配 MySQL 中单词的变体,例如,搜索 accountancy 应该匹配 accountant、accountants、accounting 等。我在共享主机上,因此无法向 MySQL 添加任何功能,例如 levenshtein。

我想要类似于 Google 在搜索“会计课程”时匹配“会计课程”和“会计课程”的方式。 Example.

我的服务器语言是 php,如果它只能在那里实现而不是在 SQL 中实现的话。

目前的说法如下。

SELECT 
  pjs.title,
  MATCH (pjs.title) AGAINST ('accountancy' IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION) AS rel1,
  MATCH (pjs.description) AGAINST ('accountancy' IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION) AS rel2,
  MATCH (
    pjs.benefits,
    pjs.experienceRequirements,
    pjs.incentives,
    pjs.qualifications,
    pjs.responsibilities,
    pjs.skills
  ) AGAINST ('accountancy' IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION) AS rel3
FROM
  pxl_jobsearch AS pjs 
ORDER BY (rel1 * 5) + (rel2 * 1.5) + (rel3) DESC;

【问题讨论】:

    标签: mysql sql match


    【解决方案1】:

    MySQL 不擅长全文搜索,您可能希望使用其他引擎。我最喜欢的是 Sphinx (http://sphinxsearch.com/),但也有其他的。大多数这些支持都是开箱即用的。

    如果您有大型表并打算使用词干提取,那么 MySQL 的性能可能会非常糟糕。

    如果你不能使用Sphinx,看看这个php脚本http://tartarus.org/~martin/PorterStemmer/php.txt

    有了这个,你可以使用词干,并搜索词干。

    【讨论】:

    • 谢谢。我很想使用 Sphinx,之前曾简要研究过,但坚持使用共享主机,所以这次没有办法。我不认为数据大小是这个网站的问题。希望如果它起飞,我将能够在未来改进托管。
    • 能否安装PECL包:pecl.php.net/package/stem 或者可以检查一下是否安装了?没关系,你也需要滚雪球。
    • 添加了一个 php 词干脚本,您应该可以在共享环境中使用它。请注意,它可能并不完美。
    • 谢谢@Nin 我授予你赏金,因为 Sphinx(或类似的)在理想情况下是最好的答案,但是到词干分析器的链接是一个很好的后备。
    • +1 链接到 PHP 词干分析器 - 让我的生活变得更轻松
    【解决方案2】:

    MySQL 的SOUNDEX() 功能非常接近。阅读更多关于它的信息here

    示例:

    create table test(id int auto_increment, a varchar(255), primary key(id));
    insert into test(a) values
    ('accountancy'),
    ('accountant'),
    ('accountants'),
    ('accounting'),
    ('accountingc'),
    ('becounting'),
    ('asdf'),
    ('this is a test');
    
    select 
    test.*,
    SOUNDEX(a),
    SOUNDEX('accountancy')
    FROM
    test 
    WHERE a SOUNDS LIKE 'accountancy';
    

    如果这不能解决问题,levenshtein 算法就是要走的路。与您的数据库管理员交谈,他允许您创建函数。如果他这样做了,这就是解决方案(我没有编写函数,归功于匿名):

    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//
    

    再次测试数据:

    create table leven(id int auto_increment, a varchar(255), primary key(id));
    insert into leven(a) values
    ('accountancy'),
    ('accountant'),
    ('accountants'),
    ('accounting'),
    ('accountingc'),
    ('becounting'),
    ('asdf'),
    ('this is a test')
    ;
    
    
    select
    leven.*,
    levenshtein(leven.a, 'accountancy')
    from
    leven
    where levenshtein(leven.a, 'accountancy') <= 3 /*or any value you like*/
    

    【讨论】:

    • @tomdom 我尝试了 SOUNDEX,但不幸的是它在这种情况下对我没有多大帮助,但我确实喜欢它来搜索人们的名字。 levenshtein 函数听起来很有趣,但我不能在共享主机上使用它。我想我还需要更多规则,也许只是改变单词的结尾 - 后缀。
    【解决方案3】:

    搜索引擎通过实施称为stemming 的文本处理技术来实现这一点。有很多库可以为您实现这一点,我个人有用户 Snowball stemmer,它做得很好。

    我对 MySql 的全文搜索功能不够熟悉,但您可以尝试将词干算法应用于搜索词。对于您的“会计课程”示例,Snowball 词干分析器返回“帐户课程”。

    【讨论】:

    【解决方案4】:

    我对@9​​87654321@ 了解不多,当我想选择具有变体的列时,我会执行以下操作

    SELECT pjs.title
    FROM pxl_jobsearch AS pjs
    WHERE pjs.title LIKE 'account%'
    

    我主要在 SQL Server 中工作,但也做一些 MySQL。我想这也适用于 MySQL。

    【讨论】:

    • 我考虑过使用like,但我的问题是如果有人在搜索中输入“accountancy”,我不能使用通配符来匹配“accountant”(accountancy%)。也许我可以做一些假设,总是删除最后 4 个字符,这样它就变成了 'account%',但是像 'trust' 这样的更短的词是行不通的。我想要类似于 Google 在搜索“会计课程”时匹配“会计课程”和“会计课程”的方式。
    • 我明白你在说什么。这是个好问题。请编辑您的问题以指定这一点。
    【解决方案5】:

    您可以使用 SQL SOUNDEX(),它对您的需求非常有用:它搜索听起来相同的词,而不是语法上接近的词。 您可以使用两种方法,它们非常相似。

    • 识别常见的后缀并将它们替换为LIKE 子句中的%:使用您的示例,accountancy 将变为account%
    • 编写一个包含您需要的所有变体的“字典”,并将其用于 PHP(stristr() 函数):因此,accountancy 将生成类似于 WHERE value='accountancy' or value='accountant' or value='accountancies' 的子句。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-28
      • 1970-01-01
      • 1970-01-01
      • 2013-04-17
      • 1970-01-01
      • 2012-12-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多