Как сделать полнотекстовый поиск с несколькими столбцами 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", будет показан только первый результат, который является желаемым.
Если я наберу "Джон Смит", будет показан только первый результат, который является желаемым.
Если я нахожу "Smith J", оба результата показывают, что 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)";
Ответы
Ответ 1
В логическом режиме, требуя присутствия строк (вместо того, чтобы просто подсчитывать больше), выполняется с помощью +
. сопоставление префикса выполняется с завершением *
. Это похоже на то, что вы хотите, поэтому выполните поиск:
+John* +S*
+John* +Smith*
+Smith* +J*
+Jo* +S*
Обратите внимание, что индексы Full Text не могут помочь вам найти слово "где угодно". поэтому что-то вроде *mith*
связано с ошибкой: они должны совпадать с символом 1 в индексе.
Если вы также хотите заказать их по значениям соответствия и, например, нужно John Smith
до Johnny Smithson
, вы бы сделали это:
SELECT * FROM user
WHERE MATCH(..fields..) AGAINST ('match' IN BOOLEAN MODE)
ORDER BY MATCH(..fields..) AGAINST ('match' IN BOOLEAN MODE) DESC;
Который вы увидите, не даст вам нигде, если вы не добавите все словa >= ft_min_word_len
снова отдельно:
+John* +S* John
+John* +Smith* John Smith
+Smith* +J* Smith
+Jo* +S*
Для последнего, оба являются < по умолчанию 4 символа, поэтому мы не можем добавлять параметры сортировки для этого в mysql по умолчанию, но вы можете установить ft_min_world_len
по-разному.
Ответ 2
IN BOOLEAN MODE
вы можете использовать +
-modifier, чтобы заставить AND
или -
-модификатор принудительно NOT
. Никакой оператор, ваше дело, не обязательно.
И вам нужно проверить минимальную длину слова в вашей конфигурации mysql, чтобы индексные слова FULLTEXT INDEX были меньше определенной длины.
Мне пришлось установить
ft_min_word_len = 2
в my.cnf и пришлось перестроить индекс, чтобы сделать это эффективным. По умолчанию оно равно 3.
Чтобы узнать свой min_word_len чек (и увеличить) этот вопрос
Ответ 3
См. http://dev.mysql.com/doc/refman/5.5/en//fulltext-boolean.html
Вы можете поместить оператор "+", "-" или "нет" перед словом, чтобы он искал "И содержит это слово", "НЕ содержит это слово", и ни один оператор не "ИЛИ содержит это слово",
Если я наберу "John S", будет показан только первый результат, который является желаемым.
Там только один Джон, так что это работает, S меньше минимальной длины слова и отбрасывается
Если я наберу "Джон Смит", будет показан только первый результат, который является желаемым.
Там только один Джон, так что это работает
Если я нахожу "Smith J", оба результата показывают, что Bob не соответствует.
J ниже минимальной длины слова, поэтому его единственный совпадающий куз, который является двумя строками
Если я наберу "Смит Джон", оба результата показывают, хотя Боб не соответствует.
Поскольку вы находитесь в BOOLEAN MODE, MySQL интерпретирует это как Смит ИЛИ Джон... Смит соответствует обоим.
Наконец, если я нахожу "Jo S", результаты не возвращаются, несмотря на частичное совпадение на "Jo" и "S".
Jo и S ниже минимальной длины слова - я считаю, что MySQL рассматривает это как поиск ничего
Вам нужно добавить "+" перед вашими поисковыми параметрами, чтобы превратить их в поиск AND... +Smith +John