mysql поиск, где пункт с каждым условием, имеющим различный счет - PullRequest
0 голосов
/ 12 октября 2011

В сумме

У меня есть два столбца, name и name_searchable.Я хотел бы найти в этих столбцах (которые имеют миллионы строк) и вернуть результаты в соответствии с их частотой совпадений.У меня есть два важных критерия;поиск должен быть эффективным и быстрым.Как мне этого добиться?

Подробнее

Я планирую создать таблицу с миллионами строк.В общем, я создал таблицу дампа просто для проверки запроса с миллионом строк.Таблица использует механизм хранения MyISAM, ее индекс и первичный ключ - это номер идентификатора.Поиск, который я хотел бы сделать, связан с полем имени, которое является столбцом varchar.Теперь, основываясь на запросе, я бы хотел вернуть все результаты, которые частично или полностью соответствуют запросу.Поэтому, когда пользователь ищет «björn borg», я хотел бы вернуть оба:

  • björn borg
  • björn borgus
  • bjorn borg (обратите внимание на o)

и так далее ...

Важным фактором здесь является то, что оператор = всегда должен возвращать более высокий рейтинг, чем оператор LIKE.Поэтому «björn borg» всегда должен предшествовать «bjorn borgus».

В последнее время я задал вопрос о том, как возвращать результаты в режиме, не учитывающем диакритические знаки, но, к сожалению, я не смог заставить его работать.Поэтому я создал еще один столбец вдоль столбца имени, в котором имя хранится только английскими символами.Итак, у нас есть поля name и name_searchable.

Ну, я попробовал все это с помощью хранимой процедуры, но, по-видимому, это очень медленно по сравнению с обычными запросами.Поэтому я хотел бы знать, могу ли я упорядочить результаты в соответствии с тем, какому предложению where они соответствуют.Другими словами:

SELECT * FROM myUsers WHERE name = 'björn borg' OR name_searchable = 'bjorn borg' OR name LIKE '%björn borg%' OR name_searchable LIKE '%bjorn borg%'; 

В общем, идея состоит в том, чтобы по-разному давать баллы каждому условию.Я имею в виду, что name = 'björn borg' должно иметь ранг, скажем, 5, name_searchable LIKE '% bjorn borg%' должно иметь 2 (а второй 4 балла, третий 3 балла ...) Как я могузаставить это работать, используя MySql?(Эффективность и скорость важны для меня)

Ответы [ 2 ]

1 голос
/ 12 октября 2011

Вы получите намного лучшую производительность, если не выполните LIKE '%<text>%', потому что это не будет правильно использовать индекс, вместо этого вы должны использовать LIKE '<text>%'.Я бы посоветовал вам подумать, хотите ли вы, чтобы пользователи могли искать name_searchable LIKE '%s%' и связанный с ним удар производительности, когда запрос занимает очень много времени и возвращает слишком много результатов.

Пробовали ли вы

SELECT CASE WHEN name = 'björn borg' THEN 1 
  WHEN name_searchable = 'bjorn borg' THEN 2 
  WHEN name LIKE '%björn borg%' THEN 3 
  WHEN name_searchable LIKE '%bjorn borg%' THEN 4 ELSE 5 END AS rank, * 
FROM myUsers 
WHERE name = 'björn borg' 
  OR name_searchable = 'bjorn borg' 
  OR name LIKE '%björn borg%' 
  OR name_searchable LIKE '%bjorn borg%'
ORDER BY CASE WHEN name = 'björn borg' THEN 1 
  WHEN name_searchable = 'bjorn borg' THEN 2 
  WHEN name LIKE '%björn borg%' THEN 3 
  WHEN name_searchable LIKE '%bjorn borg%' THEN 4 ELSE 5 END

Конечно, самый быстрый способ сделать это - добавить LIMIT 1

Другой вариант - использовать похожие поиски только при сбое точных совпадений:

SELECT CASE WHEN name = 'björn borg' THEN 1 
  WHEN name_searchable = 'bjorn borg' THEN 2 
  WHEN name LIKE '%björn borg%' THEN 3 
  WHEN name_searchable LIKE '%bjorn borg%' THEN 4 ELSE 5 END AS rank, * 
FROM myUsers 
WHERE name = 'björn borg' 
  OR name_searchable = 'bjorn borg' 
  OR (
    NOT EXISTS (SELECT TOP 1 1 FROM myUsers WHERE name = 'björn borg' OR name_searchable = 'bjorn borg' )
    AND (
    OR name LIKE '%björn borg%' 
    OR name_searchable LIKE '%bjorn borg%'
    )
  )
ORDER BY CASE WHEN name = 'björn borg' THEN 1 
  WHEN name_searchable = 'bjorn borg' THEN 2 
  WHEN name LIKE '%björn borg%' THEN 3 
  WHEN name_searchable LIKE '%bjorn borg%' THEN 4 ELSE 5 END
0 голосов
/ 12 октября 2011

Рассматривали ли вы разделение запросов и UNION их?

SELECT 5 AS rank, * FROM myUsers WHERE name = 'björn borg' UNION
SELECT 4 AS rank, * FROM myUsers WHERE name_searchable = 'bjorn borg' UNION
SELECT 3 AS rank, * FROM myUsers WHERE name LIKE '%björn borg%' UNION
SELECT 2 AS rank, * FROM myUsers WHERE name_searchable LIKE '%bjorn borg%'
ORDER BY 1 DESC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...