ElasticSearch verschachtelte Abfragen: Wie man nach eingebetteten Dokumenten sucht

ElasticSearch verschachtelte Abfragen: Wie man nach eingebetteten Dokumenten sucht

  • Orchestrierung
5 Minuten Lesezeit Aktualisiert Nov 16, 2018

Auf einen Blick: ElasticSearch kann Schwierigkeiten mit verschachtelten JSON-Dokumenten haben, was zu falschen Suchergebnissen führt. Um dem entgegenzuwirken, definieren Sie den Index explizit so, dass er verschachtelte Strukturen erkennt und die Suchgenauigkeit beim Abfragen eingebetteter Dokumente verbessert.

  • Verschachtelte JSON-Objekte können die Suchergebnisse in ElasticSearch verkomplizieren.
  • Eine explizite Indexerstellung ist notwendig für eine genaue Abfrage eingebetteter Dokumente.

ElasticSearch ist manchmal nervig kompliziert. Man kann eine Suche ausführen, die falsche Ergebnisse anzeigt, ohne dass man darüber informiert wird. Das kann zum Beispiel passieren, wenn man ein verschachteltes JSON-Dokument hat, also ein JSON-Dokument in einem anderen. Das liegt daran, dass Lucene-Anfrage (also ElasticSearch) kein Verständnis für die Objekthierarchie in einem JSON-Dokument hat.

Das Problem bei der Suche nach verschachtelten JSON-Objekten

Um das Problem und die Lösung zu veranschaulichen, laden Sie dieses Programm massAdd.py herunter und ändern Sie die URL so, dass sie zu Ihrer ElasticSearch-Umgebung passt. Dann starten Sie es. Dann sehen Sie sich die geladenen Daten an. An den Klammern sehen Sie, dass die Klasse ein JSON-Array ist. Aber der Index, wie wir sehen werden, spiegelt das nicht wider.

    curl -XGET --header 'Content-Type: application/json' http://parisx:9200/universities/_search?pretty}

"_index" : "universities",
        "_type" : "universities",
        "_id" : "428b71b0b935eaf58bdf874c819f263a919da5f3",
        "_score" : 0.0,
        "_source" : {
          "firstName" : "Stephen",
          "classes" : [
            {
              "name" : "French",
              "grades" : 2
            },
            {
              "name" : "French",
              "grades" : 3
            },
            {
              "name" : "French",
              "grades" : 2
            },
            {
              "name" : "physics",
              "grades" : 6
            },
            {
              "name" : "physics",
              "grades" : 5
            }
          ],
          "lastName" : "Shakespeare",
          "school" : "Arizona State University"
        }
      }
    ]
  }

Beachte, dass die Indexabbildung das JSON-Array nicht anzeigt. Das liegt nicht daran, dass keine Klammern [] vorhanden sind. Vielmehr fehlt das verschachtelte Wort.

    curl -XGET --header 'Content-Type: application/json' http://parisx:9200/universities?pretty

...

"classes" : {
            "properties" : {
              "grades" : {
                "type" : "long"
              },
              "name" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              }
            }
          },
...

Suchen Sie also nach dem, was Ihrer Meinung nach der logische Weg ist, Physikstudenten zu finden, die eine Note von 1 bekommen haben:

    curl -XGET --header 'Content-Type: application/json' http://parisx:9200/universities/_search/?pretty=true -d '{
    "query": {
                "bool" : {
                    "must" : [
                    { "match" : {"classes.name" : "physics"} },
                    { "match" : {"classes.grades" :  1} }
                    ]
            }
        }
}'

Erzeugt dieses falsche Ergebnis. Das liegt daran, dass Lucene das gesamte Dokument abflacht und sowohl Klassen als auch classes.name Physik findet.

    {
        "_index" : "universities",
        "_type" : "universities",
        "_id" : "5846c01f90d80448ab087bf4f476cd3f8ab6f683",
        "_score" : 1.621972,
        "_source" : {
          "classes" : [
            {
              "grades" : 2,
              "name" : "physics"
            },
            {
              "grades" : 2,
              "name" : "French"
            },
            {
              "grades" : 3,
              "name" : "physics"
            },
            {
              "grades" : 1,
              "name" : "math"
            }
          ],
          "firstName" : "Stephen",
          "lastName" : "Rowe",
          "school" : "University of South Carolina - Columbia"
        }
      }

