匹配MySQL中单词/后缀的类似/变体

时间:2012-08-23 14:46:55

标签: mysql sql match

如何匹配MySQL中单词的变体,例如搜索会计应该与会计,会计,会计等匹配。我在共享主机上,所以无法向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;

5 个答案:

答案 0 :(得分:3)

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

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

如果您不能使用Sphinx,请查看此php脚本http://tartarus.org/~martin/PorterStemmer/php.txt

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

我对MySql的全文搜索功能不够熟悉,但您可以尝试将词干算法应用于搜索词。对于你的“会计课程”的例子,Snowball词干表返回“account cours”。

答案 3 :(得分:0)

我对MATCH了解不多,当我想选择包含变体的列时,我会执行以下操作

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

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

答案 4 :(得分:0)

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

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