ElasticSearchネストされたクエリ: 埋め込まれたドキュメントの検索方法

ElasticSearchネストされたクエリ: 埋め込まれたドキュメントの検索方法

  • オーケストレーション
5分で読めます 更新日 Nov 16, 2018

ポイント: ElasticSearchはネストされたJSONドキュメントで苦労することがあり、誤った検索結果を引き起こす可能性があります。これに対処するために、ネストされた構造を認識するためにインデックスを明示的に定義し、埋め込まれたドキュメントのクエリ時に検索精度を向上させます。

  • ネストされたJSONオブジェクトはElasticSearchでの検索結果を複雑にする可能性があります。
  • 埋め込まれたドキュメントの正確なクエリには、明示的なインデックス作成が必要です。

ElasticSearchは時々非常に複雑です。検索を実行すると誤った結果が返され、それに気づかないことがあります。これは、たとえば、ネストされたJSONドキュメントがあるときに発生する可能性があります。つまり、1つのJSONドキュメントの中に別のJSONドキュメントがある場合です。これは、Lucene(つまり、ElasticSearch)のクエリがJSONドキュメント内のオブジェクト階層を理解していないためです。

ネストされたJSONオブジェクトの検索に関する問題

問題と解決策を示すために、このプログラムmassAdd.pyをダウンロードし、URLを自分のElasticSearch環境に合わせて変更します。それを実行してください。その後、読み込まれたデータを確認します。ブラケットから、classesがJSON配列であることがわかります。しかし、インデックスは、見ての通り、これを反映していません。

    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"
        }
      }
    ]
  }

インデックスマッピングがJSON配列を示していないことに注意してください。これは、ブラケット[]がないからではありません。むしろnestedという単語が欠けています。

    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
                  }
                }
              }
            }
          },
...

物理学を受講している学生を検索するために論理的だと思われる方法を使用して検索を実行してください:

    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} }
                    ]
            }
        }
}'

この誤った結果が生成されます。これは、Luceneがドキュメント全体をフラット化し、両方のclasses.grades 1とclasses.name physicsを見つけるためです。

    {
        "_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"
        }
      }

インデックスを明示的にする

データを読み込むだけでElasticSearchにインデックスを作成できます。それが即座に作成されます。しかし、そうするとインデックスの作成方法を制御することはできません。したがって、インデックス作成を明示的にして、classesがJSON配列であることを明確にします。最初にインデックスを削除します。これにより、すべてのデータも削除されます。

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

次に、新しいインデックスを作成し、classesが大学オブジェクト内のオブジェクトであることを明示的に示します。"type":"nested"を使用します。注意: 大学データは入力していません。学生だけです。そのため、これらのフィールドは無視してください。(大学データは別の投稿で使用し、前の投稿で使用しました)。

    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" }
            }
          }
        }
}'

次に、massAdd.pyを再度実行してデータを再度読み込みます。今度は、物理学で1の成績を取得した学生を見つけるために、クエリにnestedとpathの用語を追加します。pathは、JSON内の親オブジェクトであり、この場合はclassesです。そして、クラス名で検索するためにclasses.nameを使用します:

    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} }
                    ]
                }
            }
        }
    }
}'

正しい結果が得られます。

    {
        "_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"
        }
      }
    ]

これらの投稿は私自身のものであり、必ずしもBMCの立場、戦略、または意見を代表するものではありません。

オーケストレーションの関連記事

The Briefを購読する

このオファーに登録することで、あなたはBMCのプライバシーポリシーを読み、同意したことを確認します。

ありがとう

あなたはThe Briefに登録されました
The Briefはメインフレームとエンタープライズオーケストレーション—BMC AMIとControl-M—および、両者に関するアナリストの研究、顧客の展開、イベントをカバーしています。