ElasticSearch mehrstufige Eltern-Kind-Aggregation


79

Ich habe eine Eltern / Kind-Struktur in 3 Ebenen. Sagen wir:

Firma -> Mitarbeiter -> Verfügbarkeit

Da die Verfügbarkeit (und auch der Mitarbeiter) hier häufig aktualisiert wird, wähle ich die Verwendung der Eltern / Kind-Struktur für verschachtelte. Und die Suchfunktion funktioniert einwandfrei (alle Dokumente in korrekten Shards).

Jetzt möchte ich diese Ergebnisse sortieren. Das Sortieren nach Metadaten des Unternehmens (1. Ebene) ist einfach. Ich muss aber auch nach 3. Stufe sortieren (Verfügbarkeit).

Ich möchte eine Liste von Unternehmen, die sortiert sind nach:

  • Entfernung vom Standort bei angegebenem ASC
  • Bewertung DESC
  • Bald Verfügbarkeit ASC

Zum Beispiel:

Unternehmen A ist 5 Meilen entfernt, hat die Bewertung 4 und sobald einer seiner Mitarbeiter in 20 Stunden verfügbar ist, ist Unternehmen B ebenfalls 5 Meilen entfernt, hat ebenfalls die Bewertung 4, aber bald ist einer seiner Mitarbeiter in 5 Stunden verfügbar.

Daher muss das Sortierergebnis B, A sein.

Ich möchte jedem dieser Daten ein besonderes Gewicht hinzufügen, daher habe ich begonnen, Aggregationen zu schreiben, die ich später in meinem custom_score-Skript verwenden kann.

Vollständiger Inhalt zum Erstellen von Indizes, Importieren von Daten und Suchen

Jetzt habe ich es geschafft, eine Abfrage zu schreiben, die tatsächlich das Ergebnis zurückgibt, aber der Bucket für die Verfügbarkeitsaggregation ist leer. Allerdings bekomme ich auch Ergebnisse zu strukturiert zurück, ich möchte sie abflachen.

Derzeit bekomme ich zurück:

Firmen-IDS -> Mitarbeiter-IDS -> Erstverfügbarkeit

Ich hätte gerne eine Aggregation wie:

Firmen-IDS -> erste Verfügbarkeit

Auf diese Weise kann ich mein custom_scoreSkript erstellen, um die Punktzahl zu berechnen und sie richtig zu sortieren.

Vereinfachte Frage:
Wie kann man nach mehrstufigen (Enkel-) Kindern sortieren / aggregieren und möglicherweise das Ergebnis reduzieren?


Könnten Sie Ihre Zuordnung und einige Beispieldokumente (mit Nachkommen) zum Kern hinzufügen? Es ist schwer zu erkennen, wie Sie gefälschte Dokumente erfinden können, mit denen Sie Ihr System angemessen testen können.
Sloan Ahrens

Hey Sloan - Ich habe Mapping- und Beispielergebnisse hinzugefügt. Ich habe es zum leichteren Verständnis etwas entfernt. Full Stack enthält viel mehr Daten :) Danke!
Pete Minus

Ich hatte die gleiche Frage hier . Obwohl wahrscheinlich weniger performant, fordere ich nur alle Ergebnisse an, die eine Standardart von DocCount haben. Ich habe dann meine eigene rekursive Abflachung, Sortierung und Begrenzung durchgeführt, was nicht ideal war.
Matt Traynham

1
Ich habe Ihren Kern ausgeführt, aber bei der Suche erhalte ich den Fehler 500 Query Failed [Failed to execute main query]]; nested: NullPointerException;. Können Sie Ihren Kern in Ihrer lokalen Umgebung ausführen und sicherstellen, dass er in Ordnung ist? Vielen Dank!
Val

Warum erstellen Sie keine Gleichung für Ihre Ergebnisse? Ihre Daten sind nicht unscharf! Sie aggregieren jede Abfrage? . Aggregat sind Eingabeaktionen, keine Abfrage oder Ausgabe. Eine Frage "Wie Sie dieses Ergebnis überprüfen, ist wahr (richtig)?"
dsgdfg

Antworten:


3

Dazu benötigen Sie keine Aggregationen:

Dies sind die Sortierkriterien:

  1. Entfernung ASC (company.location)
  2. Bewertung DESC (company.rating_value)
  3. Früheste zukünftige Verfügbarkeit ASC (company.employee.availability.start)

Wenn Sie # 3 ignorieren, können Sie eine relativ einfache Unternehmensabfrage wie folgt ausführen :

GET /companies/company/_search
{
 "query": { "match_all" : {} },
 "sort": {
    "_script": {
        "params": {
            "lat": 51.5186,
            "lon": -0.1347
        },
        "lang": "groovy",
        "type": "number",
        "order": "asc",
        "script": "doc['location'].distanceInMiles(lat,lon)"
    },
    "rating_value": { "order": "desc" }
  }
}

