В настоящее время у меня есть одно поле поиска для поиска по нескольким столбцам с помощью этого кода:
$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, проверьте (и повысите) этот вопрос