Elasticsearch: как получить лучшие уникальные значения поля, отсортированные по совпадению?

У меня есть коллекция адресов. Давайте упростим и скажем, что единственными полями являются postcode, city, street, streetnumber и name. Я хотел бы иметь возможность предлагать список улиц, когда пользователь вводит почтовый индекс, город и некоторый запрос для улицы.

Например, если пользователь в HTML-форме вводит:

postcode: 75010
city: Paris
street: rue des

Я хотел бы получить список улиц, например

'rue des petites écuries'
'rue des messageries'
...
'rue du faubourg poissonnière'
...

что я мог бы предложить пользователю.

Итак, я хотел бы получить список уникальных значений поля «улица», отсортированных по тому, насколько хорошо они соответствуют моему запросу в поле «улица». Я хочу получить 10 наиболее подходящих улиц для этого запроса.

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

{
    "query": {
        "bool": {
            "must": [
                {{"term": {"postcode": "75010"}},
                {{"term": {city": "Paris"}},
                {{"match": {"street": "rue des"}}
            ]    
        }
     }
}

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

Я попытался использовать структуру «агрегации» и добавил аггс:

{
    "query": {
        "bool": {
            "must": [
                {{"term": {"postcode": "75010"}},
                    {{"term": {city": "Paris"}},
                    {{"match": {"street": "rue des"}}
            ]    
        }
     },
     "aggs": {
        "street_agg": {
            "terms": {
                "field": "street",
                "size": 10
             }
         }           
     }
}

Проблема в том, что он автоматически сортируется не по количеству баллов, а по количеству документов в каждой корзине.

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

Как бы вы этого добились?


person John Smith Optional    schedule 04.06.2018    source источник


Ответы (1)


Итак, решение действительно можно найти в порядок агрегации Elasticsearch по количеству попаданий, но только если вы читаете комментарий Шадоко: агрегация Elasticsearch упорядочить по количеству попаданий , чего у меня не было.

Итак, вот решение для всех, кто заинтересован, и для меня в будущем:

{                                 
    'query': {
        'bool': {
            'must': [
                {'term': {'postcode': '75010'}},
                {'term': {'city': 'Paris'}},
                {'match': {'street.autocomplete': 'rue des'}}
            ]
         }
    },
    'aggs': {
        'street_agg': {
            'terms': {
                'field': 'street',
                'size': 10,
                'order': {
                    'max_score': 'desc'
                }
            },
            'aggs': {
                'max_score': {
                    'max': {'script': '_score'}
                }
            }
        }
    }
}

Он не идеален, поскольку использует функцию агрегации max, а это означает, что он выполняет ненужные вычисления (было бы достаточно просто взять оценку одного документа из корзины). Но похоже, что функции агрегирования "выбрать один" нет, только min, max, avg и sum, так что вам придется это сделать. Ну, я думаю, что вычисление максимума в любом случае не так дорого.

person John Smith Optional    schedule 04.06.2018