web-dev-qa-db-ja.com

Elasticsearch-一般的なファセット構造-フィルターと組み合わせた集計の計算

私たちの新しいプロジェクトでは、この記事に触発されました http://project-a.github.io/on-site-search-design-patterns-for-e-commerce/#generic-faceted- search 「ファセット」構造を実行するため。また、記事で説明されている範囲で機能するようにしていますが、ファセットを選択するときに機能させる際に問題が発生しました。誰かが何か試してみるヒントを教えてくれることを願っています。そのため、すべての集計を個別の集計計算にやり直す必要はありません。

問題は基本的に、単一の集計を使用してすべての「ファセット」を一度に計算していることですが、フィルターを追加すると(fx。ブランド名をチェック)、集計を返すときに他のすべてのブランドが「削除」されます。私が基本的に望んでいるのは、他のファセットを計算するときにそのブランドをフィルターとして使用する必要があることですが、ブランドの集計を計算するときは使用しないでください。これは、たとえば、ユーザーが複数のブランドを選択できるようにするために必要です。

https://www.contorion.de/search/Metabo_Fein/ou1-ou2?q=Winkelschleifer&c=bovy (上記の記事で説明されているサイト)を見て、「Metabo」を選択しました。 」と「Fein」メーカー(Hersteller)、およびHerstellerメニューを展開すると、選択したメーカーだけでなく、すべてのメーカーが表示されます。だから私はそれがどういうわけか可能であることを知っています、そして私はそこにいる誰かが集計/フィルターを書く方法についてのヒントを持っていることを願っています、それで私は「正しいeコマースファセットの振る舞い」を得ます。

