5

検索インターフェースでよくある問題は、選択した結果を返したいが、すべてのドキュメントに関する情報を返したい場合があるということです。(例: 赤いシャツをすべて見たいが、他にどんな色があるか知りたい)。

これは、「ファセット結果」または「ファセット ナビゲーション」と呼ばれることもあります。Elasticsearchリファレンスの例は、理由/方法を説明する上で非常に明確であるため、これをこの質問のベースとして使用しました。

概要/質問: これには、ポスト フィルターまたはグローバル アグリゲーションの両方を使用できるようです。どちらもまったく同じ機能を異なる方法で提供しているようです。私が見ていない利点や欠点があるかもしれませんか?もしそうなら、私はどれを使うべきですか?

リファレンス ガイドの例に基づいて、いくつかのドキュメントと両方のタイプのメソッドを使用したクエリを含む完全な例を以下に示します。


オプション 1: ポストフィルター

Elasticsearch リファレンスの例を参照してください

できることは、元のクエリでより多くの結果を取得することです。そのため、これらの結果を「集計」し、後で実際の結果をフィルター処理できます。

例はそれを説明する上で非常に明確です:

ただし、他の色の Gucci シャツが何枚あるかをユーザーに伝えたい場合もあります。color フィールドに用語集計を追加するだけでは、クエリが Gucci の赤いシャツのみを返すため、赤色のみが返されます。

代わりに、集計中にすべての色のシャツを含めてから、検索結果にのみ色フィルターを適用します。

これが以下のコード例でどのように見えるかを参照してください。

これに関する問題は、キャッシュを使用できないことです。これは、(5.1 ではまだ利用できません)elasticsearch ガイドで次のように警告されています。

パフォーマンスに関する考慮事項 post_filter は、検索結果と集計を区別してフィルター処理する必要がある場合にのみ使用してください。通常の検索に post_filter を使用することがあります。

これをしないでください!post_filter の性質上、クエリの後に実行されるため、フィルタリングによるパフォーマンス上の利点 (キャッシュなど) は完全に失われます。

post_filter は、集計と組み合わせてのみ使用し、差分フィルタリングが必要な場合にのみ使用してください。

ただし、別のオプションがあります。

オプション 2: グローバル集計

検索クエリの影響を受けない集計を行う方法があります。したがって、たくさん取得して集計してからフィルター処理する代わりに、フィルター処理された結果を取得するだけで、すべての集計を行います。リファレンスを見てみよう

まったく同じ結果が得られます。このためのキャッシュに関する警告は読みませんでしたが、最終的にはほぼ同じ量の作業を行う必要があるようです。それが唯一の省略かもしれません。

サブ集計が必要なため、少し複雑です ( と を同じ「レベル」にすることはできませんglobal) filter

これを使用したクエリについて私が読んだ唯一の不満は、複数のアイテムに対してこれを行う必要がある場合は、自分で繰り返す必要があるかもしれないということです。結局、ほとんどのクエリを生成できるので、私のユースケースでは自分自身を繰り返すことはそれほど問題ではなく、これを「キャッシュを使用できない」と同等の問題とは実際には考えていません。

質問

両方の機能が少なくとも重複しているか、まったく同じ機能を提供しているようです。これは私を困惑させます。それとは別に、どちらにも私が見たことのない利点があるかどうか、そしてここにベストプラクティスがあるかどうかを知りたいです?

これは主にpost-filter リファレンス ページからのものですが、グローバル フィルタークエリを追加しました。

マッピングとドキュメント

PUT /shirts
{
    "mappings": {
        "item": {
            "properties": {
                "brand": { "type": "keyword"},
                "color": { "type": "keyword"},
                "model": { "type": "keyword"}
            }
        }
    }
}

PUT /shirts/item/1?refresh
{
    "brand": "gucci",
    "color": "red",
    "model": "slim"
}

PUT /shirts/item/2?refresh
{
    "brand": "gucci",
    "color": "blue",
    "model": "slim"
}


PUT /shirts/item/3?refresh
{
    "brand": "gucci",
    "color": "red",
    "model": "normal"
}


PUT /shirts/item/4?refresh
{
    "brand": "gucci",
    "color": "blue",
    "model": "wide"
}


PUT /shirts/item/5?refresh
{
    "brand": "nike",
    "color": "blue",
    "model": "wide"
}

PUT /shirts/item/6?refresh
{
    "brand": "nike",
    "color": "red",
    "model": "wide"
}

現在、すべての赤のグッチ シャツ (アイテム 1 と 3)、これら 2 シャツのシャツの種類 (スリムとノーマル)、グッチの色 (赤と青) をリクエストしています。

最初に、ポスト フィルター: すべてのシャツを取得し、赤いグッチ シャツのモデルとグッチ シャツの色 (すべての色) を集約し、赤いグッチ シャツのポスト フィルターを使用してそれらのみを結果として表示します: (これは、可能な限り明確なポストフィルターの適用に近づけようとするためです。)

GET /shirts/_search
{
  "aggs": {
    "colors_query": {
      "filter": {
        "term": {
          "brand": "gucci"
        }
      },
      "aggs": {
        "colors": {
          "terms": {
            "field": "color"
          }
        }
      }
    },
    "color_red": {
      "filter": {
        "bool": {
          "filter": [
            {
              "term": {
                "color": "red"
              }
            },
            {
              "term": {
                "brand": "gucci"
              }
            }
          ]
        }
      },
      "aggs": {
        "models": {
          "terms": {
            "field": "model"
          }
        }
      }
    }
  },
  "post_filter": {
    "bool": {
      "filter": [
        {
          "term": {
            "color": "red"
          }
        },
        {
          "term": {
            "brand": "gucci"
          }
        }
      ]
    }
  }
}

また、すべての赤いグッチ シャツ (元のクエリ) を取得し、モデル (すべての赤いグッチ シャツ) と色 (すべてのグッチ シャツ) のグローバル集計を行うこともできます。

GET /shirts/_search
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "color": "red"   }},
        { "term": { "brand": "gucci" }}
      ]
    }
  },
  "aggregations": {
    "color_red": {
      "global": {},
      "aggs": {
        "sub_color_red": {
          "filter": {
            "bool": {
              "filter": [
                { "term": { "color": "red"   }},
                { "term": { "brand": "gucci" }}
              ]
            }
          },
          "aggs": {
            "keywords": {
              "terms": {
                "field": "model"
              }
            }
          }
        }
      }
    },
    "colors": {
      "global": {},
      "aggs": {
        "sub_colors": {
          "filter": {
            "bool": {
              "filter": [
                { "term": { "brand": "gucci" }}
              ]
            }
          },
          "aggs": {
            "keywords": {
              "terms": {
                "field": "color"
              }
            }
          }
        }
      }
    }
  }
}

両方とも同じ情報を返します。サブ集計によって追加のレベルが導入されたため、2 番目の情報のみが異なります。2 番目のクエリはもう少し複雑に見えますが、これはそれほど問題ではないと思います。実際のクエリはコードによって生成されますが、おそらくもっと複雑であり、それは優れたクエリである必要があります。

4

2 に答える 2