Как добиться ранжирования на основе совпадения предложения (без полнотекстовой индексации) - PullRequest
1 голос
/ 31 января 2012

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

select 
    *
from
    sometable
where
(
    (
        firstname like 'chris%' or
        lastname like 'chris%'
    )
    and
    (
        firstname like 'vann%' or
        lastname like 'vann%'
    )    
)

Данные в таблице могут выглядеть следующим образом:

FirstName         LastName
------------------------------
Chris             Smith
John              Vann
Chris             Vann

Я бы хотел упорядочить результаты так, чтобы строка соответствовала-классы в предложении where (т.е. firstname = Chris и lastname = Vann) оцениваются выше, чем строка, соответствующая только одному из подпунктов.Возможно ли это в стандартном SQL?

Редактировать: Я значительно упростил вопрос, чтобы разобраться в сути проблемы.

Ответы [ 2 ]

1 голос
/ 31 января 2012

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

create table #t (f varchar(10), l varchar(10) );

insert into #t values ('aa','ee'),('aa','ii'),('oo','ee');

select 
   *,
   case when f like 'aa%' then 1 else 0 end +
   case when l like 'aa%' then 1 else 0 end +
   case when f like 'ii%' then 1 else 0 end + 
   case when l like 'aa%' then 1 else 0 end 
   as priority
from #t
order by 
   priority desc

Результаты:

f  l  priority 
-- -- -------- 
aa ee 4        
aa ii 4        
oo ee 0 

Для вашей схемы может быть что-то вроде:

select 
    *.
    case when firstname like 'chris%' and lastname like 'vann%' then 4 else 0 +
    case when firstname like 'chris%' and lastname not like 'vann%' then 3 else 0 +
    case when firstname not like 'chris%' and lastname like 'vann%' then 3 else 0 +
    ...
    as priority
from
    sometable
where
(
    (
        firstname like 'chris%' or
        lastname like 'chris%'
    )
    and
    (
        firstname like 'vann%' or
        lastname like 'vann%'
    )    
)
order by priority desc
0 голосов
/ 14 января 2019

Вот рейтинг T-SQL, который я набрал, кажется, работает довольно хорошо.

  • Он ранжируется с использованием функции разности для каждой пары поиска: первый-первый, первый-последний, последний-первый, last-last, затем добавляет вес, когда в имени или фамилии найдено совпадение подстроки поисковых терминов, причем совпадения first-first и last-last весят больше.совпадения и затем имеют самые ранние совпадения, а затем имеют наименьшую разницу между длиной строки поиска и длиной имени / фамилии.
  • Весовые коэффициенты (* 2, * 4) в TotalRank являются произвольными ипросто отразите мое желание взвешивать более тяжелые совпадения с первым-первым и последним-последним.
  • В приведенном ниже SQL есть много дополнительных столбцов, демонстрирующих компоненты, которые входят в столбец TotalRank.Очевидно, вы можете удалить их.

`

DECLARE @searchFirst varchar(max) = 'chris';

DECLARE @searchLast varchar(max) = 'vann';

SELECT firstname, lastname,

SOUNDEX(@searchFirst) as FSearchSoundEx,

SOUNDEX(firstname) as FSoundEx,

DIFFERENCE(firstname, @searchFirst) as FDiff,

LEN(firstName) - LEN(@searchFirst) as FFDelta,


SOUNDEX(lastname) as LSoundEx,

SOUNDEX(@searchLast) as LSearchSoundEx,

DIFFERENCE(lastName, @searchLast) as LDiff,

LEN(lastName) - LEN(@searchLast) as LLDelta,


PATINDEX('%' + @searchFirst + '%', firstname) as FFIndex,

PATINDEX('%' + @searchFirst + '%', lastname) as FLIndex,

PATINDEX('%' + @searchLast + '%', firstname) as LFIndex,

PATINDEX('%' + @searchLast + '%', lastname) as LLIndex,

CONVERT(BIT, PATINDEX('%' + @searchFirst + '%', firstname)) as HasFF,

CONVERT(BIT, PATINDEX('%' + @searchFirst + '%', lastname)) as HasFL, 

CONVERT(BIT, PATINDEX('%' + @searchLast + '%', firstname)) as HasLF,

CONVERT(BIT, PATINDEX('%' + @searchLast + '%', lastname)) as HasLL,

DIFFERENCE(firstname, @searchFirst) * DIFFERENCE(firstname, @searchFirst) as FFDiffSq, DIFFERENCE(lastname, @searchFirst) * DIFFERENCE(lastname, @searchFirst) as FLDiffSq, DIFFERENCE(firstname, @searchLast) * DIFFERENCE(firstname, @searchLast) as LFDiffSq, DIFFERENCE(lastname, @searchLast) * DIFFERENCE(lastname, @searchLast) as LLDiffSq,

DIFFERENCE(firstname, @searchFirst) * DIFFERENCE(firstname, @searchFirst) + DIFFERENCE(lastname, @searchFirst) * DIFFERENCE(lastname, @searchFirst) + DIFFERENCE(firstname, @searchLast) * DIFFERENCE(firstname, @searchLast) + Difference(lastname, @searchLast) * Difference(lastname, @searchLast) as SumDiffSquares,

DIFFERENCE(firstname, @searchFirst) * DIFFERENCE(firstname, @searchFirst) * 2 + DIFFERENCE(lastname, @searchFirst) * DIFFERENCE(lastname, @searchFirst) + DIFFERENCE(firstname, @searchLast) * DIFFERENCE(firstname, @searchLast) + DIFFERENCE(lastname, @searchLast) * DIFFERENCE(lastname, @searchLast) * 2
+ CONVERT(BIT, PATINDEX('%' + @searchFirst + '%', firstname)) * 4 + CONVERT(BIT, PATINDEX('%' + @searchFirst + '%', lastname)) + CONVERT(BIT, PATINDEX('%' + @searchLast + '%', firstname)) + CONVERT(BIT, PATINDEX('%' + @searchLast + '%', lastname)) * 4 as TotalRank

FROM Contacts

ORDER BY TotalRank Desc, HasLL Desc, HasFF Desc, HasFL Desc, HasLF Desc, LLIndex, FFIndex, FLIndex, LFIndex, LLDelta, FFDelta
...