MySQL match () против () - порядок по релевантности и столбцу?

80

Хорошо, поэтому я пытаюсь выполнить полнотекстовый поиск в нескольких столбцах, примерно так:

SELECT * FROM pages WHERE MATCH(head, body) AGAINST('some words' IN BOOLEAN MODE)

Теперь я хочу отсортировать по релевантности (сколько слов найдено?), Что я смог сделать примерно так:

SELECT * , MATCH (head, body) AGAINST ('some words' IN BOOLEAN MODE) AS relevance 
FROM pages
WHERE MATCH (head, body) AGAINST ('some words' IN BOOLEAN MODE)
ORDER BY relevance

Теперь наступает та часть, где я теряюсь, я хочу расставить приоритеты по релевантности в headстолбце.

Думаю, я мог бы создать два столбца релевантности, один для headи один для body, но в этот момент я бы трижды выполнял один и тот же поиск в таблице, и для того, что я делаю этой функцией, важна производительность, поскольку запрос будет объединен и сопоставлен с другими таблицами.

Итак, мой главный вопрос: есть ли более быстрый способ поиска релевантности и определения приоритетов определенных столбцов? (И в качестве бонуса, возможно, даже подсчет релевантности, сколько раз слова встречаются в столбцах?)

Любые предложения или советы были бы замечательными.

Примечание: я буду запускать это на LAMP-сервере. (WAMP в локальном тестировании)

Кристоффер ла Кур
источник
Вам действительно нужно указывать MATCH ... AGAINST как в предложении SELECT, так и в предложении WHERE? Вы не можете использовать псевдоним в предложении SELECT и ссылаться на псевдоним в предложении WHERE? Я пытаюсь использовать подготовленные операторы, и мне это кажется избыточным / странным.
S. Imp
2
Нет, как указано в документации MySQL, начиная с версии 5.5, MATCH ... AGAINST будет вычисляться один раз, когда оба находятся в SELECT и WHERE, поэтому никаких дополнительных накладных расходов.
Bob2u

Ответы:

156

Это может повысить актуальность той части головы, которую вы хотите. Это не удвоит его, но, возможно, этого будет достаточно для вас:

SELECT pages.*,
       MATCH (head, body) AGAINST ('some words') AS relevance,
       MATCH (head) AGAINST ('some words') AS title_relevance
FROM pages
WHERE MATCH (head, body) AGAINST ('some words')
ORDER BY title_relevance DESC, relevance DESC

-- alternatively:
ORDER BY title_relevance + relevance DESC

Альтернативой, которую вы также хотите изучить, если у вас есть возможность переключить движок БД, является Postgres . Это позволяет установить вес операторов и поэкспериментировать с рейтингом.

Дени де Бернарди
источник
14
Кроме того, MySQL 5.6 поддерживает полнотекстовый поиск в таблицах InnoDB!
Джабари
1
Можете ли вы предоставить для этого скрипт SQL?
Пользователь
Насколько негативно влияют множественные поисковые запросы? Мне понадобится 4 совпадения в моем SELECT, так как у меня есть 4 разных весовых коэффициента. Значительно ли это снизит производительность?
ToBe
@ToBe Я видел, как по другим аналогичным вопросам более одного человека говорили, что использование нескольких MATCHоператоров не требует дополнительных затрат из-за того, как MySQL работает внутренне.
BadHorsie 08
Убедитесь, что вы запустите эти два. ALTER TABLE talk_webpages ADD FULLTEXT(head)иALTER TABLE talk_webpages ADD FULLTEXT(head, body)
Supun Kavinda
15

Просто добавление для тех, кому может понадобиться ... Не забудьте изменить таблицу!

ALTER TABLE table_name ADD FULLTEXT(column_name);
Камилла
источник
3
если вы выполните указанную выше команду более одного раза, будет создано несколько индексов для одного и того же столбца (столбцов). Так что просто запустите эту команду только один раз.
hakiko
Еще лучше использовать CREATE FULLTEXT INDEX indexname для tablename (column_name (s)). Вы также должны действительно проверить, существует ли индекс, прежде чем пытаться его создать. Вы можете проверить, существует ли он, используя: SELECT INDEX_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_CATALOG= 'def' AND TABLE_SCHEMA= DATABASE () AND TABLE_NAME= 'tablename' AND INDEX_NAME= 'indexname';
Дэйв Хилдитч
9

Я никогда этого не делал, но похоже

