在mysql中搜索名称的最佳方法

时间:2016-04-30 23:21:58

标签: php mysql lucene full-text-search

我想搜索名为“Martins Silva”的用户。我在BOOLEAN MODE中使用全文。

id     results_numbers  new_id name              creation_time
9680    2               9394   lesbyfaye         11/10/14 0:23
9680    3                999   Kayts & Koilsby   11/10/14 0:23
9690    3               5968   Jacobsonl         12/10/14 0:10
9690    3                 47   SarHix            12/10/14 0:10
9690    3               8825   joy               12/10/14 0:10

“Martins Silva”的搜索结果返回

 MATCH(name,lastname) AGAINST('+martins +silva' IN BOOLEAN MODE)

问题是数据库上有一个名为“Martins Silva”的用户,但它只出现在540位的结果集上。

这是我期望阅读文档并了解排名的计算结果。但是,它无助于我解决这个问题。我也尝试用LIKE搜索,但我也一样。

鉴于结果集,对我来说最好的是:

Orleans Silva De Martins (1)
Armistrong Oliveira Martins Da Silva (2)
Douglas Martins Vieira Da Silva (3)
Glauciene Silva Martins (4)
Jose Martins Silva (5)
...

所以,我认为我可以通过一种算法来解决这个问题,该算法考虑了单词在查询中的顺序或位置。

我尝试计算levenshtein距离,但对于大型数据库来说它确实很慢。

MySQL有办法解决这个问题吗?或者我必须使用Apache Lucene?或者我做错了什么?这个搜索是我网站上的主要内容,它必须工作得非常好。

非常感谢,伙计们!

2 个答案:

答案 0 :(得分:1)

在您的特定情况下,您需要实现levenshtein函数才能实现此目的。匹配将无法以正确的方式完成。 通过对levenshtein相关性ASC进行排序,您将从最相关到​​最不相关。

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$$
DELIMITER ;

此模态查询将按最相关的姓氏排序,名称排名第二,并显示最相关的第一行,添加LIMIT 1只能得到最相关的结果:

Select lastname, levenshtein(lastname,$var1) as relevance1,
name, levenshtein(name,$var2) as relevance2
FROM database
ORDER BY relevance 1 ASC, relevance 2 ASC

答案 1 :(得分:0)

如果您想要精确搜索,则可以合并列并使用它们进行搜索。 使用类似这样的东西

从tableName中选择CONCAT(firstname,“”,lastname),其中CONCAT(firstname,“”,lastname)=“Martins Silva”;

文本搜索的最佳解决方案是Lucene。

如果您使用任何其他文本搜索算法将会很慢,并且lucene已经测试了性能和编码的简便性。 http://lucene.apache.org/

相关问题