Как сделать полнотекстовый поиск с несколькими столбцами 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 | john_smith@js.com 2 | Smith | Bob | bob_smith@js.com 

Если я наберу «John S», только первый результат показывает, что является желаемым поведением.

Если я наберу «Джон Смит», будет показан только первый результат, который является желаемым поведением.

Если я наберу «Смит Дж», оба результата показывают, хотя Боб не соответствует.

Если я наберу «Смит Джон», оба результата показывают, что Боб не соответствует.

Наконец, если я набираю «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)"; 

В логическом режиме, требуя присутствия строк (вместо того, чтобы подсчитывать больше), выполняется с помощью + . prefix сопоставив делается с окончанием * . Это похоже на то, что вы хотите, поэтому выполните поиск:

 +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; 

Который вы увидите, не даст вам нигде, если вы не добавите все слова> = ft_min_word_len снова отдельно:

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

Для последнего, оба являются <по умолчанию 4 символа, поэтому мы не можем добавлять параметры сортировки для этого в mysql по умолчанию, но вы можете установить ft_min_world_len разному.

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

Вы можете разместить оператор «+», «-» или «нет» перед словом, чтобы он искал «И содержит это слово», «НЕ содержит это слово», и ни один оператор не «ИЛИ содержит это слово»,

Если я наберу «John S», только первый результат показывает, что является желаемым поведением.

Есть только один Джон, так что это работает, S меньше минимальной длины слова и отбрасывается

Если я наберу «Джон Смит», будет показан только первый результат, который является желаемым поведением.

Есть только один Джон, поэтому это работает

Если я наберу «Смит Дж», оба результата показывают, хотя Боб не соответствует.

J ниже минимальной длины слова, поэтому его единственный совпадающий кузнец, который является двумя рядами

Если я наберу «Смит Джон», оба результата показывают, что Боб не соответствует.

Поскольку вы находитесь в BOOLEAN MODE, MySQL интерпретирует это как Смит ИЛИ Джон … Смит соответствует обоим.

Наконец, если я набираю «Jo S», результаты не возвращаются, несмотря на частичное совпадение «Jo» и «S».

Jo и S ниже минимальной длины слова – я считаю, что MySQL относится к этому как к поиску ничего

Вам нужно добавить «+» перед вашими поисковыми параметрами, чтобы превратить их в поиск AND … +Smith +John

IN BOOLEAN MODE вы можете использовать + -модификатор, чтобы заставить AND или -modifier заставить NOT . Никакой оператор, ваше дело, не обязательно.

И вам нужно проверить минимальную длину слова в вашей конфигурации mysql, чтобы индексные слова FULLTEXT INDEX были меньше определенной длины.

Мне пришлось установить

 ft_min_word_len = 2 

в my.cnf и пришлось перестроить индекс, чтобы сделать это эффективным. По умолчанию это 3.

Чтобы узнать свой min_word_len, проверьте (и повысите) этот вопрос