web-dev-qa-db-ja.com

Elasticsearchを使用した配列オブジェクトタイプの正確な検索

私はエラスティック検索でexact配列一致を行う方法を探しています。これらが私のドキュメントだとしましょう:

{"id": 1, "categories" : ["c", "d"]}
{"id": 2, "categories" : ["b", "c", "d"]}
{"id": 3, "categories" : ["c", "d", "e"]}
{"id": 4, "categories" : ["d"]}
{"id": 5, "categories" : ["c", "d"]}

正確にカテゴリ「c」と「d」(ドキュメント1と5)を持つすべてのドキュメントを検索する方法はありますか?

ボーナスとして:「これらのいずれかの」カテゴリの検索も引き続き可能です(たとえば、「c」を検索して1、2、3、および5を取得できます)

この問題に取り組むための賢い方法はありますか?

17
Pascal

離散的な既知のカテゴリのセットがある場合は、boolクエリを使用できます。

"bool" : {
    "must" : {
        "terms" : { "categories" : ["c", "d"],
             minimum_should_match : 2
         }
    },
    "must_not" : {
        "terms" : { "categories" : ["a", "b", "e"],
             minimum_should_match : 1
         }
    }
}

そうでなければ、おそらくこれを達成する最も簡単な方法は、categoriesキーワードとして機能する別のフィールドを保存することだと思います。

{"id": 1, "categories" : ["c", "d"], "categorieskey" : "cd"}

そんな感じ。次に、次のように、用語クエリを使用して、必要な結果を正確にクエリすることができます。

term { "categorieskey" : "cd" }

そして、次のように、非排他的に検索することもできます。

term { "categories" : "c" }

両方が存在する必要がある2つのカテゴリをクエリするのは簡単ですが、他の潜在的なカテゴリが存在しないようにするのは少し難しいです。あなたはおそらくそれを行うことができます。おそらく、両方のレコードを検索するクエリを作成し、それにフィルタを適用して、指定されたカテゴリ以外のカテゴリのレコードを削除することをお勧めします。私の知る限り、Luceneが実際に処理するように設計されているのは実際には一種の検索ではありません。

正直なところ、ここで使用するのに適したフィルターを思い付くのに少し問題があります。スクリプトフィルターが必要な場合もあれば、取得後に結果をフィルター処理することもできます。

19
femtoRgon

うまくいくように見えるユースケースの解決策を見つけました。これは、2つのフィルターと、照合するカテゴリーの数に関する知識に依存しています。用語フィルターとスクリプトフィルターを使用して、配列のサイズをチェックします。この例では、marketBasketListはカテゴリエントリに似ています。

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "siteId": 4
          }
        },
        {
          "match": {
            "marketBasketList": {
              "query": [
                10,
                11
              ],
              "operator": "and"
            }
          }
        }
      ]
    },
    "boost": 1,
    "filter": {
      "and": {
        "filters": [
          {
            "script": {
              "script": "doc['marketBasketList'].values.length == 2"
            }
          },
          {
            "terms": {
              "marketBasketList": [
                10,
                11
              ],
              "execution": "and"
            }
          }
        ]
      }
    }
  }
}
1
Lucas Holt