Задача [#7852]: Сортировка результатов поиска по документам

Формулировка проблемы: на данный момент сортировка результатов поиска по документам осуществляется по дате создания. Необходимо, чтобы результаты поиска были отсортированы по релевантности, причём учитывалась релевантность частичных совпадений — чем меньше найденное слово отличается от искомого, тем выше релевантность этого результата (см. пример по ссылке).

Решение: так как алгоритм поиска по документам на данный момент нигде не описан, сделаем это здесь. Список атрибутов (метаданных) документа, по которым ведётся поиск (поисковых атрибутов):

Кроме этих полей, поиск ведётся также по полям дополнительных карточек старого (XForms) и нового типов.

Замечание: в связи с переделкой механизмов указания дополнительной карточки документа, а также реализованной возможностью указания нескольких оснований для документа возможность поиска по полям дополнительных карточек типа XForms необходимо проверить особо.

Поиск запускается путём ввода в поле «Поиск информации...» поисковой строки и нажатия Enter. Поисковая строка разбивается на искомые слова по пробелам. Документ становится результатом поиска, если какое-либо из искомых слов (одно или несколько, отношение «ИЛИ») встречается среди его поисковых атрибутов, причём учитывается как полное, так и частичное совпадение слов. Частичное совпадение слов срабатывает, если искомое слово входит в найденное с начала (пример: для искомого слова «езд» совпадениями будут «езд», «ездить», «ездок», но не «съезд», «подъезд»). Поиск слов является регистронезависимым, т.е. слова «иван» и «Иван» считаются одинаковыми.

Результаты поиска сортируются согласно трём критериям релевантности, по убыванию (чем больше критерий релевантности, тем выше в списке соответствующий ему результат), в следующем порядке:

Примечание: если искомое слово имеет длину меньше, чем указано в параметре ft_min_word_length (значение по умолчанию --- 4), то MySQL не будет рассчитывать релевантность для такого поиска. Поэтому для искомых слов длиной менее значения ft_min_word_length Rm мы вычисляем самостоятельно:

Rm = ∑ncount(xn) , где

n --- количество найденных искомых слов;

count(xn) --- количество точных совпадений слова хn со словами из поисковых атрибутов найденного документа;

$$R_a = \sum_{m} \left ( \frac{\sum_{i=0}^{N-1}\left ( \frac{len(y_{m}^{i})}{len(y_{m}^{i}) - len(x_m) + 1} \right )}{N_m} \right )$$ , где

m --- общее количество искомых слов, найденных в результате (если найденное слово присутствует в поисковой строке несколько раз, все они входят в m);

x --- исходное слово, len(x) --- длина исходного слова;

y --- найденное слово (исходное слово входит в него как часть);

len(y) --- длина найденного слова;

N --- количество y, найденных по m-тому х, т.е. размер набора найденных по какому-либо искомому слову слов. Пример: исходное слово «лев», найдены «левый», «левее», «левак», N=3.

RL = ∑m(∑N(len(ymN))) , т.е. сумме всех длин найденных слов для всех искомых.

Как видно из формул, оба критерия, Ra и RL, имеют такую возможность, как усиление веса какого-либо искомого слова --- достаточно повторить слово несколько раз, и релевантность найденного документа с этим словом возрастёт пропорционально количеству его повторений.

Разберём ситуацию на примерах. Допустим, у нас есть набор документов с такими атрибутами:

Номер Краткое содержание

77

Хороший документ

778

Входящее письмо

7796

Из КПМ срочно

77961

Всё очень плохо

779614

На самом деле, нет

7796145

словарный словарный словарный словарный словарный словарный словарный словарный словарный словарный

7796146

слова поэта

779648

kill all humans

7796888

слова

7796999

слова наши - просто слова

7796777

словари

7796454

словари словарный

7796123

словари словари

Пусть поисковая строка будет слова. Отсортированные результаты поиска будут таковы:

Номер Краткое содержание Rm Ra RL

7796999

слова наши - просто слова

6.096320629119873

7796146

слова поэта

3.7137179374694824

7796888

слова

3.5679874420166016

7796123

словари словари

0

2.3333333333

14

7796777

словари

0

2.3333333333

7

7796454

словари словарный

0

2.0666666666

7796145

словарный словарный словарный словарный словарный словарный словарный словарный словарный словарный

0

1.8

Покажем, как рассчитывается Ra и RL на примере документа с номером 7796123. В этом документе найдено одно искомое слово «слова», указано оно в поисковой строке один раз, поэтому m=1. Длина искомого слова для первого (и единственного) m len(x) = 5. Совпадений для него найдено N = 2. len(y0) = len(y1) = 7. Следовательно,

$$R_a = \sum_{1} \left ( \frac{\sum_{i=0}^{N-1}\left ( \frac{len(y_{m}^{i})}{len(y_{m}^{i}) - len(x_{m}) + 1)} \right )}{N_m} \right ) = \frac{\sum_{i=0}^{2-1}\left ( \frac{len(y_{1}^{i})}{len(y_{1}^{i}) - 5 + 1} \right )}{2} = \frac{\frac{7}{7 - 4}+\frac{7}{7 - 4}}{2} = 2\frac{1}{3}$$

Как мы видим, такая же Ra получается для документа с номером 7796777, поэтому для обоих этих документов необходимо рассчитать RL. Легко видеть, что в первом случае это 14 (len(словари)+len(словари)), а во втором --- 7 (всего одно слово «словари»).