Как запросить уникальные значения поля в ElasticSearch

Допустим, у нас есть индекс ElasticSearch под названием strings с полем pattern типа {"type": "keyword"}.

Получить топ-N значений колонки

Если мы хотим получить топ-N (12 в нашем примере) записей, т.е. pattern, которые присутствуют в большинстве документов, мы можем использовать этот запрос:

terms_aggregation_query.json
{
    "aggs" : {
        "patterns" : {
            "terms" : {
                "field" : "pattern.keyword",
                "size": 12
            }
        }
    }
}

Полный пример на Python:

es_terms_example.py
from elasticsearch import Elasticsearch

es = Elasticsearch()

result = es.search(index="strings", body={
    "aggs" : {
        "patterns" : {
            "terms" : {
                "field" : "pattern.keyword",
                "size": 12
            }
        }
    }
})
for aggregation in result["aggregations"]["patterns"]["buckets"]:
    print(aggregation) # e.g. {'key': 'mypattern, 'doc_count': 2802}

См. документацию по terms aggregation для более подробной информации.

Получить все уникальные значения колонки

Получить все значения немного сложнее, так как нам нужно использовать composite aggregation, который возвращает after_key для пагинации запроса.

Эта вспомогательная функция Python автоматически пагинирует запрос с настраиваемым размером страницы:

es_iterate_distinct.py
from elasticsearch import Elasticsearch

es = Elasticsearch()

def iterate_distinct_field(es, fieldname, pagesize=250, **kwargs):
    """
    Helper to get all distinct values from ElasticSearch
    (ordered by number of occurrences)
    """
    compositeQuery = {
        "size": pagesize,
        "sources": [{
                fieldname: {
                    "terms": {
                        "field": fieldname
                    }
                }
            }
        ]
    }
    # Iterate over pages
    while True:
        result = es.search(**kwargs, body={
            "aggs": {
                "values": {
                    "composite": compositeQuery
                }
            }
        })
        # Yield each bucket
        for aggregation in result["aggregations"]["values"]["buckets"]:
            yield aggregation
        # Set "after" field
        if "after_key" in result["aggregations"]["values"]:
            compositeQuery["after"] = \
                result["aggregations"]["values"]["after_key"]
        else: # Finished!
            break

# Usage example
for result in iterate_distinct_field(es, fieldname="pattern.keyword", index="strings"):
    print(result) # e.g. {'key': {'pattern': 'mypattern'}, 'doc_count': 315}

Check out similar posts by category: Databases ElasticSearch Python