Добрый день,
наверное задам этот вопрос в 100500 раз, проведя в тестах и поиске гугл я так и не нашел для себя внятного ответа.
Постановка задачи:
Есть поисковое слово, к примеру "тест", нужно найти следующие его словоформы:
- тест
- тест*
- *тест*
При этом нужно отранжировать результаты:
- сначала по словоформе (т.е. документы с четкими совпадениями тест должны стоять выше чем документы с совпадениями тест*)
- если словоформы одинаковые, то выше идет документ, у кого больше словоформ этого типа (т.е. документ "тест тест" должен стоять выше чем документ "просто тест")
Положение слова в документе, его частотность и пр. не важны, т.е. слова "это" и "контрвзбзднуть" для меня равны
Тестовый индекс:index rttest2
{
type = rt
path = /var/sphinx/rttest2
rt_attr_string = phrase1
rt_field = phrase2
min_infix_len = 2
index_exact_words = 1
}
INSERT into rttest2(id,phrase1,phrase2) values(1,'очень простой тест','очень простой тест');
INSERT into rttest2(id,phrase1,phrase2) values(2,'хитрый тестик','хитрый тестик');
INSERT into rttest2(id,phrase1,phrase2) values(3,'супертестик','супертестик');
INSERT into rttest2(id,phrase1,phrase2) values(4,'тестировщик тестов','тестировщик тестов');
Неправильное решение 1: Используем OPTION ranker=sph04 (это типичный ответ, если спрашивают про точные совпадения)
... потому что это ранжирование учитывает прежде всего положение слова в документе и частотность:
select *,weight() from rttest2 where match('тест|тест*|*тест*') and id <= 4 option ranker=sph04;
+------+-------------------------------------+----------+
| id | phrase1 | weight() |
+------+-------------------------------------+----------+
| 3 | супертестик | 6430 |
| 4 | тестировщик тестов | 6310 |
| 1 | очень простой тест | 4430 |
| 2 | хитрый тестик | 4362 |
+------+-------------------------------------+----------+
Не очень хорошее решение 2: пишем собственное ранжирование на основе hit_count и exact_order
... потому что это работает при одном поисковом слове, а при болшем количестве - нет
select *,weight() from rttest2 where match('тест|тест*|*тест*') option ranker=expr('sum(exact_order*10+hit_count)');
+------+-------------------------------------+----------+
| id | phrase1 | weight() |
+------+-------------------------------------+----------+
| 1 | очень простой тест | 13 |
| 4 | тестировщик тестов | 4 |
| 2 | хитрый тестик | 2 |
| 3 | супертестик | 1 |
+------+-------------------------------------+----------+
Однако, добавим еще один документ и второе слово в поиск и все становится плохо (так как exact_order перестает работать):
INSERT into rttest2(id,phrase1,phrase2) values(5,'тестик тестик простой','тестик тестик простой');
select *,weight() from rttest2 where match('(тест|тест*|*тест*)&(простой|простой*|*простой*)') option ranker=expr('sum(exact_order*10+hit_count)');
+------+------------------------------------------+----------+
| id | phrase1 | weight() |
+------+------------------------------------------+----------+
| 5 | тестик тестик простой | 7 |
| 1 | очень простой тест | 6 |
+------+------------------------------------------+----------+
Непонятно почему не работающее решение 3: пытаемся добавить вес словоформам путем повторения (чтоб не использовать exact_order), но ранжирование вообще перестает работать, так как hit_count становится всегда равным 1:
select *,weight() from rttest2 where match('тест|тест*|*тест*') option ranker=expr('sum(hit_count)');
+------+------------------------------------------+----------+
| id | phrase1 | weight() |
+------+------------------------------------------+----------+
| 4 | тестировщик тестов | 4 |
| 5 | тестик тестик простой | 4 |
| 1 | очень простой тест | 3 |
| 2 | хитрый тестик | 2 |
| 3 | супертестик | 1 |
+------+------------------------------------------+----------+
select *,weight() from rttest2 where match('тест|тест|тест*|*тест*') option ranker=expr('sum(hit_count)');
+------+------------------------------------------+----------+
| id | phrase1 | weight() |
+------+------------------------------------------+----------+
| 4 | тестировщик тестов | 2 |
| 5 | тестик тестик простой | 2 |
| 1 | очень простой тест | 1 |
| 2 | хитрый тестик | 1 |
| 3 | супертестик | 1 |
+------+------------------------------------------+----------+
вывод с packedfactors не привожу, так как он делает сообщение не читаемым, желающие могут легко включить его в запросы
Подозреваю, что тут есть какая-то ошибка или "фича" sphinx, которая мешает воспользоваться этим трюком.
Подитоживая: нормального решения я не нашел, есть приемлеммое решение для одного поискового слова, но нет решения для нескольких поисковых форм. Возможно кто-то придложет решение получше