Как разрешить полнотекстовый поиск с дефисами в поисковом запросе
У меня есть ключевые слова, такие как "some-or-other", где дефис имеет значение при поиске через мою базу данных mysql. В настоящее время я использую полнотекстовую функцию.
Есть ли способ избежать символа дефиса?
Я знаю, что одним из вариантов является комментарий #define HYPHEN_IS_DELIM
в файле myisam/ftdefs.h, но, к сожалению, мой хост не разрешает это. Есть ли другой вариант?
Редактировать 3-8-11
Вот код, который у меня есть прямо сейчас:
$search_input = $_GET['search_input'];
$keyword_safe = mysql_real_escape_string($search_input);
$keyword_safe_fix = "*'\"" . $keyword_safe . "\"'*";
$sql = "
SELECT *,
MATCH(coln1, coln2, coln3) AGAINST('$keyword_safe_fix') AS score
FROM table_name
WHERE MATCH(coln1, coln2, coln3) AGAINST('$keyword_safe_fix')
ORDER BY score DESC
";
Ответы
Ответ 1
Отсюда http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
Одним из решений для поиска слова с тире или дефисом является использование ПОЛНОГО ТЕКСТА ПОИСКА В РЕЖИМЕ BOOLEAN и включение слова с дефис/тире в двойные кавычки.
Или отсюда http://bugs.mysql.com/bug.php?id=2095
Существует еще одно обходное решение. Недавно он был добавлен в руководство:
"
Измените файл набора символов: это не требует перекомпиляции. Макрос true_word_char()
использует таблицу "тип символа", чтобы отличать буквы и цифры от других
персонажи., Вы можете редактировать содержимое в одном из наборов символов XML
чтобы указать, что '-' является буквой. Затем используйте заданный набор символов для вашего
Индексы FULLTEXT.
"
Не пробовал самостоятельно.
Изменить: вот еще дополнительная информация отсюда http://dev.mysql.com/doc/refman/5.0/en/fulltext-boolean.html
Фраза, заключенная в символы двойной кавычки ( "" ), соответствует только строкам, которые содержат фразу буквально, поскольку она была напечатана. Полнотекстовый механизм разбивает фразу на слова и выполняет поиск в индексе FULLTEXT для слова. До MySQL 5.0.3 движок затем выполнил поиск подстроки для фразы в найденных записях, поэтому совпадение должно включать в себя несловочные символы во фразе. Начиная с MySQL 5.0.3, символы неслова не должны быть точно соответствует: поиск по фразам требует только того, чтобы совпадения содержали точно такие же слова, как фраза и в том же порядке. Например, "тестовая фраза" соответствует "test, phrase" в MySQL 5.0.3, но не раньше.
Если фраза не содержит слов, которые находятся в индексе, результат пуст. Например, если все слова являются либо временными, либо короче минимальной длины индексированных слов, результат пуст.
Ответ 2
Возможно, проще использовать оператор Binary
.
SELECT *
FROM your_table_name
WHERE BINARY your_column = BINARY "Foo-Bar%AFK+LOL"
http://dev.mysql.com/doc/refman/5.0/en/cast-functions.html#operator_binary
Оператор Binary
передает строку, следующую за ней, в двоичную строку. Это простой способ заставить сравнение столбцов выполнять байты по байтам, а не по символу. Это приводит к тому, что сравнение чувствительно к регистру, даже если столбец не определен как Binary
или BLOB
. Binary
также приводит к значительным значениям конечных пробелов.
Ответ 3
Некоторые люди предложили бы использовать следующий запрос:
SELECT id
FROM texts
WHERE MATCH(text) AGAINST('well-known' IN BOOLEAN MODE)
HAVING text LIKE '%well-known%';
Но вам нужно много вариантов в зависимости от используемых полнотекстовых операторов. Задача: выполнить запрос типа +well-known +(>35-hour <39-hour) working week*
. Слишком сложно!
И не забывайте значение len по умолчанию ft_min_word_len
, поэтому поиск up-to-date
возвращает только date
в ваших результатах.
Trick
Из-за этого я предпочитаю трюк, поэтому конструкции с HAVING
и т.д. вообще не нужны:
-
Вместо добавления в таблицу базы данных следующего текста:
"The Up-to-Date Sorcerer" is a well-known science fiction short story.
скопируйте дефисные слова без гипсов в конец текста внутри комментария: "The Up-to-Date Sorcerer" is a well-known science fiction short story.<!-- UptoDate wellknown -->
-
Если пользователь ищет up-to-date
удалить дефис в запросе sql:
MATCH(text) AGAINST('uptodate ' IN BOOLEAN MODE)
Таким образом, вы можете найти up-to-date
как одно слово вместо получения всех результатов, содержащих только date
(потому что ft_min_word_len
убивает up
и to
).
Конечно, перед текстом echo
вы должны удалить комментарии <!-- ... -->
.
<сильные > Преимущества
- запрос проще
- пользователь может использовать все полнотекстовые операторы как обычно
- запрос выполняется быстрее.
- Если пользователь ищет
-well-known +science
, MySQL рассматривает это как not include *well*, could include *known* and must include *science*
. Это не то, что ожидал пользователь. Этот трюк тоже решает (поскольку запрос sql ищет -wellknown +science
)
Ответ 4
Это может звучать, но после того, как я боролся с этим некоторое время, я понял, что получаю результаты, которые я хочу, удалив дефис из выражения поиска. Например, если я ищу "разделенный словами"
SELECT * FROM table WHERE MATCH(column) AGAINST ('word separated');
возвращает экземпляры "разделенных словами" по мере необходимости. Это также возвращает другие экземпляры разделенных и слов, но добавление оператора +
к каждому слову достигает поиска в дефис.
SELECT * FROM table WHERE MATCH(column) AGAINST ('+word +separated');
Ответ 5
Мое предпочтительное решение состоит в том, чтобы удалить дефис из поискового запроса и из данных, в которых выполняется поиск. Я храню две колонки в моей полнотекстовой таблице - search
и return
. search
содержит очищенные данные с удалением различных символов, и это то, с чем сравниваются поисковые запросы пользователей после того, как мой код также их очистил.
Затем я отображаю столбец return
.
Это означает, что у меня есть две копии данных в моей базе данных, но для меня этот компромисс стоит того. Моя таблица FT занимает всего ~ 500 тыс. Строк, поэтому в моем случае это не имеет большого значения.