ESの製品では、次の構造になっています:(元の記事と同じですが、名前は「C#化」されています)

"attributeStrings": [
    {
        "facetName": "Property",
        "facetValue": "Organic"
    },
    {
        "facetName": "Property",
        "facetValue": "Without parfume"
    },
    {
        "facetName": "Brand",
        "facetValue": "Adidas"
    }
]

したがって、上記の製品には2つの属性/ファセットグループがあります。2つの値を持つプロパティ(オーガニック、香水なし)と1つの値を持つブランド(アディダス)です。フィルタを使用せずに、次のクエリから集計を計算します。

  "aggs": {
    "agg_attr_strings_filter": {
      "filter": {},
      "aggs": {
        "agg_attr_strings": {
          "nested": {
            "path": "attributeStrings"
          },
          "aggs": {
            "attr_name": {
              "terms": {
                "field": "attributeStrings.facetName"
              },
              "aggs": {
                "attr_value": {
                  "terms": {
                    "field": "attributeStrings.facetValue",
                    "size": 1000,
                    "order": [
                      {
                        "_term": "asc"
                      }
                    ]
   } } } } } } } }

ここで、プロパティ「Organic」とブランド「Adidas」を選択すると、同じ集計が作成されますが、これら2つの制約を適用するためのフィルターが使用されます(これは、ある種の問題でした...)。

  "aggs": {
    "agg_attr_strings_filter": {
      "filter": {
        "bool": {
          "filter": [
            {
              "nested": {
                "query": {
                  "bool": {
                    "filter": [
                      {
                        "term": {
                          "attributeStrings.facetName": {
                            "value": "Property"
                          }
                        }
                      },
                      {
                        "terms": {
                          "attributeStrings.facetValue": [
                            "Organic"
                          ]
                        }
                      }
                    ]
                  }
                },
                "path": "attributeStrings"
              }
            },
            {
              "nested": {
                "query": {
                  "bool": {
                    "filter": [
                      {
                        "term": {
                          "attributeStrings.facetName": {
                            "value": "Brand"
                          }
                        }
                      },
                      {
                        "terms": {
                          "attributeStrings.facetValue": [
                            "Adidas"
                          ]
                        }
                      }
                    ]
                  }
                },
                "path": "attributeStrings"
              }
            }
          ]
        }
      },
      "aggs": {
        "agg_attr_strings": {
          "nested": {
            "path": "attributeStrings"
          },
          "aggs": {
            "attr_name": {
              "terms": {
                "field": "attributeStrings.facetName",
              },
              "aggs": {
                "attr_value": {
                  "terms": {
                    "field": "attributeStrings.facetValue",
                    "size": 1000,
                    "order": [
                      {
                        "_term": "asc"
                      }
                    ]
   } } } } } } } }

このモデルで私が前向きに見ることができる唯一の方法は、選択した各ファセットの集計を計算し、何らかの方法で結果をマージすることです。しかし、それは非常に複雑で、記事で説明されているモデルを持つという点を打ち負かすようなものです。したがって、よりクリーンな解決策があり、誰かが試してみるヒントを与えることができるといいのですが。

17
Reonekot

このモデルで私が前向きに見ることができる唯一の方法は、選択した各ファセットの集計を計算し、何らかの方法で結果をマージすることです。

これはまさに正しいです。 1つのファセット(例:brand)が選択されている場合、複数選択のために他のブランドも取得する場合は、グローバルブランドフィルターを使用できません。あなたができることは、選択されたファセットにすべてのotherフィルターを適用し、選択されていないファセットにallfiltersを適用することです。結果として、nの選択されたフィルターに対してn+1の個別の集計が作成されます。最初の集計はすべてのファセット用で、残りは選択されたファセット用です。

あなたの場合、クエリは次のようになります。

{
  "aggs": {
    "agg_attr_strings_filter": {
      "filter": {
        "bool": {
          "filter": [
            {
              "nested": {
                "query": {
                  "bool": {
                    "filter": [
                      {
                        "term": {
                          "attributeStrings.facetName": {
                            "value": "Property"
                          }
                        }
                      },
                      {
                        "terms": {
                          "attributeStrings.facetValue": [
                            "Organic"
                          ]
                        }
                      }
                    ]
                  }
                },
                "path": "attributeStrings"
              }
            },
            {
              "nested": {
                "query": {
                  "bool": {
                    "filter": [
                      {
                        "term": {
                          "attributeStrings.facetName": {
                            "value": "Brand"
                          }
                        }
                      },
                      {
                        "terms": {
                          "attributeStrings.facetValue": [
                            "Adidas"
                          ]
                        }
                      }
                    ]
                  }
                },
                "path": "attributeStrings"
              }
            }
          ]
        }
      },
      "aggs": {
        "agg_attr_strings": {
          "nested": {
            "path": "attributeStrings"
          },
          "aggs": {
            "attr_name": {
              "terms": {
                "field": "attributeStrings.facetName"
              },
              "aggs": {
                "attr_value": {
                  "terms": {
                    "field": "attributeStrings.facetValue",
                    "size": 1000,
                    "order": [
                      {
                        "_term": "asc"
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "special_agg_property": {
      "filter": {
        "nested": {
          "query": {
            "bool": {
              "filter": [
                {
                  "term": {
                    "attributeStrings.facetName": {
                      "value": "Brand"
                    }
                  }
                },
                {
                  "terms": {
                    "attributeStrings.facetValue": [
                      "Adidas"
                    ]
                  }
                }
              ]
            }
          },
          "path": "attributeStrings"
        }
      },
      "aggs": {
        "special_agg_property": {
          "nested": {
            "path": "attributeStrings"
          },
          "aggs": {
            "agg_filtered_special": {
              "filter": {
                "query": {
                  "match": {
                    "attributeStrings.facetName": "Property"
                  }
                }
              },
              "aggs": {
                "facet_value": {
                  "terms": {
                    "size": 1000,
                    "field": "attributeStrings.facetValue"
                  }
                }
              }
            }
          }
        }
      }
    },
    "special_agg_brand": {
      "filter": {
        "nested": {
          "query": {
            "bool": {
              "filter": [
                {
                  "term": {
                    "attributeStrings.facetName": {
                      "value": "Property"
                    }
                  }
                },
                {
                  "terms": {
                    "attributeStrings.facetValue": [
                      "Organic"
                    ]
                  }
                }
              ]
            }
          },
          "path": "attributeStrings"
        }
      },
      "aggs": {
        "special_agg_brand": {
          "nested": {
            "path": "attributeStrings"
          },
          "aggs": {
            "agg_filtered_special": {
              "filter": {
                "query": {
                  "match": {
                    "attributeStrings.facetName": "Brand"
                  }
                }
              },
              "aggs": {
                "facet_value": {
                  "terms": {
                    "size": 1000,
                    "field": "attributeStrings.facetValue"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

このクエリは非常に大きくて怖いように見えますが、そのようなクエリの生成は数十行のコードで実行できます。クエリ結果を解析するときは、最初に一般的な集計(すべてのフィルターを使用するもの)を解析し、その後に特別なファセット集計を解析する必要があります。上の例から、最初にagg_attr_strings_filterの結果を解析しますが、これらの結果にはBrandおよびspecial_agg_propertyおよびspecial_agg_brandからの集計値で上書きする必要があるプロパティまた、Elasticsearchは個別のフィルター句をキャッシュするのに適しているため、このクエリは効率的です。クエリのさまざまな部分のフィルタは安価である必要があります。

しかし、それは非常に複雑で、記事で説明されているモデルを持つという点を打ち負かすようなものです。したがって、よりクリーンな解決策があり、誰かが試してみるヒントを与えることができるといいのですが。

異なるファセットに異なるフィルターを適用する必要があり、同時に異なるクエリフィルターを使用する必要があるという事実を回避する方法は実際にはありません。 「正しいeコマースファセットの動作」をサポートする必要がある場合は、複雑なクエリが発生します:)

免責事項:私は言及された記事の共著者です。

20
hakaa

この問題は、集計のPropertyOrganicinsideにフィルターを追加しているという事実に起因しています。選択するファセットが多いほど、取得する条件を制限することになります。その記事では、彼らが使用するfilterは実際には post_filter であり、両方の名前は最近まで許可されていましたが、filter削除されました それがあいまいさを引き起こしていたからです。

必要なのは、そのフィルターを集計の外側のpost_filterセクションに移動することです。これにより、選択されたファセットによって結果が正しくフィルターで除外されますが、すべてのファセットはドキュメントセット全体で正しく計算されます。 。

{
  "post_filter": {
    "bool": {
      "filter": [
        {
          "nested": {
            "query": {
              "bool": {
                "filter": [
                  {
                    "term": {
                      "attributeStrings.facetName": {
                        "value": "Property"
                      }
                    }
                  },
                  {
                    "terms": {
                      "attributeStrings.facetValue": [
                        "Organic"
                      ]
                    }
                  }
                ]
              }
            },
            "path": "attributeStrings"
          }
        },
        {
          "nested": {
            "query": {
              "bool": {
                "filter": [
                  {
                    "term": {
                      "attributeStrings.facetName": {
                        "value": "Brand"
                      }
                    }
                  },
                  {
                    "terms": {
                      "attributeStrings.facetValue": [
                        "Adidas"
                      ]
                    }
                  }
                ]
              }
            },
            "path": "attributeStrings"
          }
        }
      ]
    }
  },
  "aggs": {
    "agg_attr_strings_full": {
      "nested": {
        "path": "attributeStrings"
      },
      "aggs": {
        "attr_name": {
          "terms": {
            "field": "attributeStrings.facetName"
          },
          "aggs": {
            "attr_value": {
              "terms": {
                "field": "attributeStrings.facetValue",
                "size": 1000,
                "order": [
                  {
                    "_term": "asc"
                  }
                ]
              }
            }
          }
        }
      }
    },
    "agg_attr_strings_filtered": {
      "filter": {
        "bool": {
          "filter": [
            {
              "nested": {
                "path": "attributeStrings",
                "query": {
                  "bool": {
                    "filter": [
                      {
                        "term": {
                          "attributeStrings.facetName": {
                            "value": "Property"
                          }
                        }
                      },
                      {
                        "terms": {
                          "attributeStrings.facetValue": [
                            "Organic"
                          ]
                        }
                      }
                    ]
                  }
                }
              }
            },
            {
              "nested": {
                "path": "attributeStrings",
                "query": {
                  "bool": {
                    "filter": [
                      {
                        "term": {
                          "attributeStrings.facetName": {
                            "value": "Brand"
                          }
                        }
                      },
                      {
                        "terms": {
                          "attributeStrings.facetValue": [
                            "Adidas"
                          ]
                        }
                      }
                    ]
                  }
                }
              }
            }
          ]
        }
      },
      "aggs": {
        "nested": {
          "path": "attributeStrings"
        },
        "aggs": {
          "attr_name": {
            "terms": {
              "field": "attributeStrings.facetName"
            },
            "aggs": {
              "attr_value": {
                "terms": {
                  "field": "attributeStrings.facetValue",
                  "size": 1000,
                  "order": [
                    {
                      "_term": "asc"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}
6
Val

私はあなたたちがここで話していることを達成しようとしています。私もこのスレッドで言及されている記事をフォローしていますが、3週間ほど試した後、フィルターが正しい結果を返す理由がわからないようですが、フィルターを集計に入れると、集計がすべて間違っています。私は例を使って全体を詳しく説明しました この質問で 、誰かが私を立ち往生させないための指針を持っているのだろうかと思います。どうもありがとう!

0