4

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

我想要类似于 Google在搜索“会计课程”时如何匹配“会计课程”和“会计课程”的内容。例子

我的服务器语言是 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;
4

5 回答 5

3

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

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

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

有了这个,您可以使用词干提取和词干搜索。

于 2012-09-11T07:44:30.613 回答
1

MySQL的SOUNDEX()功能非常接近。在此处阅读更多相关信息。

例子:

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*/
于 2012-09-07T15:41:05.047 回答
1

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

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

于 2012-09-07T16:03:42.600 回答
0

我不太了解MATCH,当我想选择具有变化的列时,我执行以下操作

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

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

于 2012-08-23T14:54:39.093 回答
0

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

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