Php 如何在匹配部分单词的情况下进行多列mysql全文搜索

Php 如何在匹配部分单词的情况下进行多列mysql全文搜索,php,mysql,sql,full-text-search,Php,Mysql,Sql,Full Text Search,我目前有一个搜索字段,使用以下代码对多个列进行搜索: $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 ('"

我目前有一个搜索字段,使用以下代码对多个列进行搜索:

$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       | john_smith@js.com
2  | Smith     | Bob        | bob_smith@js.com
如果我输入“johns”,只有第一个结果显示哪个是期望的行为

如果我输入“John Smith”,只有第一个结果显示了所需的行为

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

如果我输入“Smith John”,两个结果都会显示,即使Bob不是对手

最后,如果我键入“Jo S”,则不会返回结果,尽管“Jo”和“S”部分匹配

有人能帮我修复我的查询,以处理所需的功能性订单不重要和部分结果匹配吗?如果它可以被最佳匹配(即单词的最长部分,从第一个字母开始,而不是中间的一个部分,在最多的列中),这也将是一个巨大的帮助。

更新:

只是想发布基于解决方案的最终代码。我创建多个匹配语句的循环不正确,我的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)";

在布尔模式下
可以使用
+
-修饰符强制
-
-修饰符强制
。无操作员,您的案例,意味着可选

您需要检查mysql配置中的最小字长,以使全文索引字长小于某个长度

我必须把它放好

ft_min_word_len = 2
在my.cnf中,必须重建索引以使其有效。默认值为3


要在布尔模式下找到您的最小单词长度检查(和向上投票)

,需要字符串存在(而不是仅仅得分更高),请使用
+
完成。前缀匹配以结尾
*
完成。这似乎是您想要的,因此请搜索:

+John* +S*
+John* +Smith*
+Smith* +J*
+Jo* +S*
请注意,全文索引无法帮助您搜索“单词中的任何位置”。所以像
*mith*
这样的东西注定会失败:它们意味着从索引中的字符1开始匹配

如果您还想按匹配值对其排序,例如,在
约翰尼·史密斯
之前需要
约翰·史密斯
,您可以执行以下操作:

 SELECT * FROM user 
 WHERE MATCH(..fields..) AGAINST ('match' IN BOOLEAN MODE)
 ORDER BY MATCH(..fields..) AGAINST ('match' IN BOOLEAN MODE) DESC;
除非您再次单独添加所有单词>=
ft\u min\u word\u len
,否则您将无法看到这些单词:

+John* +S* John
+John* +Smith* John Smith
+Smith* +J* Smith
+Jo* +S*
对于最后一个,这两个字符都是<默认的4个字符,因此我们不能在默认的mysql中添加排序参数,但是您可以根据需要设置
ft\u min\u world\u len

请参见

您可以在单词前放置“+”、“-”或no运算符,使其搜索“并包含此单词”、“不包含此单词”,并且没有运算符是“或包含此单词”

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

只有一个John,所以这个有效,s小于最小字长,被丢弃

如果我输入“John Smith”,只有第一个结果显示了所需的行为

只有一个约翰,这样就行了

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

J小于最小字长,因此它唯一匹配的是两行

如果我输入“Smith John”,两个结果都会显示,即使Bob不是对手

由于您处于布尔模式,MySQL将其解释为Smith或John。。。史密斯两者都匹配

最后,如果我键入“Jo S”,则不会返回结果,尽管“Jo”和“S”部分匹配

Jo和S都低于最小字长-我相信MySQL会将其视为无搜索


您需要在搜索参数之前添加一个“+”,以将它们转换为AND搜索
+Smith+John

字段
ft\u min\u word\u len
不用于匹配查询,而是用于已创建的索引,查询现在正在与之匹配。因此,有人叫Jo Smith,他不会匹配
+Jo*
匹配项。已经删除了我的第一条评论(因为这是错误的,布尔模式使用最小字长,对此我深表歉意)。不过,术语顺序似乎仍然有问题。我将巴勃罗·毕加索添加到数据库中,以获得更长的名称进行测试。术语“Pablo Pica”返回一个结果。“Pica Pablo”没有。我应该将带有+和*的完整术语集传递到一个匹配语句中,还是像上面那样使用or执行多个匹配语句?@Max:我无法复制这一点,两个
Pica Pablo
都作为
Pablo Pica
(或
+Pica*+Pablo*
/
+Pablo*+Pica*
)为我返回相同的用户。是的,在一个
MATCH()对()
语句中。
MATCH()
中的每个术语都很可能需要
+术语*
格式。但一定要读@PatrickB的评论:名字<4个字符永远不会匹配。谢谢!将ft_min_word_len和将其更改为单个匹配语句的组合修复了它。我将用我的最终代码更新问题。因此,我有一个用户表,其中有一个
名称
列。我有一行名字是“James De
Quan”和。。。从
users`中选择*,其中MATCH(name)对('+james*+de*'在布尔模式下)不返回任何结果。适用于没有撇号的所有其他条目。有什么线索吗?条款的顺序似乎还有问题。我把巴勃罗·毕加索加入了DB。术语“Pablo Pica”返回一个结果。“Pica Pablo”没有。我应该将带有+和*的完整术语集传递到单个匹配语句中,还是像上面那样使用or执行多个匹配语句?