Во второй части серии об оценке релевантности рассказываем, как позиции слов можно использовать для поиска совпадений и для оценки документов.
Знать позиции слов в поле важно: они помогают повысить релевантность поиска. На позициях построен широкий набор текстовых операторов: одни ищут совпадения по положению слова в поле, другие — по расстоянию между найденными ключевыми словами внутри поля или в сравнении с запросом. Один из самых востребованных операторов на основе позиций — оператор фразы (phrase)
: "A B". Совпадения по фразе строгие: ключевые слова должны совпасть ровно так, как они записаны в запросе, то есть стоять рядом и в том же порядке.
Зная позицию слова, можно найти поля, которые начинаются или заканчиваются определёнными словами: для этого есть операторы
начала (^) и конца ($) поля. Поиск внутри поля можно ограничить так, чтобы совпадение засчитывалось, только если слово стоит среди первых N слов поля. Для этого лимит указывают после оператора поля: @myfield [10] word. Можно также потребовать, чтобы слова запроса шли в заданном порядке, — с помощью оператора порядка word1 << word2 << word3, или чтобы они находились в поле на заданном расстоянии друг от друга, — с помощью оператора близости (proximity)
: "word1 word2"~10.
Оператор proximity позволяет иметь не более N слов между совпадающими ключевыми словами в поле. Например, "A B C"~4 совпадает с "A D E B F C", но не с "A D E B F G C".
Для менее ограничительного расстояния можно использовать оператор NEAR. В отличие от оператора proximity, который работает с набором ключевых слов, NEAR работает с двумя операндами, которые могут быть словами или другими подвыражениями. Например, можно написать "A B" NEAR/2 C — совпадение считается валидным, если между фразой "A B" и словом C находится максимум 2 слова. Аналогично существует оператор NOTNEAR, который совпадает только когда между операндами (словами или подвыражениями) имеется минимум слов.
Несколько метрик релевантности используют позиции слов для расчёта расстояния между запросом и документом. LCS (Longest Common Subsequence — наибольшая общая подпоследовательность) даёт длину максимального дословного совпадения между документом и запросом. Это означает, что мы пытаемся найти, есть ли подпоследовательности входного запроса в наших документах. Максимальное значение LCS равно количеству слов в запросе, если имеется точное совпадение. Подпоследовательности дают более низкие значения LCS в зависимости от их длины, а наименьшее значение — 1 — когда слова найдены, но не образуют подпоследовательность длиннее одного слова. Стоит учитывать, что подпоследовательность не обязана состоять из соседних совпавших слов. Например, если в запросе A B C, а в документе найдено A D C, эта подпоследовательность получит оценку 2, потому что A и C найдены в порядке и на тех же позициях, что и в запросе:
mysql> SELECT *,WEIGHT() FROM testrt WHERE MATCH('hello world program') OPTION ranker=expr('top(lcs)');
+------+--------------------------+----------------------------+----------+
| id | title | content | weight() |
+------+--------------------------+----------------------------+----------+
| 6 | hello world program | just some content | 3 |
| 4 | hello test program | just some world content | 2 |
| 5 | hello test world program | just some content | 2 |
| 9 | hello world | just program world content | 2 |
| 7 | hello test world | just program some content | 1 |
| 8 | test program hello | just some world content | 1 |
+------+--------------------------+----------------------------+----------+
6 rows in set (0.00 sec)
Документ 4 имеет LCS в заголовке со значением 2, потому что наш запрос — hello world program, а подпоследовательность — hello test program: хотя в ней есть слово, которого нет в списке совпадений, слова hello и program стоят на своих позициях (1 и 3), с одним словом между ними.
Документ 7 с hello test world, хотя содержит 2 слова (hello и world) в порядке, их позиции — 1 и 3, тогда как в запросе позиции — 1 и 2. Поскольку позиции не совпадают, мы не можем говорить о двух совпавших словах, образующих подпоследовательность.
Более ограничительная версия LCS — LCCS (Longest Common Contiguous Subsequence). LCCS оценивает только подпоследовательности, образованные соседними словами. Чтобы проиллюстрировать разницу, возьмём предыдущий пример, но теперь с LCCS:
mysql> select *,weight() from testrt where match('hello world program') option ranker=expr('top(lccs)');
+------+--------------------------+----------------------------+----------+
| id | title | content | weight() |
+------+--------------------------+----------------------------+----------+
| 6 | hello world program | just some content | 3 |
| 5 | hello test world program | just some content | 2 |
| 9 | hello world | just program world content | 2 |
| 4 | hello test program | just some world content | 1 |
| 7 | hello test world | just program some content | 1 |
| 8 | test program hello | just some world content | 1 |
+------+--------------------------+----------------------------+----------+
6 rows in set (0.00 sec)
Теперь у документа 4, у которого был LCS=2, LCCS=1, поскольку хотя есть подпоследовательность и слова находятся на тех же позициях, они не являются соседними.
И LCS, и LCCS считают каждое ключевое слово равным 1 в формуле, не учитывая информацию о важности (насколько слово редкое или распространённое). Вариация LCCS под названием WLCCS (Weighted Longest Common Contiguous Subsequence) может суммировать IDF ключевых слов вместо простого подсчёта. В отличие от LCS и LCCS, WLCCS принимает значения с плавающей точкой, поскольку IDF выражается дробным числом, а результат зависит от самих данных (IDF — мера, которая зависит от текущего индекса). WLCCS даст более высокие значения подпоследовательностям, включающим редкие слова, и может поднять в выдаче документ, который при использовании LCS или LCCS получил бы более низкую оценку.
Ранее мы говорили об операторе, который срабатывает, только если ключевые слова стоят в начале поля. Позицию первого вхождения тоже можно учитывать при расчёте релевантности: чем раньше ключевое слово встречается в поле (а лучше всего — в самом начале), тем оно важнее для этого поля. min_hit_pos указывает позицию первого совпавшего ключевого слова. В выражениях ранжирования можно добавить проверку min_hit_pos==1, чтобы узнать, стоит ли первое совпавшее ключевое слово в начале поля.
Самая ранняя позиция также может применяться к подпоследовательностям. Представьте, что у нас есть несколько документов, которые дают нам подпоследовательности, совпадающие с запросом (частично или полностью), и мы хотим узнать, в каких документах подпоследовательности появляются раньше в полях. Для этого можно использовать min_best_span_pos, который возвращает первое вхождение лучшей подпоследовательности (рассчитанной как LCS) в поле.