MATCH (head, head, body) AGAINST ('some words' IN BOOLEAN MODE)

Должны придавать двойной вес спичкам, найденным в голове.


Просто прочтите этот комментарий на странице документации , подумав, что это может быть полезно для вас:

Отправленный Патриком О'Лоуном, 9 декабря 2002 г., 6:51

В документации следует отметить, что IN BOOLEAN MODE почти всегда возвращает значение 1.0. Чтобы получить значимую актуальность, вам необходимо:

SELECT MATCH('Content') AGAINST ('keyword1 keyword2') as Relevance 
FROM table 
WHERE MATCH ('Content') AGAINST('+keyword1+keyword2' IN BOOLEAN MODE) 
HAVING Relevance > 0.2 
ORDER BY Relevance DESC 

Обратите внимание, что вы выполняете обычный запрос релевантности для получения факторов релевантности в сочетании с предложением WHERE, которое использует BOOLEAN MODE. BOOLEAN MODE дает вам подмножество, которое удовлетворяет требованиям поиска BOOLEAN, запрос релевантности выполняет фактор релевантности, а предложение HAVING (в данном случае) гарантирует, что документ релевантен для поиска (т. Е. Документы с оценкой менее 0,2 считаются неактуальными). Это также позволяет вам упорядочивать по релевантности.

Это может быть, а может и не быть ошибкой в ​​способе работы IN BOOLEAN MODE, хотя комментарии, которые я прочитал в списке рассылки, предполагают, что рейтинг релевантности IN BOOLEAN MODE не очень сложен, что плохо подходит для фактического предоставления соответствующих документов. Кстати, я не заметил потери производительности при этом, поскольку кажется, что MySQL выполняет поиск FULLTEXT только один раз, хотя два предложения MATCH отличаются. Используйте EXPLAIN, чтобы доказать это.

Таким образом, может показаться, что вам не нужно беспокоиться о двойном вызове полнотекстового поиска, хотя вам все равно следует «использовать EXPLAIN, чтобы доказать это»

Jisaacstone
источник
1
К сожалению, добавление головы дважды к функции match () не работает. Может быть, потому, что запрос не считает, сколько раз встречаются слова? И я использую эту страницу, на которую вы ссылаетесь, но по какой-то причине я не могу заставить ее работать ... Я еще не проиндексировал свои столбцы, и поэтому не могу выполнять поиск без тега "IN BOOLEAN MODE" .. .
Кристоффер ла Кур
Я думаю, что поиск без логических значений вернет количество вхождений, а логический - нет?
jisaacstone
Я более подробно рассмотрю это завтра, но пока задержусь. Спасибо за ответ, посмотрим, поможет ли мне, когда я разберусь с этим.
Kristoffer la Cour
У меня возникла проблема с использованием IN BOOLEAN MODE и последующим упорядочиванием по релевантности, и это решило мою проблему, когда актуальность всегда возвращалась как 1. Спасибо.
Jazzy
Создание поля оценки решило мою проблему: я получал результаты, но многие из них были полным шумом. Спасибо, +1
Chris Baker
4

Я тоже просто играл с этим. Один из способов добавить лишний вес - в области кода ORDER BY.

Например, если вы сопоставляете 3 разных столбца и хотите повысить вес определенных столбцов:

SELECT search.*,
MATCH (name) AGAINST ('black' IN BOOLEAN MODE) AS name_match,
MATCH (keywords) AGAINST ('black' IN BOOLEAN MODE) AS keyword_match,
MATCH (description) AGAINST ('black' IN BOOLEAN MODE) AS description_match
FROM search
WHERE MATCH (name, keywords, description) AGAINST ('black' IN BOOLEAN MODE)
ORDER BY (name_match * 3  + keyword_match * 2  + description_match) DESC LIMIT 0,100;
Ной Кинг
источник
Разве это не действительно сложный вопрос?
Beanow
5
Переместите математику в оператор select, и это значительно облегчит нагрузку. SELECT search.*, (MATCH (name) AGAINST ('black' IN BOOLEAN MODE) * 3) + (MATCH (keywords) AGAINST ('black' IN BOOLEAN MODE)*2 + MATCH (description) AGAINST ('black' IN BOOLEAN MODE)) AS totalScore , FROM search WHERE MATCH (name, keywords, description) AGAINST ('black' IN BOOLEAN MODE) ORDER BY totalScore DESC LIMIT 0,100;
reverseSpear