У меня есть такой набор таблиц в MySQL (внешние ключи, на которые ссылается [table_name] _id):
Articles(id, author_id, title, date, broad_search, ...)
Keywords(id, article_id, keyword (varchar))
Authors(id, name, ...)
Attachments(id, article_id, url, ...)
Таблица, которая нас больше всего беспокоит, это «Ключевые слова», поэтому я упоминаю индексы только для нее:
id - Primary - BTREE
(article_id,keyword) - Unique - BTREE
keyword - BTREE
article_id - BTREE
Каждая статья имеет связанный список ключевых слов. В столбце "broad_search" в Articles
указывается, может ли данная конкретная статья быть широко сопоставлена с ключевыми словами (broad_search = 1) или должно быть точное совпадение ключевого слова (broad_search = 0). У меня есть запрос SELECT, который вытягивает список статей на основе ключевых слов, параметра broad_search и других критериев фильтрации.
$sql = "SELECT *
FROM Keywords k, Attachments at, Articles ar, Authors a (2 more tables)
WHERE
((ar.broad_search=0 AND k.keyword = '$Keyword')
OR (ar.broad_search=1 AND (INSTR('$Keyword', k.keyword)>0 OR k.keyword like '%$Keyword%')))
AND at.article_id = ar.id
AND a.id = ar.author_id
... (more conditions)
LIMIT 20";
Для статьи может быть задано либо совпадение, либо точное совпадение, и я пытаюсь получить их список по ключевому слову.
Точное совпадение просто. Но у широкого соответствия есть различные случаи, которые не позволяют мне использовать простой шаблон подстановки, такой как «% search_term%». Пример:
Keywords for a broad match article = {books, used books, reading books, popular book}
search term = new books
Теперь мы не можем использовать совпадение с подстановочной строкой mysql, поскольку '%new books%'
не будет соответствовать ни одному из ключевых слов, но его необходимо найти, так как поисковый термин содержит подстроку ключевых слов (broad_search = 1). Итак, broad_search имеет 2 типа: search_term = "автомобили" в ключевом слове "подержанные автомобили" и поисковый термин = "подержанные автомобили" в ключевом слове "автомобили".
Если broad_search = 0, сделайте точное совпадение. Если broad_search = 1, сопоставьте оба случая:
((ar.broad_search=0 AND k.keyword = '$Keyword')
OR (ar.broad_search=1 AND (INSTR('$Keyword', k.keyword)>0 OR k.keyword like '%$Keyword%')))
Запрос, который я написал, отлично справляется Но проблема в производительности. Таблица ключевых слов очень большая, 100 000 строк и продолжает расти. Кроме того, это приложение с высокой нагрузкой и убивает мой сервер из-за огромного количества запросов, которые оно получает.
Мне кажется, это не правильный способ выполнения текстового поиска. Я попытался просмотреть документы mysql в отношении полнотекстового поиска, но я не совсем понял, в чем заключается его применение и соответствует ли оно моим критериям поиска. Кроме того, я подумал, что Apache Lucene будет лучшим выбором, но я не использовал его ранее, поэтому не уверен (этот запрос выполняется в сценарии PHP).
Как мне это реализовать? Это проблема индексации, или функция MySQL INSTR неэффективна, или я должен использовать совершенно другой подход?