如何使多列MySQL的全文搜索,其中部分单词匹配

问题描述:

我现在有一个单一的搜索字段使用此代码对多列搜索:如何使多列MySQL的全文搜索,其中部分单词匹配

$searchArray = explode(" ", $searchVal); 
$query="SELECT * FROM users WHERE "; 
$i=0; 
foreach ($searchArray as $word) { 
    if ($i != 0) $query .= " OR "; 
    $query .= " MATCH (`first_name`, `last_name`, `email`) AGAINST ('".$word."*' IN BOOLEAN MODE)"; 
    $i++; 
} 

可以说我有表中的这两行:

id | last_name | first_name | email 
1 | Smith  | John  | [email protected] 
2 | Smith  | Bob  | [email protected] 

如果我输入“John S”,只有第一个结果显示哪个是需要的行为。

如果我输入“John Smith”,只有第一个结果显示哪一个是期望的行为。

如果我输入“Smith J”,即使Bob不匹配,两个结果都会显示。

如果我输入“Smith John”,即使Bob不匹配,两个结果都会显示。

最后,如果输入“Jo S”,尽管部分匹配“Jo”和“S”,但没有结果返回。

任何人都可以帮助我解决我的查询处理所需的功能不重要和部分结果匹配?如果可以按照最佳匹配(即单词的最长部分,从第一个字母开始而不是中间的部分,最高的列数)进行排序,那也是一个巨大的帮助。

UPDATE:

只是想后的起作用基于该解决方案的最终代码。我的循环创建多个匹配语句是不正确的,因为我的ft_min_word_len。

我的代码是现在:

$searchArray = explode(" ", $searchVal); 
$query="SELECT * FROM users WHERE MATCH (`first_name`, `last_name`, `email`) AGAINST ('"; 
$i=0; 
foreach ($searchArray as $word) { 
    $query .= "+".$word."* "; 
} 
$query .= "' IN BOOLEAN MODE)"; 

在布尔模式,要求字符串存在(而不仅仅是得分越高),与+完成。前缀匹配以结尾*完成。这似乎是你想要的,所以搜索:

+John* +S* 
+John* +Smith* 
+Smith* +J* 
+Jo* +S* 

注意,全文索引不能帮你搜索“一句话的任何地方”。所以像*mith*这样的东西肯定会失败:它们意味着在索引中匹配字符1。

如果你也想通过匹配值命令他们,例如,需要John SmithJohnny Smithson,你可以这样做:除非添加

SELECT * FROM user 
WHERE MATCH(..fields..) AGAINST ('match' IN BOOLEAN MODE) 
ORDER BY MATCH(..fields..) AGAINST ('match' IN BOOLEAN MODE) DESC; 

,你会看到你没好处所有单词> = ft_min_word_len再次分开:

+John* +S* John 
+John* +Smith* John Smith 
+Smith* +J* Smith 
+Jo* +S* 

在过去的一个,两者都是<默认4个字符,所以我们不能添加排序p在默认情况下为mysql的arams,但你可以设置不同的ft_min_world_len

+0

尽管这些术语的顺序似乎仍然存在问题。我将Pablo Picasso添加到数据库中以获得更长的测试名称。术语“Pablo Pica”返回结果。 “Pica Pablo”没有。我是否应该将具有+和*的全部术语传递给单个MATCH语句,或者像上面那样使用OR来执行多个MATCH语句? – Max 2013-03-12 21:38:49

+0

@Max:我不能重现这一点,'Pica Pablo'和'Pablo Pica'(或'+ Pica * + Pablo *'/'+ Pablo * + Pica *')都会为我返回同一个用户。是的,在一个'MATCH()AGAINST()'语句中。 'MATCH()'中的每个单词都很可能需要'+ term *'格式。尽管阅读@ PatrickB的评论:名字 Wrikken 2013-03-12 21:48:40

+0

谢谢!将ft_min_word_len与将其更改为单个MATCH语句的组合将其修复。我将用我的最终代码更新这个问题。 – Max 2013-03-13 16:12:02

IN BOOLEAN MODE可以使用+ -modifier强制AND- -modifier强制NOT。没有操作员,您的情况,意味着可选。

而且您需要检查mysql配置中的最小单词长度,以使FULLTEXT INDEX索引单词小于特定长度。

我必须设置

ft_min_word_len = 2 
在my.cnf

,不得不重建,使这个有效的指标。默认情况下,它是3

要找出您的min_word_len检查(并给予好评)this question

+1

字段'ft_min_word_len'不适用于MATCH查询,它用于已创建的索引和查询现在匹配的字段。所以,一个叫乔史密斯的人不会匹配'+ Jo *'匹配。 – 2013-03-12 21:11:49

+0

已经删除我的第一条评论(因为它是错误的,布尔模式_does_使用最小字长,我的道歉)。 – Wrikken 2013-03-12 21:19:57

http://dev.mysql.com/doc/refman/5.5/en//fulltext-boolean.html

您可以将一个“+”,“ - ”,或一个字之前,没有运营商,使其搜索“并包含这个词”,“不包含这个词”,也没有运营商是“OR包含此词”

如果我输入“John S”,只有第一个结果显示哪个是期望的行为。

这里只有一个约翰,所以此工程,S是最小字长的下方,并丢弃

如果我输入“约翰·史密斯”,只有第一个结果表明这是期望的行为。

这里只有一个约翰所以此工程

如果键入“史密斯J”,无论结果表明,即使鲍勃不匹配。

J是最小字长以下,所以其只匹配史密斯这是两行

如果我输入“约翰·史密斯”,无论结果表明,即使鲍勃不匹配。

由于您处于BOOLEAN模式,MySQL会将此解释为Smith或John ... Smith匹配两者。

最后,如果我键入“乔S”,没有结果,尽管在“乔”和“S”的部分匹配返回。

乔和S是最小字长如下 - 我相信MySQL的会将其视为寻找什么

你要添加一个“+”之前,你的搜索参数,以使他们成为一个与搜索... +Smith +John

+0

这些条款的顺序似乎仍然存在问题。我把巴勃罗·毕加索加入了数据库。术语“Pablo Pica”返回结果。 “Pica Pablo”没有。我是否应该将具有+和*的全部术语传递给单个MATCH语句,或者像上面那样使用OR来执行多个MATCH语句? – Max 2013-03-12 21:46:02