MySQL – Как получить результаты поиска с точной релевантностью

Я неоднократно пересматривал эту проблему, и я никогда не нашел правильного ответа.

Возможно ли выполнить поиск MySQL, который возвращает ACTUAL точно отсортированные результаты по релевантности?

Я пытаюсь создать форму поиска ajax, которая делает предложения, когда пользователь вводит в поле ввода, и не нашел подходящего решения для этого, используя только чистые запросы MySQL. Я знаю, что есть поисковые серверы, такие как ElasticSearch, я хочу знать, как это сделать, только с необработанным MySQL-запросом.


У меня есть таблица школьных предметов. Есть менее 1200 строк, и это никогда не изменится. Давайте проведем базовый поиск FULLTEXT, где пользователь начнет вводить «Bio».

Запрос («Bio …») – FULLTEXT BOOLEAN MODE

SELECT name, MATCH(name) AGAINST('bio*' IN BOOLEAN MODE) AS relevance FROM subjects WHERE MATCH(name) AGAINST('bio*' IN BOOLEAN MODE) ORDER BY relevance DESC LIMIT 10 

Результаты

 name | relevance -------------------------------------------------------- Biomechanics, Biomaterials and Prosthetics | 1 Applied Biology | 1 Behavioural Biology | 1 Cell Biology | 1 Applied Cell Biology | 1 Developmental/Reproductive Biology | 1 Developmental Biology | 1 Reproductive Biology | 1 Environmental Biology | 1 Marine/Freshwater Biology | 1 

Чтобы показать, насколько плохи эти результаты, вот сравнение с простым запросом LIKE который показывает все более релевантные результаты, которые не были показаны:

Запрос («Bio …») – LIKE

 SELECT id, name WHERE name LIKE 'bio%' ORDER BY name 

Результаты

 name | relevance -------------------------------------------------------- Bio-organic Chemistry | 1 Biochemical Engineering | 1 Biodiversity | 1 Bioengineering | 1 Biogeography | 1 Biological Chemistry | 1 Biological Sciences | 1 Biology | 1 Biomechanics, Biomaterials and Prosthetics | 1 Biometry | 1 

И уже вы видите, сколько предметов не предлагается, даже если они более вероятно, что пользователь будет искать.

Однако проблема с использованием LIKE заключается в том, как выполнять поиск по нескольким словам и в середине слов, таких как FULLTEXT .

Основной порядок, который я хотел бы реализовать, это что-то вроде:

  1. Первые слова, начинающиеся с поискового запроса
  2. Второе слово, начинающееся с поискового запроса
  3. Слова, где термин не находится в начале слов
  4. Все обычно в алфавитном порядке, если не

Итак, мой вопрос: как можно получить разумно отсортированный список предложений для пользователя с поиском MySQL по нескольким словам?

Related of "MySQL – Как получить результаты поиска с точной релевантностью"

Вы можете использовать строковые функции, такие как:

 select id, name from subjects where name like concat('%', @search, '%') order by name like concat(@search, '%') desc, ifnull(nullif(instr(name, concat(' ', @search)), 0), 99999), ifnull(nullif(instr(name, @search), 0), 99999), name; 

Это дает вам все записи, содержащие @search. Сначала те, которые имеют это в начале, затем те, которые имеют его после пробела, затем по положению события, затем по алфавиту.

name like concat(@search, '%') desc использует логическую логику MySQL, кстати. 1 = true, 0 = false, поэтому упорядочение этого спуска дает вам истинное первое.

Скрипт SQL: http://sqlfiddle.com/#!9/c6321a/1

Для других, приземляющихся здесь (как и я): по моему опыту, для достижения наилучших результатов вы можете использовать условное в зависимости от количества поисковых слов. Если есть только одно слово, используйте LIKE '% word%', в противном случае используйте логический полнотекстовый поиск, например:

 if(sizeof($keywords) > 1){ $query = "SELECT *, MATCH (col1) AGAINST ('+word1* +word2*' IN BOOLEAN MODE) AS relevance1, MATCH (col2) AGAINST ('+word1* +word2*' IN BOOLEAN MODE) AS relevance2 FROM table1 c LEFT JOIN table2 p ON p.id = c.id WHERE MATCH(col1, col2) AGAINST ('+word1* +word2*' IN BOOLEAN MODE) HAVING (relevance1 + relevance2) > 0 ORDER BY relevance1 DESC;"; $execute_query = $this->conn->prepare($query); }else{ $query = "SELECT * FROM table1_description c LEFT JOIN table2 p ON p.product_id = c.product_id WHERE colum1 LIKE ? AND column2 LIKE ?;"; // sanitize $execute_query = $this->conn->prepare($query); $word=htmlspecialchars(strip_tags($keywords[0])); $word = "%{$word}%"; $execute_query->bindParam(1, $word); $execute_query->bindParam(2, $word); } 

Я попробовал это на основе вашего описанного заказа.

 SET @src := 'bio'; SELECT name, name LIKE (CONCAT(@src,'%')), LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(name,' ',2),' ',-1),LENGTH(@src)) = @src, name LIKE (CONCAT('%',@src,'%')) FROM subjects ORDER BY name LIKE (CONCAT(@src,'%')) DESC, LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(name,' ',2),' ',-1),LENGTH(@src)) = @src DESC, name LIKE (CONCAT('%',@src,'%')) DESC, name 

http://sqlfiddle.com/#!9/6bffa/1

Я подумал, может быть, вы даже захотите включить количество вхождений @src. Считать количество вхождений строки в поле VARCHAR?