Den Index explizit machen

Man kann einen Index in ElasticSearch einfach durch das Laden von Daten erstellen. Das erstellt ihn on-the-fly. Aber man kann nicht kontrollieren, wie der Index erstellt wird, wenn man das tut. Also machen wir die Indexerstellung explizit und stellen klar, dass Klassen ein JSON-Array sind. Löschen Sie zuerst den Index, der auch alle Daten löscht.

    curl -XDELETE http://parisx:9200/universities

Erstellen Sie dann einen neuen Index und machen Sie klar, dass Klassen ein Objekt innerhalb des Universitätsobjekts sind, indem Sie "Typ" : "verschachtelt" verwenden. Hinweis: Wir füllen keine Universitätsdaten aus, sondern nur Studenten. Ignorieren Sie diese Felder. (Wir werden Universitätsdaten in einem anderen Beitrag verwenden und sie im vorherigen Beitrag verwendet).

    curl -XPUT --header 'Content-Type: application/json' http://parisx:9200/universities -d '{
    "mappings" : {
      "universities" : {
        "properties" : {
          "Address" : { "type" : "text"},
          "AdminEmail" : { "type" : "text"},
          "AdminName" : { "type" : "text" },
          "AdminPhone" : { "type" : "text" },
          "DapipId" : { "type" : "text" },
          "Fax" : { "type" : "text" },
          "GeneralPhone" : { "type" : "text" },
          "LocationName" : { "type" : "text" },
          "LocationType" : { "type" : "text" },
          "OpeId" : { "type" : "text" },
          "ParentDapipId" : { "type" : "text" },
          "ParentName" :  { "type" : "text" },
          "UpdateDate" : { "type" : "text" },
          "classes" : {
                "type" : "nested",
                "properties" : {
                   "name" : { "type" : "text"},
                   "grades" : { "type" : "integer" }
              }
            },
        "firstName" : { "type" : "text" },
          "lastName" : { "type" : "text" },
          "school" : { "type" : "text" }
            }
          }
        }
}'

Dann laden Sie die Daten erneut, indem Sie massAdd.py erneut ausführen: Fügen Sie nun die verschachtelten Begriffe und den Pfad zur Abfrage hinzu, um Schüler zu finden, die in Physik eine Note von 1 erreicht haben. Der Pfad ist das Elternobjekt im JSON, das in diesem Fall Klassen ist. Und verwenden Sie classes.name, um nach Klassennamen zu suchen:

    curl -XGET --header 'Content-Type: application/json' http://parisx:9200/universities/_search/?pretty=true -d '{
    "query": {
        "nested" : {
            "path" : "classes",
            "score_mode" : "avg",
            "query" : {
                "bool" : {
                "must" : [
                    { "match" : {"classes.name" : "physics"} },
                    { "match" : {"classes.grades" : 1} }
                    ]
                }
            }
        }
    }
}'

führt zum korrekten Ergebnis.

    {
        "_index" : "universities",
        "_type" : "universities",
        "_id" : "20ce682e16d0b88487addc9ceba2a695d57692aa",
        "_score" : 2.188588,
        "_source" : {
          "lastName" : "Shakespeare",
          "firstName" : "Julie",
          "classes" : [
            {
              "grades" : 1,
              "name" : "physics"
            },
            {
              "grades" : 6,
              "name" : "math"
            }
          ],
          "school" : "Arizona State University"
        }
      }
    ]

Diese Beiträge sind meine eigenen und spiegeln nicht unbedingt die Position, Strategien oder Meinung von BMC wider.

Mehr aus Orchestrierung

Abonnieren Sie The Brief

Mit der Registrierung für dieses Angebot bestätigen Sie, dass Sie die Datenschutzrichtlinie von BMC gelesen und zugestimmt haben.

Danke

Sie haben The Brief abonniert
Das Briefing umfasst die Mainframe- und Enterprise-Orchestrierung – BMC AMI und Control-M – sowie die Analystenforschung, Kundeneinsätze und Events in beiden Bereichen.