Suchen nach Duplikaten in Elasticsearch

9

Ich versuche Einträge in meinen Daten zu finden, die in mehr als einem Aspekt gleich sind. Ich mache dies derzeit mit einer komplexen Abfrage, die Aggregationen nistet:

%Vor%

Dies funktioniert in einem Ausmaß, wie das Ergebnis, das ich erhalte, wenn keine Duplikate gefunden werden, ungefähr wie folgt aussieht:

%Vor%

Ich überspringe etwas von der Ausgabe, die ziemlich ähnlich aussieht.

Ich kann jetzt diese komplexe tief verschachtelte Datenstruktur durchsuchen und feststellen, dass in all diesen verschachtelten Buckets keine Dokumente gespeichert sind. Aber das scheint ziemlich umständlich. Ich denke, es könnte eine bessere (einfachere) Art und Weise, dies zu tun.

Wenn ich mehr als vier Felder überprüfen möchte, wird diese verschachtelte Struktur wachsen und wachsen und wachsen. Es skaliert also nicht sehr gut und ich möchte das vermeiden.

Kann ich meine Lösung verbessern, sodass ich eine einfache Liste aller Dokumente erhalte, die Duplikate sind? (Vielleicht sind das die Duplikate von einander irgendwie gruppiert.) Oder gibt es einen ganz anderen Ansatz (zB ohne Aggregation), der die hier beschriebenen Nachteile nicht aufweist?

EDIT: Ich habe einen Ansatz gefunden, der die Script-Funktion von ES hier verwendet, aber in meinem Version von ES gibt nur eine Fehlermeldung zurück. Vielleicht kann jemand auf mich hinweisen, wie man es in ES 5.0 macht? Meine bisherigen Versuche haben nicht funktioniert.

EDIT: Ich habe einen Weg gefunden, ein Skript für meinen Ansatz zu verwenden, der den modernen Weg benutzt (Sprache "schmerzlos"):

%Vor%

Dies scheint bei sehr kleinen Datenmengen zu funktionieren und führt zu einem Fehler bei realistischen Datenmengen ( circuit_breaking_exception : [request] Data too large, data for [<reused_arrays>] would be larger than limit of [6348236390/5.9gb] ). Irgendeine Idee, wie ich das beheben kann? Wahrscheinlich einige Einstellungen des ES anpassen, um größere interne Puffer oder ähnliches zu verwenden?

Es scheint keine richtige Lösung für meine Situation zu geben, die die Verschachtelung allgemein vermeidet.

Glücklicherweise haben drei meiner vier Felder einen sehr begrenzten Wertebereich; der erste kann nur 1 oder 2 sein, der zweite kann 1, 2 oder 3 sein und der dritte kann 1, 2, 3 oder 4 sein. Da dies nur 24 Kombinationen sind, gehe ich derzeit mit dem Filtern eines 24. aus dem Ganzen Datensatz vor dem Anwenden der Aggregation, dann von nur eins (das verbleibende vierte Feld). Ich muss dann alle Aktionen 24 Mal anwenden (einmal mit jeder Kombination der drei oben genannten begrenzten Felder), aber das ist noch praktikabler als die vollständige Verarbeitung des gesamten Datensatzes.

Die Abfrage (d. h. eine der 24 Abfragen), die ich jetzt sende, sieht ungefähr so ​​aus:

%Vor%

Die Ergebnisse dafür sind natürlich nicht mehr verschachtelt. Dies kann jedoch nicht durchgeführt werden, wenn mehr als ein Feld beliebige Werte eines größeren Bereichs enthält.

Ich habe auch herausgefunden, dass wenn Verschachtelung gemacht werden muss, die Felder mit dem am meisten eingeschränkten Wertebereich (zB nur zwei Werte wie "1 oder 2") innerlich sein sollten und der mit der größte Wertebereich sollte äußerster sein. Dies verbessert die Leistung stark (aber immer noch nicht genug in meinem Fall). Wenn Sie es falsch machen, können Sie eine unbrauchbare Abfrage erhalten (keine Antwort innerhalb von Stunden und schließlich nicht genügend Arbeitsspeicher auf der Serverseite).

Ich denke jetzt, dass die richtige Aggregation der Schlüssel zur Lösung eines Problems wie meines ist. Der Ansatz, der ein Skript verwendet, um eine flache Bucket-Liste zu haben (wie in meiner Frage beschrieben), wird den Server überlasten, da er die Aufgabe in keiner Weise verteilen kann. Für den Fall, dass kein Doppel gefunden wird, muss ein Bucket für jedes Dokument im Speicher gehalten werden (mit nur einem Dokument). Auch wenn nur wenige Doubles gefunden werden können, ist dies bei größeren Datenmengen nicht möglich. Wenn nichts anderes möglich ist, muss der Datensatz künstlich in Gruppen aufgeteilt werden. Z.B. Man kann 16 Unterdatensätze erstellen, indem man aus den relevanten Feldern einen Hash erstellt und die letzten 4 Bits verwendet, um das Dokument in die 16 Gruppen einzutragen. Jede Gruppe kann dann getrennt behandelt werden; Doubles werden mit dieser Technik in eine Gruppe fallen.

Unabhängig von diesen allgemeinen Überlegungen sollte die ES-API jedoch alle Möglichkeiten bieten, um durch das Ergebnis von Aggregationen paginieren zu können. Es ist schade, dass es (noch) keine solche Möglichkeit gibt.

    
Alfe 06.12.2016, 15:45
quelle

2 Antworten

1

Ihr letzter Ansatz scheint der beste zu sein. Und Sie können Ihre Elasticsearch-Einstellungen wie folgt aktualisieren:

%Vor%

Ich habe 75% gewählt, weil der Standardwert 60% ist und in Ihrer elasticsearch 5.9gb ist und Ihre Abfrage wird ~6.3gb , was basierend auf Ihrem Protokoll ungefähr 71.1% ist.

  

circuit_breaking_exception: [request] Data too large, data for [<reused_arrays>] would be larger than limit of [6348236390/5.9gb]

Und schließlich muss indices.breaker.total.limit größer sein als indices.breaker.fielddata.limit nach elasticsearch Dokument .

    
Dulguun 13.12.2016 05:24
quelle
0

Eine Idee, die in einem Logstash-Szenario funktionieren könnte, ist das Kopieren von Feldern:

Kopieren Sie alle Kombinationen in separate Felder und fassen Sie sie zusammen:

%Vor%

aggregiert über das neue Feld.

Schauen Sie hier nach: Ссылка

Ich weiß nicht, ob add_field Array unterstützt (andere tun es, wenn Sie sich die Dokumentation ansehen). Wenn dies nicht der Fall ist, können Sie versuchen, mehrere neue Felder hinzuzufügen und die Zusammenführung zu verwenden, um nur ein Feld zu haben.

Wenn Sie dies zur Indexzeit tun können, wäre es sicherlich besser.

Sie benötigen nur die Kombinationen (A_B) und nicht alle Permutationen (A_B, B_A)

    
Dennis Ich 06.12.2016 17:21
quelle