# 3 ist schwierig, da Sie die Verfügbarkeit ( Unternehmen> Mitarbeiter> Verfügbarkeit ) für jedes Unternehmen ermitteln müssen, das dem Zeitpunkt der Anforderung am nächsten liegt, und diese Dauer als drittes Sortierkriterium verwenden müssen.

Wir werden eine function_scoreAbfrage auf Enkelkind-Ebene verwenden, um den Zeitunterschied zwischen der Anforderungszeit und jeder Verfügbarkeit im Treffer zu ermitteln _score. (Dann verwenden wir das _scoreals drittes Sortierkriterium).

Um die Enkelkinder zu erreichen, müssen wir eine has_childAbfrage innerhalb einer has_childAbfrage verwenden.

Für jedes Unternehmen möchten wir den schnellstmöglichen verfügbaren Mitarbeiter (und natürlich dessen engste Verfügbarkeit). Elasticsearch 2.0 gibt uns einen "score_mode": "min"Fall für solche Fälle, aber da wir uns darauf beschränken, werden "score_mode": "max"wir das Enkelkind _scorezum Kehrwert des Zeitunterschieds machen.

          "function_score": {
            "filter": { 
              "range": { 
                "start": {
                  "gt": "2014-12-22T10:34:18+01:00"
                } 
              }
            },
            "functions": [
              {
                "script_score": {
                  "lang": "groovy",
                  "params": {
                      "requested": "2014-12-22T10:34:18+01:00",
                      "millisPerHour": 3600000
                   },
                  "script": "1 / ((doc['availability.start'].value - new DateTime(requested).getMillis()) / millisPerHour)"
                }
              }
            ]
          }

Nun ist die _scorefür jedes Enkelkind ( Verfügbarkeit ) 1 / number-of-hours-until-available(damit wir die maximale wechselseitige Zeit bis zur Verfügbarkeit pro Mitarbeiter und die maximale wechselseitige (ly?) Verfügbare Mitarbeiterzahl pro Unternehmen verwenden können).

Alles in allem fragen wir weiterhin Unternehmen ab , verwenden jedoch Unternehmen> Mitarbeiter> Verfügbarkeit , um das _scorezu verwendende Sortierkriterium Nr. 3 zu generieren :

GET /companies/company/_search
{
 "query": { 
    "has_child" : {
        "type" : "employee",
        "score_mode" : "max",
        "query": {
          "has_child" : {
            "type" : "availability",
            "score_mode" : "max",
            "query": {
              "function_score": {
                "filter": { 
                  "range": { 
                    "start": {
                      "gt": "2014-12-22T10:34:18+01:00"
                    } 
                  }
                },
                "functions": [
                  {
                    "script_score": {
                      "lang": "groovy",
                      "params": {
                          "requested": "2014-12-22T10:34:18+01:00",
                          "millisPerHour": 3600000
                       },
                      "script": "1/((doc['availability.start'].value - new DateTime(requested).getMillis()) / millisPerHour)"
                    }
                  }
                ]
              }
            }
          }
        }
    }
 },
 "sort": {
  "_script": {
    "params": {
        "lat": 51.5186,
        "lon": -0.1347
    },
    "lang": "groovy",
    "type": "number",
    "order": "asc",
    "script": "doc['location'].distanceInMiles(lat,lon)"
  },
  "rating_value": { "order": "desc" },
  "_score": { "order": "asc" }
 }
}

Möglicherweise erzielen Sie eine etwas bessere Leistung, wenn Sie eine lineare Abklingfunktion anstelle eines Skripts verwenden, das _scorevon der Zeit bis zur Verfügbarkeit generiert wird .
Peter Dixon-Moses

Elasticsearch hat dynamisches Scripting standardmäßig deaktiviert. Besser ist es, indizierte Skripte zu verwenden. Siehe hier: elastic.co/blog/...
schellingerht

Pete Minus: Konnten Sie das zum Laufen bringen? Ich weiß, dass dies eine ältere Frage ist, aber es gibt viele Leute, die an Ihrer Lösung interessiert sind.
Peter Dixon-Moses

Peter Dixon-Moses: Schließlich habe ich aufgegeben und zwei Anfragen geschrieben - zuerst nach Unternehmen / Mitarbeiter zu suchen und dann über Verfügbarkeit nach den 100 besten Unternehmen zu suchen und dann zusammenzuführen. Warum? Es war zu zeitaufwändig, es nur in ES zu erstellen. Die für die Suche aufgewendete Zeit ist akzeptabel.
Pete Minus

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.