ElasticSearch - Gibt eindeutige Werte zurück


122

Wie würde ich die Werte aller languagesaus den Datensätzen erhalten und sie einzigartig machen?

Aufzeichnungen

PUT items/1
{ "language" : 10 }

PUT items/2
{ "language" : 11 }

PUT items/3
{ "language" : 10 }

Abfrage

GET items/_search
{ ... }

# => Expected Response
[10, 11]

Jede Hilfe wäre großartig.


1
fields: [languages]gibt nur die Werte des angegebenen Feldes an, aber es ist wahrscheinlich einfacher, sie im Code eindeutig zu machen. Möglicherweise gibt es eine praktische Aggregation, die dies für Sie erledigen kann.
Ashalynd

1
Für diejenigen, die dieses Thema erforschen, gibt es hier auch eine nützliche Diskussion: Finden Sie unterschiedliche Werte, nicht unterschiedliche Zählungen in der
Elastiksuche

Antworten:


165

Sie können die Begriffe Aggregation verwenden .

{
"size": 0,
"aggs" : {
    "langs" : {
        "terms" : { "field" : "language",  "size" : 500 }
    }
}}

Eine Suche gibt ungefähr Folgendes zurück:

{
"took" : 16,
"timed_out" : false,
"_shards" : {
  "total" : 2,
  "successful" : 2,
  "failed" : 0
},
"hits" : {
"total" : 1000000,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
  "langs" : {
    "buckets" : [ {
      "key" : "10",
      "doc_count" : 244812
    }, {
      "key" : "11",
      "doc_count" : 136794

    }, {
      "key" : "12",
      "doc_count" : 32312
       } ]
    }
  }
}

Der sizeParameter innerhalb der Aggregation gibt die maximale Anzahl von Begriffen an, die in das Aggregationsergebnis aufgenommen werden sollen. Wenn Sie alle Ergebnisse benötigen, setzen Sie diesen Wert auf einen Wert, der größer ist als die Anzahl der eindeutigen Begriffe in Ihren Daten.


2
"fields" : ["language"]bringt das gleiche Ergebnis zurück. Können Sie Ihre Antwort erweitern, um festzustellen, ob das Aggregationsframework nur die Sprachwerte zurückgeben kann? #=> [10, 11, 10]
ChuckJHardy

1
@ CharlesJHardy, es hat nicht das gleiche Ergebnis. Die Daten, nach denen Sie suchen, befinden sich unter dem Schlüssel "Aggregationen". Ich habe meine Antwort mit einem Beispielergebnis bearbeitet. Sie können / sollten auch "Größe" setzen: 0, um keines der Dokumente einzuschließen, sondern nur die gewünschten aggregierten Ergebnisse.
Anton

1
Beachten Sie, dass Sie, wenn Sie viele mögliche Werte haben language, möglicherweise hinzufügen size=0und shard_size=0, um sicherzustellen, dass Sie alle Werte erhalten. Siehe elasticsearch.org/guide/en/elasticsearch/reference/current/…
Dror

3
Ich denke, diese Antwort spricht das OP nicht an. Die ursprüngliche Frage möchte, dass unterschiedliche Werte nicht zählen. Vermisse ich etwas
Bhurlow

4
@BHBH, Die Antwort liefert die unterschiedlichen Werte. Sie sind die "Schlüssel" -Werte, dh "10", "11" und "12". (Aggregationen> langs> Eimer> Schlüssel ...)
Anton

9

Elasticsearch 1.1+ verfügt über die Kardinalitätsaggregation , mit der Sie eine eindeutige Anzahl erhalten

Beachten Sie, dass es sich tatsächlich um eine Annäherung handelt und die Genauigkeit bei Datensätzen mit hoher Kardinalität möglicherweise abnimmt, bei meinen Tests jedoch im Allgemeinen ziemlich genau ist.

Sie können die Genauigkeit auch mit dem precision_thresholdParameter einstellen. Der Kompromiss oder Kurs ist die Speichernutzung.

