Почему ранжирование работает не так как ожидалось

Здравствуйте.

Давно уже используем Manticoresearch (работает версия 6.3.6) для работы с адресами в системе. Загружаем их из ФИАС и строим полнотекстовый поиск по полной строке адреса. Более менее всё работало, но недавно наткнулись на необычное поведение ранжирования искомой строки, когда то, что ожидалось оказывается ниже чем, другие строки.

Итак, по порядку

DESCRIBE russia_fias_idx;
+---------------------+------------+--------------------------+
| Field               | Type       | Properties               |
+---------------------+------------+--------------------------+
| id                  | bigint     |                          |
| full_name           | string     | indexed stored attribute |
| name                | string     | indexed stored attribute |
| display_name        | string     |                          |
| custom_weight       | uint       |                          |
| json_tree           | json       |                          |
| full_name_length    | uint       |                          |
| aolevel             | uint       |                          |
| address_object_type | uint       |                          |
| full_name_len       | tokencount |                          |
| name_len            | tokencount |                          |
+---------------------+------------+--------------------------+

Делаем запрос с кастомным ранжированием:

select id, display_name, custom_weight, WEIGHT() AS W
from russia_fias_idx where MATCH('г Владимир проезд 2-й Почаевский') 
ORDER BY W DESC, full_name_len ASC, full_name_length ASC 
LIMIT 5 
OPTION ranker=expr('sum(exact_hit+lcs+custom_weight*0.1-min_gaps*0.1)*1000+bm25');

получаем результат:

+----------+------------------------------------------------------------------------------------------------------------------+---------------+------+
| id       | full_name                                                                                                     | custom_weight | w    |
+----------+------------------------------------------------------------------------------------------------------------------+---------------+------+
| 17885772 | Российская Федерация, Владимирская обл, г Владимир, проезд 2-й Почаевский, д. 2                                                        |             3 | 9159 |
| 24750954 | Российская Федерация, Владимирская обл, г Владимир, проезд 2-й Почаевский, д. 7, стр. 2                                                |             3 | 9159 |
| 32593543 | Российская Федерация, Владимирская обл, г Владимир, проезд 2-й Почаевский, д. 6а, стр. 2                                               |             3 | 9159 |
|  1201478 | Российская Федерация, Владимирская обл., г Владимир, проезд 2-й Почаевский                                                             |            10 | 8557 |
| 37929926 | Российская Федерация, Владимирская обл, г Владимир, проезд 2-й Почаевский, д. 5, к. 2                                                  |             3 | 7857 |
+----------+------------------------------------------------------------------------------------------------------------------+---------------+------+
5 rows in set (0,124 sec)

Искомая строка почему-то оказывается на 4м месте.

Делал запрос с PACKEDFACTORS({json=1})

Для первой строки:

{
    "bm25": 559,
    "bm25a": 0.5581727,
    "field_mask": 3,
    "doc_word_count": 7,
    "fields": [
        {
            "field": 0,
            "lcs": 7,
            "hit_count": 9,
            "word_count": 7,
            "tf_idf": 0.13068013,
            "min_idf": -0.00691398,
            "max_idf": 0.05496708,
            "sum_idf": 0.12550066,
            "min_hit_pos": 5,
            "min_best_span_pos": 5,
            "exact_hit": 0,
            "max_window_hits": 1,
            "min_gaps": 0,
            "exact_order": 1,
            "lccs": 7,
            "wlccs": 0.12550066,
            "atc": 0.00327622
        },
        {
            "field": 1,
            "lcs": 1,
            "hit_count": 1,
            "word_count": 1,
            "tf_idf": 0.01209343,
            "min_idf": 0.01209343,
            "max_idf": 0.01209343,
            "sum_idf": 0.01209343,
            "min_hit_pos": 1,
            "min_best_span_pos": 1,
            "exact_hit": 0,
            "max_window_hits": 1,
            "min_gaps": 0,
            "exact_order": 0,
            "lccs": 1,
            "wlccs": 0.01209343,
            "atc": 0
        }
    ],
    "words": [
        {
            "tf": 1,
            "idf": 0.00045326
        },
        {
            "tf": 1,
            "idf": 0.03094799
        },
        {
            "tf": 1,
            "idf": 0.01685472
        },
        {
            "tf": 2,
            "idf": -0.00691398
        },
        {
            "tf": 3,
            "idf": 0.01209343
        },
        {
            "tf": 1,
            "idf": 0.01709816
        },
        {
            "tf": 1,
            "idf": 0.05496708
        }
    ]
}

