ElasticSearch - повышение релевантности на основе значения поля

Необходимо найти способ в ElasticSearch, чтобы повысить релевантность документа на основе определенного значения поля. В частности, во всех моих документах есть специальное поле, где чем выше значение поля, тем более актуальным должен быть документ, содержащий его, независимо от поиска.

Рассмотрим следующую структуру документа:

{
    "_all" : {"enabled" : "true"},
    "properties" : {
        "_id":            {"type" : "string",  "store" : "yes", "index" : "not_analyzed"},
        "first_name":     {"type" : "string",  "store" : "yes", "index" : "yes"},
        "last_name":      {"type" : "string",  "store" : "yes", "index" : "yes"},
        "boosting_field": {"type" : "integer", "store" : "yes", "index" : "yes"}
        }
}

Я бы хотел, чтобы документы с более высоким значением boosting_field были по своей сути более релевантными, чем те, у которых более низкое значение boosting_field. Это всего лишь отправная точка - сопоставление между запросом и другими полями также будет приниматься во внимание при определении окончательной оценки релевантности каждого документа в поиске. Но, при прочих равных условиях, чем выше поле форсирования, тем более актуальным является документ.

У кого-нибудь есть идея, как это сделать?

Спасибо большое!

Ответ 1

Вы можете либо увеличить время индекса, либо время запроса. Я обычно предпочитаю увеличение времени запроса, даже если оно делает запросы немного медленнее, в противном случае мне нужно будет переиндексации каждый раз, когда я хочу изменить свои факторы повышения, которые обычно необходимы для точной настройки и должны быть довольно гибкими.

Существуют различные способы применения повышения времени запроса с использованием запроса elasticsearch DSL:

Первые три запроса полезны, если вы хотите дать конкретный импульс документам, которые соответствуют конкретным запросам или фильтрам. Например, если вы хотите повысить только документы, опубликованные за последний месяц. Вы можете использовать этот подход с вашим boosting_field, но вам нужно будет вручную определить некоторые интервалы boosting_field и дать им разный импульс, что не так уж и велико.

Лучшим решением было бы использовать Custom Score Query, который позволит вам сделать запрос и настроить его оценку с помощью script. Он достаточно мощный, с помощью script вы можете напрямую изменить сам счет. Прежде всего, я бы масштабировал значения boosting_field до значения от 0 до 1, например, чтобы ваш окончательный результат не стал большим числом. Для этого вам нужно предсказать, какие более или менее минимальные и максимальные значения, которые может содержать поле. Предположим, например, минимум 0 и максимум 100000. Если вы масштабируете значение boosting_field до числа от 0 до 1, вы можете добавить результат к фактическому счету следующим образом:

{
    "query" : {
        "custom_score" : {
            "query" : {
                "match_all" : {}
            },
            "script" : "_score + (1 * doc.boosting_field.doubleValue / 100000)"
        }
    }
}

Вы также можете использовать boosting_field как фактор повышения (_score *, а не _score +), но тогда вам нужно будет масштабировать его до интервала с минимальным значением 1 (просто добавьте +1).

Вы можете даже настроить результат, чтобы изменить его значение, добавив вес к значению, которое вы используете, чтобы повлиять на оценку. Вам понадобится это еще больше, если вам нужно объединить несколько факторов повышения вместе, чтобы придать им другой вес.

Ответ 2

С помощью последней версии Elasticsearch (версия 1.3+) вы захотите использовать "запросы к функциям":

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html

Забитый запрос query_string выглядит следующим образом:

{
 'query': {
        'function_score': {
            'query': { 'query_string': { 'query': 'my search terms' } },
            'functions': [{ 'field_value_factor': { 'field': 'my_boost' } }]
        }
    }
}

"my_boost" - это числовое поле в вашем поисковом индексе, содержащем фактор повышения для отдельных документов. Может выглядеть так:

{ "my_boost": { "type": "float", "index": "not_analyzed" } }

Ответ 3

если вы хотите избежать повышения каждый раз внутри запроса, вы можете подумать о том, чтобы добавить его к вашему сопоставлению, добавив в него "boost: factor".

Итак, ваше сопоставление может выглядеть так:

{
    "_all" : {"enabled" : "true"},
    "properties" : {
        "_id":            {"type" : "string",  "store" : "yes", "index" : "not_analyzed"},
        "first_name":     {"type" : "string",  "store" : "yes", "index" : "yes"},
        "last_name":      {"type" : "string",  "store" : "yes", "index" : "yes"},
        "boosting_field": {"type" : "integer", "store" : "yes", "index" : "yes", "boost" : 10.0,}
        }
}

Ответ 4

Если вы используете Nest, вы должны использовать этот синтаксис:

.Query(q => q
    .Bool(b => b
        .Should(s => s
            .FunctionScore(fs => fs
                .Functions(fn => fn
                    .FieldValueFactor(fvf => fvf
                        .Field(f => f.Significance)
                        .Weight(2)
                        .Missing(1)
        ))))
        .Must(m => m
            .Match(ma => ma
                .Field(f => f.MySearchData)
                    .Query(query)
))))