Формулировка проблемы: на данный момент сортировка результатов поиска по документам осуществляется по дате создания. Необходимо, чтобы результаты поиска были отсортированы по релевантности, причём учитывалась релевантность частичных совпадений — чем меньше найденное слово отличается от искомого, тем выше релевантность этого результата (см. пример по ссылке).
Решение: так как алгоритм поиска по документам на данный момент нигде не описан, сделаем это здесь. Список атрибутов (метаданных) документа, по которым ведётся поиск (поисковых атрибутов):
Номер документа;
Краткое содержание;
Номер исходящего;
Корреспондент;
Корреспондент (организация);
Тип документа;
Исполнитель документа;
Автор документа;
Пользователь, зарегистрировавший документ;
Кроме этих полей, поиск ведётся также по полям дополнительных
карточек старого (XForms
) и нового типов.
Замечание: в связи с переделкой механизмов
указания дополнительной карточки документа, а также реализованной
возможностью указания нескольких оснований для документа возможность
поиска по полям дополнительных карточек типа
XForms
необходимо проверить особо.
Поиск запускается путём ввода в поле «Поиск информации...»
поисковой строки и нажатия
Enter
. Поисковая строка разбивается на
искомые слова по пробелам. Документ становится
результатом поиска, если какое-либо из искомых
слов (одно или несколько, отношение «ИЛИ») встречается среди его
поисковых атрибутов, причём учитывается как полное, так и частичное
совпадение слов. Частичное совпадение слов срабатывает, если искомое
слово входит в найденное с начала (пример: для искомого слова «езд»
совпадениями будут «езд», «ездить», «ездок», но не «съезд»,
«подъезд»). Поиск слов является регистронезависимым, т.е. слова
«иван» и «Иван» считаются одинаковыми.
Результаты поиска сортируются согласно трём критериям релевантности, по убыванию (чем больше критерий релевантности, тем выше в списке соответствующий ему результат), в следующем порядке:
Результаты поиска, имеющие поисковые атрибуты, содержащие слова, точно совпадающие (с учётом регистронезависимости, а также акцентонезависимости: «mangé» = «mange») с какими-либо из искомых слов, сортируются по релевантности Rm, вычисляемой по нормализованной TF-IDF формуле (более подробно см. здесь).
Примечание: если искомое слово имеет длину
меньше, чем указано в параметре
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.
Результаты поиска, имеющие одинаковые Ra, сортируются согласно следующему критерию:
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 (всего одно слово «словари»).