Получить id документов в порядке убывания вхождения слов из запроса в документ

Допустим индексируемые документы содержат следующие данные:

шкаф двухдверный
шкаф двухдверный черный
шкаф двухдверный черный деревянный
шкаф коричневый
шкаф деревянный
шкаф шкаф шкаф шкаф
синхрофазатрон
деревянная полка
т.д.

Как получить id документов отсортированных в порядке убывания вхождения слов в запрос (одно слово из запроса учитывается только один раз для каждого документа - например, для документа с текстом “шкаф шкаф шкаф шкаф” - считаем только одно совпадение). Т.е. из указанных выше данных получить такой порядок для запроса “шкаф двухдверный черный деревянный

шкаф двухдверный черный деревянный
шкаф двухдверный черный
шкаф двухдверный
шкаф деревянный
шкаф коричневый
шкаф шкаф шкаф шкаф
деревянная полка
mysql> drop table if exists t; create table t(f text) morphology='lemmatize_ru_all'; insert into t(f) values('шкаф двухдверный'),('шкаф двухдверный черный'),('шкаф двухдверный черный деревянный'),('шкаф коричневый'),('шкаф деревянный'),('шкаф шкаф шкаф шкаф'),('синхрофазатрон'),('деревянная полка'); select * from t where match('"шкаф двухдверный черный деревянный"/1') option ranker=expr('sum(word_count)');
--------------
drop table if exists t
--------------

Query OK, 0 rows affected (0.01 sec)

--------------
create table t(f text) morphology='lemmatize_ru_all'
--------------

Query OK, 0 rows affected (0.00 sec)

--------------
insert into t(f) values('шкаф двухдверный'),('шкаф двухдверный черный'),('шкаф двухдверный черный деревянный'),('шкаф коричневый'),('шкаф деревянный'),('шкаф шкаф шкаф шкаф'),('синхрофазатрон'),('деревянная полка')
--------------

Query OK, 8 rows affected (0.01 sec)

--------------
select * from t where match('"шкаф двухдверный черный деревянный"/1') option ranker=expr('sum(word_count)')
--------------

+---------------------+-------------------------------------------------------------------+
| id                  | f                                                                 |
+---------------------+-------------------------------------------------------------------+
| 1514660626570412133 | шкаф двухдверный черный деревянный                                |
| 1514660626570412132 | шкаф двухдверный черный                                           |
| 1514660626570412131 | шкаф двухдверный                                                  |
| 1514660626570412135 | шкаф деревянный                                                   |
| 1514660626570412134 | шкаф коричневый                                                   |
| 1514660626570412136 | шкаф шкаф шкаф шкаф                                               |
| 1514660626570412138 | деревянная полка                                                  |
+---------------------+-------------------------------------------------------------------+
7 rows in set (0.00 sec)

Спасибо.

  1. что означает “/1” ?
  2. как это запрос на выборку оформить через php api?

это оператор кворума, описан тут Manticore Search Manual: Searching > Full text matching > Operators

Как я могу этот запрос отправить через PHP API?
select * from t where match(’“шкаф двухдверный черный деревянный”/1’) option
ranker=expr(‘sum(word_count)’)

php AddQuery должен обрабатывать такие запросы

$client->SetRankingMode ( "SPH_RANK_EXPR", "sum(word_count)" )
$client->AddQuery ('“шкаф двухдверный черный деревянный”/1', 't');

Правильно ли я понимаю? для каждого найденного документа вычисляется количество вхождений запрашиваемых при поиске слов в индекс документа - значение word_count. Тогда для чего делать sum? Что с чем суммируется?

Как переделать эту конструкцию, чтобы учитывался также мой рейтиг документов?
Каждому документу присваиваю “рейтинг” от 1 до 3 (записываю в поле myRating, в операторе SELECT конфигурации индекса), где 3 наиболее приоритетные документы.
Нужно что-то типа:

word_count * 0.5 / max_count + @myRating * 0.5 / 3

Таким образом, вклад word_count будет 50%, вклад рейтинга документа - 50%.
Как получить значение max_count?

В описании к факторам написано что это field level factor, те он считается для каждого поля и после вам нужно использовать какой-то агрегат sum / min / max - чтобы получить одно число

max_count - соответствует query_word_count но вы можете использовать форму “шкаф двухдверный черный деревянный”/0.5 как описано в документации для того чтобы получить нормализованные значения в диапазоне 0.0 - 1.0

и ваш запрос выглядел бы

SELECT ( weight() + myRating * 0.5 / 3 ) as sort FROM idx where match('“шкаф двухдверный черный деревянный”/0.5') ORDER by sort desc OPTION RANKER=expr('sum(word_count)' 

Спасибо. Как теперь правильно оформить этот запрос с помощью API?
Делаю:
$sphinx->SetSelect(‘*,( weight() + myRating * 0.5 / 3 ) as sort’);
$sphinx->SetRankingMode(“SPH_RANK_EXPR”, “sum(word_count)”);
// ORDER by sort desc как оформить?
$result = $sphinx->Query(“"$searchText"/0.5”, ‘idx’);

// ORDER by sort desc как оформить?

$sphinx->SetSortMode(SPH_SORT_EXTENDED, "sort desc")

Результаты с SphinxQL и через API - отличаются. Через API выдает не то, что нужно.
Может что-то я еще не указал?

вы можете включить опцию демона

query_log_format = sphinxql

и отправить запрос SphinxQL и API и сравнить то как эти запросы видит демон в query.log и проверить отличие в этих запросах

ммм, отличная опция. :+1:

Я так понимаю, если для запроса “шкаф деревянный” слово “шкаф” будет встречаться в нескольких полях документа, то каждое такое встретившееся слово будет добавлять +1. Можно ли сделать так, чтобы одно и то же слово из запроса, которое встречается сразу в нескольких полях прибавляло бы только единицу?

Не могу понять, как опция RANKER=expr(‘sum(word_count)’) и функция weight() связаны между собою. Простите, но в голове путаница, а документация только еще больше вносит непонятного)

Можно ли сделать так, чтобы одно и то же слово из запроса, которое встречается сразу в нескольких полях прибавляло бы только единицу?

надо пробовать разные запросы с разными факторами - может быть подойдет вот этот фактор doc_word_count ту судя по описанию он на целый документ сразу вычисляется

number of unique keywords matched in the document

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

про WEIGHT() сказано же, что это функция - вес документа, который можно получить \ использовать в select list

ну и про дефолтную сортировку можно почитать тут