web-dev-qa-db-ja.com

Elasticsearchクエリで子を親のフィールドとして扱います

私はelasticsearchのドキュメントを読んでおり、この[page] [1]では、_parentを使用して子を親タイプにマッピングする方法について説明しています。

emailという名前の子がaccountという名前の親にアタッチされている場合:

各タイプのフィールド:

account (http://localhost:9200/myapp/account/1)
========
id
name
some_other_info
state

email (http://localhost:9200/myapp/email/1?parent=1)
========
id
email
  • nameaccountemailである場合、emailstateフィールドとaccountactiveフィールドを検索するにはどうすればよいですか?

  • 親が所有する(特定のタイプまたは任意のタイプの)すべての子を取得する方法はありますか?

  • 子ドキュメントのインデックスを作成するときに、クエリ文字列の一部ではなく、JSONデータのオブジェクトプロパティとして親を渡すことはできますか?


Imotovの提案を試した後、私はこのクエリを思いつきました:

これはhttp://localhost:9200/myapp/account/_searchで実行されます

{
  "query": {
    "bool": {
      "must": [
        {
          "prefix": {
            "name": "a"
          }
        },
        {
          "term": {
            "statuses": "active"
          }
        }
      ],
      "should": [
        {
          "has_child": {
            "type": "emailaddress",
            "query": {
              "prefix": {
                "email": "a"
              }
            }
          }
        }
      ]
    }
  }
}

問題は、上記ではメールが一致するアカウントが得られないことです。

私が望む効果は本質的にこれです:

  • 検索ボックスが1つあります
  • ユーザーが入力を開始すると、検索ボックスがオートコンプリートされます。
  • ユーザーのクエリは、accountまたはemailaddressタイプの名前と照合されます。
  • accountsが一致した場合は、それらを返すだけです。 emailaddressが一致した場合は、その親アカウントを返します。
  • 検索ごとに最大x(たとえば10)アカウントに制限します。

したがって、基本的に2つのタイプ間の検索をORして、一致の親タイプを返すことができる必要があります。


テストデータ:

curl -XPUT http://localhost:9200/test/account/1 -d '{
    "name": "John Smith",
    "statuses": "active"
}'

curl -XPUT http://localhost:9200/test/account/2 -d '{
    "name": "Peter Smith",
    "statuses": "active"
}'

curl -XPUT http://localhost:9200/test/account/3 -d '{
    "name": "Andy Smith",
    "statuses": "active"
}'

//Set up mapping for parent/child relationship

curl -XPUT 'http://localhost:9200/test/email/_mapping' -d '{
    "emails" : {
        "_parent" : {"type" : "account"}
    }
}'

curl -XPUT http://localhost:9200/test/email/1?parent=1 -d '{
    "email": "[email protected]"
}'

curl -XPUT http://localhost:9200/test/email/2?parent=1 -d '{
    "email": "[email protected]"
}'

curl -XPUT http://localhost:9200/test/email/3?parent=1 -d '{
    "email": "[email protected]"
}'

curl -XPUT http://localhost:9200/test/email/4?parent=2 -d '{
    "email": "[email protected]"
}'

curl -XPUT http://localhost:9200/test/email/5?parent=3 -d '{
    "email": "[email protected]"
}'

curl -XPUT http://localhost:9200/test/email/6?parent=3 -d '{
    "email": "[email protected]"
}'

imotovのソリューションは私のために働いた。私が見つけた別の解決策は、accountsにstatus = activeを照会し、結果に対してboolフィルターを実行し、子タイプにhas_childを使用し、prefixフィルター内のnameboolを使用することです。

20
F21

Elasticsearchとリレーショナルデータベースの重要な違いは、elasticsearchは結合を実行できないことです。 Elasticsearchでは、常に単一のインデックスまたはインデックスの和集合を検索しています。ただし、親子関係の場合は、子インデックスのクエリを使用して、親インデックスの結果を制限することができます。たとえば、このクエリはaccountタイプで実行できます。

{
    "bool": {
        "must": [
            { 
                "text" : { "name": "foo" } 
            }, { 
                "term" : { "state": "active" } 
            }, {
                "has_child": {
                    "type": "email",
                    "query": {
                        "text": {"email": "bar" }
                    }
                }
            }
        ]
    }
}

このクエリは親ドキュメントのみを返します(子ドキュメントは返されません)。このクエリによって返された親IDを使用して、デフォルトで保存およびインデックス付けされるフィールド_parentを使用して、この親のすべての子を検索できます。

{
    "term" : { "_parent": "1" } 
}

または、フィールドbarに単語emailを含む子のみに結果を制限することもできます。

{
    "bool": {
        "must": [
            { 
                "term" : { "_parent": "1" } 
            }, { 
                "text" : { "email": "bar" } 
            }
        ]
    }
}

_ bulk indexing を使用していない限り、jsonで親を指定することはできないと思います。

これは、質問で提供されたテストデータを使用して電子メールルックアップを実装する方法です。

#!/bin/sh
curl -XDELETE 'http://localhost:9200/test' && echo 
curl -XPOST 'http://localhost:9200/test' -d '{
    "settings" : {
        "number_of_shards" : 1,
        "number_of_replicas" : 0
    },
    "mappings" : {
      "account" : {
        "_source" : { "enabled" : true },
        "properties" : {
          "name": { "type": "string", "analyzer": "standard" },
          "statuses": { "type": "string",  "index": "not_analyzed" }
        }
      },
      "email" : {
        "_parent" : {
          "type" : "account"
        },
        "properties" : {
          "email": { "type": "string",  "analyzer": "standard" }
        }
      }
    }
}' && echo

curl -XPUT 'http://localhost:9200/test/account/1' -d '{
    "name": "John Smith",
    "statuses": "active"
}'

curl -XPUT 'http://localhost:9200/test/account/2' -d '{
    "name": "Peter Smith",
    "statuses": "active"
}'

curl -XPUT 'http://localhost:9200/test/account/3' -d '{
    "name": "Andy Smith",
    "statuses": "active"
}'

//Set up mapping for parent/child relationship

curl -XPUT 'http://localhost:9200/test/email/1?parent=1' -d '{
    "email": "[email protected]"
}'

curl -XPUT 'http://localhost:9200/test/email/2?parent=1' -d '{
    "email": "[email protected]"
}'

curl -XPUT 'http://localhost:9200/test/email/3?parent=1' -d '{
    "email": "[email protected]"
}'

curl -XPUT 'http://localhost:9200/test/email/4?parent=2' -d '{
    "email": "[email protected]"
}'

curl -XPUT 'http://localhost:9200/test/email/5?parent=3' -d '{
    "email": "[email protected]"
}'

curl -XPUT 'http://localhost:9200/test/email/6?parent=3' -d '{
    "email": "[email protected]"
}'

curl -XPOST 'http://localhost:9200/test/_refresh'
echo
curl 'http://localhost:9200/test/account/_search' -d '{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "statuses": "active"
          }
        }
      ],
      "should": [
        {
          "prefix": {
            "name": "a"
          }
        },
        {
          "has_child": {
            "type": "email",
            "query": {
              "prefix": {
                "email": "a"
              }
            }
          }
        }
      ],
      "minimum_number_should_match" : 1
    }
  }
}' && echo
21
imotov