Для искомой 4-й:

{
    "bm25": 557,
    "bm25a": 0.59452122,
    "field_mask": 1,
    "doc_word_count": 7,
    "fields": [
        {
            "field": 0,
            "lcs": 7,
            "hit_count": 7,
            "word_count": 7,
            "tf_idf": 0.12550066,
            "min_idf": -0.00691398,
            "max_idf": 0.05496708,
            "sum_idf": 0.12550066,
            "min_hit_pos": 5,
            "min_best_span_pos": 5,
            "exact_hit": 0,
            "max_window_hits": 1,
            "min_gaps": 0,
            "exact_order": 1,
            "lccs": 7,
            "wlccs": 0.12550066,
            "atc": 0.00382692
        }
    ],
    "words": [
        {
            "tf": 1,
            "idf": 0.00045326
        },
        {
            "tf": 1,
            "idf": 0.03094799
        },
        {
            "tf": 1,
            "idf": 0.01685472
        },
        {
            "tf": 1,
            "idf": -0.00691398
        },
        {
            "tf": 1,
            "idf": 0.01209343
        },
        {
            "tf": 1,
            "idf": 0.01709816
        },
        {
            "tf": 1,
            "idf": 0.05496708
        }
    ]
}

Если сложить по формуле то веса сходятся, но почему так?

Ещё добавлю, что формулу ранжирования в своё время задавал не я и её происхождение не знаю :slight_smile: А тот кто знал, уже ушёл

Может кто-нибудь подсказать, чтобы адрес г Владимир, проезд 2-й Почаевский был выше чем г Владимир, проезд 2-й Почаевский, д. 2? Что можно попробовать?

Здравствуйте.

Причина в sum(): она суммирует выражение по всем полнотекстовым полям, в которых найдено совпадение.

У первой строки field_mask=3, то есть совпали full_name и name:

поле 0: 0 + 7 + 3*0.1 - 0 = 7.3
поле 1: 0 + 1 + 3*0.1 - 0 = 1.3
итого: (7.3 + 1.3)*1000 + 559 = 9159

У нужной строки field_mask=1, поэтому участвует только full_name:

поле 0: 0 + 7 + 10*0.1 - 0 = 8.0
итого: 8.0*1000 + 557 = 8557

То есть custom_weight у вас находится внутри полевой агрегации и у первой строки учитывается два раза. Кроме того, совпадение слова 2 в поле name добавляет ещё lcs=1.

exact_hit=0 в обоих случаях нормально: он равен 1 только когда запрос равен всему содержимому поля. Здесь full_name содержит ещё Российская Федерация, Владимирская обл....

Если вы действительно ищете только по полной строке адреса, самый простой вариант - это ограничить поиск полем full_name:

WHERE MATCH('@full_name (г Владимир проезд 2-й Почаевский)')

Спасибо, что ответили и спасибо за совет с поиском по full_name

Теперь ответ получается такой:

+----------+------------------------------------------------------------------------------------------------------------------+---------------+------+
| id       | display_name                                                       | custom_weight | w    |
+----------+------------------------------------------------------------------------------------------------------------------+---------------+------+
|  1201478 | Владимирская обл., г Владимир, проезд 2-й Почаевский               |             10 | 8557 |
| 17885772 | Владимирская обл, г Владимир, проезд 2-й Почаевский, д. 2          |             3 | 7858 |
| 24750954 | Владимирская обл, г Владимир, проезд 2-й Почаевский, д. 7, стр. 2  |             3 | 7858 |
| 32593543 | Владимирская обл, г Владимир, проезд 2-й Почаевский, д. 6а, стр. 2 |             3 | 7858 |
| 37929926 | Владимирская обл, г Владимир, проезд 2-й Почаевский, д. 5, к. 2    |             3 | 7857 |
+----------+------------------------------------------------------------------------------------------------------------------+---------------+------+

Т.е. из-за того, что у нас name включено вынесено тоже как поле для поиска и получается такая проблема.

В целом можете подсказать - такой подход и ранжирование подходят для поиска по адресам?