Diese Grafik aus den Dokumenten zeigt, wie ein höherer precision_thresholdWert zu viel genaueren Ergebnissen führt.


Relativer Fehler gegen Schwelle


2
Hat Cardinality Aggregation Garantie , dass , wenn ein Begriff vorhanden ist , dann wird es in den Ergebnissen erscheint (mit einer Zählung> = 1)? Oder könnten möglicherweise einige Begriffe übersehen werden, die in einem großen Datensatz nur einmal vorkommen?
Markieren Sie den

2
@mark hängt von der von Ihnen festgelegten Genauigkeitsschwelle ab. Je höher die Schwelle, desto geringer ist die Wahrscheinlichkeit, dass sie verfehlt. Beachten Sie, dass die Einstellung des Genauigkeitsschwellenwerts auf 40.000 begrenzt ist. Was bedeutet, dass bei einem höheren Datensatz eine Schätzung vorliegt und daher der einzelne Wert möglicherweise übersehen wird
Sundar,

12
Ich glaube, diese Antwort ist falsch. Die Kardinalitätsaggregation ist ein hervorragendes Werkzeug. Die Aufgabe bestand jedoch darin, die Begriffe selbst abzurufen und nicht zu schätzen, wie viele verschiedene Begriffe es gibt.
Anton

4

Wenn Sie das erste Dokument für jeden languageeindeutigen Feldwert erhalten möchten , können Sie Folgendes tun:

{
 "query": {
    "match_all": {
    }
  },
  "collapse": {
    "field": "language.keyword",
    "inner_hits": {
    "name": "latest",
      "size": 1
    }
  }
}

3

Ich suche diese Art von Lösung auch für mich. Ich fand Referenz in Bezug auf Aggregation .

Demnach ist das Folgende die richtige Lösung.

{
"aggs" : {
    "langs" : {
        "terms" : { "field" : "language",  
                    "size" : 500 }
    }
}}

Aber wenn Sie auf folgenden Fehler gestoßen sind:

"error": {
        "root_cause": [
            {
                "type": "illegal_argument_exception",
                "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [fastest_method] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."
            }
        ]}

In diesem Fall müssen Sie der Anforderung " KEYWORD " hinzufügen , wie folgt:

   {
    "aggs" : {
        "langs" : {
            "terms" : { "field" : "language.keyword",  
                        "size" : 500 }
        }
    }}

1

Wenn Sie alle eindeutigen Werte ohne Annäherung oder Festlegen einer magischen Zahl ( size: 500) erhalten möchten , verwenden Sie COMPOSITE AGGREGATION (ES 6.5+) .

Aus der offiziellen Dokumentation :

"Wenn Sie alle Begriffe oder alle Kombinationen von Begriffen in einer verschachtelten Begriffsaggregation abrufen möchten, sollten Sie die COMPOSITE AGGREGATION verwenden , mit der Sie über alle möglichen Begriffe paginieren können, anstatt eine Größe festzulegen, die größer ist als die Kardinalität des Felds in der Begriffsaggregation Die Aggregation von Begriffen soll die Top-Begriffe zurückgeben und erlaubt keine Paginierung. "

Implementierungsbeispiel in JavaScript:

const ITEMS_PER_PAGE = 1000;

const body =  {
    "size": 0, // Returning only aggregation results: https://www.elastic.co/guide/en/elasticsearch/reference/current/returning-only-agg-results.html
    "aggs" : {
        "langs": {
            "composite" : {
                "size": ITEMS_PER_PAGE,
                "sources" : [
                    { "language": { "terms" : { "field": "language" } } }
                ]
            }
        }
     }
};

const uniqueLanguages = [];

while (true) {
  const result = await es.search(body);

  const currentUniqueLangs = result.aggregations.langs.buckets.map(bucket => bucket.key);

  uniqueLanguages.push(...currentUniqueLangs);

  const after = result.aggregations.langs.after_key;

  if (after) {
      // continue paginating unique items
      body.aggs.langs.composite.after = after;
  } else {
      break;
  }
}

console.log(uniqueLanguages);

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.