Лучший способ сделать взвешенный поиск по нескольким полям в MySQL? - PullRequest
22 голосов
/ 27 июня 2011

Вот что я хочу сделать:

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

Пример: предположим, у меня есть блог. Тогда кто-то ищет «php». Результаты будут выглядеть так:

  • сначала совпадения для поля 'title', упорядоченные по релевантности
  • тогда совпадения для поля 'body' также упорядочены по релевантности
  • и т. Д. С указанными полями ...

На самом деле я сделал это с классом в PHP, но он использует много UNIONS (много!) И растет с размером предмета поиска. Поэтому я беспокоюсь о производительности и проблемах с DOS. У кого-нибудь есть подсказки по этому поводу?

Ответы [ 5 ]

35 голосов
/ 27 июня 2011

Вероятно, этот подход к взвешенному поиску / результатам подходит вам:

SELECT *,
    IF(
            `name` LIKE "searchterm%",  20, 
         IF(`name` LIKE "%searchterm%", 10, 0)
      )
      + IF(`description` LIKE "%searchterm%", 5,  0)
      + IF(`url`         LIKE "%searchterm%", 1,  0)
    AS `weight`
FROM `myTable`
WHERE (
    `name` LIKE "%searchterm%" 
    OR `description` LIKE "%searchterm%"
    OR `url`         LIKE "%searchterm%"
)
ORDER BY `weight` DESC
LIMIT 20

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

Если у вас больше данных и вам нужны результаты быстрее, вы можете использовать что-то вроде Sphinx или Lucene.

9 голосов
/ 27 июня 2011

Вы можете добавить несколько значений mysql MATCH () вместе, сначала умножив каждое из них на их вес.

упрощенно конечно ...

'(MATCH(column1) AGAINST(\''.$_GET['search_string'].'\') * '.$column1_weight.')
 + (MATCH(column2) AGAINST(\''.$_GET['search_string'].'\') * '.$column2_weight.')
 + (MATCH(column3) AGAINST(\''.$_GET['search_string'].'\') * '.$column3_weight.')
 AS relevance'

тогда

'ORDER BY relevance'
1 голос
/ 18 июля 2018

Есть собственный и чистый способ сделать это, используя функцию CASE MySQL (https://dev.mysql.com/doc/refman/5.7/en/case.html).

Пример (не проверено):

SELECT * FROM `myTable` 
WHERE (`name` LIKE "%searchterm%" OR `description` LIKE %searchterm%" OR `url` LIKE "%searchterm%")
ORDER BY CASE
WHEN `name`        LIKE "searchterm%"  THEN 20
WHEN `name`        LIKE "%searchterm%" THEN 10
WHEN `description` LIKE "%searchterm%" THEN 5
WHEN `url`         LIKE "%searchterm%" THEN 1
ELSE 0
END
LIMIT 20

Использовали это для многих взвешенныхпоиски мои и работает абсолютное удовольствие!

1 голос
/ 27 июня 2011

У меня был точно такой же вопрос, и он был полностью дан ответ на одном из форумов MySQL. Вот нить. Вид длинной нити (потому что я немного скучный), но выигрыш - это то, что вы ищете.

1 голос
/ 27 июня 2011

Вы должны использовать специальный индексатор для предварительной загрузки всех данных в оптимизированный индекс с возможностью поиска. Sphinx и аналогичные продукты делают это очень хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...