SQL LIKE, как отсортировать результаты по взвешенному количеству вхождений? - PullRequest
9 голосов
/ 24 февраля 2011

У меня есть мой поисковый термин:

"Yellow large widgets"

Я разделил термины на 3 слова:

1 = "Yellow";
2 = "Large";
2 = "Widgets";

Затем я ищу:

SELECT * FROM widgets
    WHERE (description LIKE '%yellow%' OR description LIKE '%large%' OR description LIKE 'widgets') 
    OR (title LIKE '%yellow%' OR title LIKE '%large%' OR title LIKE '%widgets%')

Как я могу отсортировать результаты с этими искажениями?

  • Титул имеет значение, если какой-либо из терминов присутствует в заголовке, его следует считать более важным
  • Количество вхождений, результаты с более высоким общим значениемвхождения должны появляться первыми

Идеальная методология

  • Количество вхождений в description.
  • Каждое вхождение здесь стоит 1 point.
  • Количество вхождений в title.
  • Каждое вхождение title стоит 5 points.
  • Сортировка по точкам.

Но я не знаю, с чего начать делать это в SQL.

Ответы [ 4 ]

10 голосов
/ 24 февраля 2011

Хорошо, давайте запишем условия поиска во временную таблицу:

CREATE TABLE #SearchTerms (Term varchar(50) not null)
insert into #SearchTerms (Term)
select 'yellow' union all
select 'large' union all
select 'widgets'

И давайте сделаем что-нибудь глупое:

select
    widgets.ID,
    (LEN(description) - LEN(REPLACE(description,Term,''))) / LEN(Term) as DescScore
    (LEN(title) - LEN(REPLACE(title,Term,''))) / LEN(Term) as TitleScore
from
    widgets,#SearchTerms

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

Итак, теперь мы можем суммировать и взвешивать эти случаи:

select
    widgets.ID,
    SUM((LEN(description) - LEN(REPLACE(description,Term,''))) / LEN(Term) +
    ((LEN(title) - LEN(REPLACE(title,Term,''))) / LEN(Term) *5)) as CombinedScore
from
    widgets,#SearchTerms
group by
    Widgets.ID

И если нам нужно сделать больше с этим, я бы рекомендовал поместить вышеупомянутое в подвыбор

select
    w.*,CombinedScore
from
    widgets.w
       inner join
    (select
        widgets.ID,
        SUM((LEN(description) - LEN(REPLACE(description,Term,''))) / LEN(Term) +
        ((LEN(title) - LEN(REPLACE(title,Term,''))) / LEN(Term) *5)) as CombinedScore
    from
        widgets,#SearchTerms
    group by
        Widgets.ID
    ) t
        on
            w.ID = t.ID
where
    CombinedScore > 0
order by
    CombinedScore desc

(обратите внимание, что я предположил, что во всех этих примерах есть столбец идентификатора, но его можно расширить на столько столбцов, сколько необходимо для определения PK в таблице виджетов)


Настоящий трюк здесь заключается в подсчете вхождений слова в большую часть текста, что делается с помощью:

(LEN(text) - LEN(text with each occurrence of term removed)) / LEN(term)
3 голосов
/ 24 февраля 2011

Выберите один из следующих вариантов:

  • использовать полнотекстовую поисковую систему (Lucene или аналог) для взвешенного полнотекстового поиска;
  • см. этот другой вопрос StackOverflow
  • сделать несколько SELECT с, каждое с полем релевантность , объединить их с UNION и отсортировать результат;
  • отсортируйте результаты в приложении после получения результатов.
0 голосов
/ 15 ноября 2015

Может быть, так

   SELECT description, title ,
            (       IF(title LIKE '%yellow%', 2, 0) +
            IF(title LIKE '%large%', 2, 0) +
            IF(title LIKE '%widgets%', 2, 0)+       IF(description LIKE '%yellow%', 1, 0) +
            IF(description LIKE '%large%', 1, 0) +
            IF(description LIKE '%widgets%', 1, 0)      )   AS w 

    FROM widget ORDER BY w DESC
0 голосов
/ 24 февраля 2011

Быстрый взлом (для mysql вы можете использовать аналогичные конструкции на других БД). Примечание, не проверено.

SELECT description, title
  FROM
(SELECT description, title,
        IF(description LIKE '%yellow%' OR 
           description LIKE '%large%' OR 
           description LIKE 'widgets' 2, 0) +
        IF(title LIKE '%yellow%' OR 
           title LIKE '%large%' OR
           title LIKE '%widgets%', 1, 0) AS w
  FROM widget)
 WHERE w > 0
ORDER BY w
...