Distinct-Feldwerte in ElasticSearch abfragen

English Deutsch

Nehmen wir an, wir haben einen ElasticSearch-Index namens strings mit einem Feld pattern vom Typ {"type": "keyword"}.

Die Top N Werte der Spalte abrufen

Wenn wir die Top N (12 in unserem Beispiel) Einträge abrufen möchten, d.h. die patterns, die in den meisten Dokumenten vorhanden sind, können wir diese Abfrage verwenden:

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

Vollständiges Beispiel in 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}

Siehe die Terms-Aggregation-Dokumentation für weitere Informationen.

Alle distinct-Werte der Spalte abrufen

Alle Werte abzurufen ist etwas komplizierter, da wir eine Composite-Aggregation verwenden müssen, die einen after_key zurückgibt, um die Abfrage zu paginieren.

Diese Python-Hilfsfunktion paginiert die Abfrage automatisch mit konfigurierbarer Seitengröße:

es_iterate_distinct.py
from elasticsearch import Elasticsearch

es = Elasticsearch()

def iterate_distinct_field(es, fieldname, pagesize=250, **kwargs):
    """
    Hilfsfunktion um alle distinct-Werte aus ElasticSearch abzurufen
    (sortiert nach Anzahl der Vorkommen)
    """
    compositeQuery = {
        "size": pagesize,
        "sources": [{
                fieldname: {
                    "terms": {
                        "field": fieldname
                    }
                }
            }
        ]
    }
    # Über Seiten iterieren
    while True:
        result = es.search(**kwargs, body={
            "aggs": {
                "values": {
                    "composite": compositeQuery
                }
            }
        })
        # Jeden Bucket ausgeben
        for aggregation in result["aggregations"]["values"]["buckets"]:
            yield aggregation
        # "after"-Feld setzen
        if "after_key" in result["aggregations"]["values"]:
            compositeQuery["after"] = \
                result["aggregations"]["values"]["after_key"]
        else: # Fertig!
            break

# Verwendungsbeispiel
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