如何使用Elastic对嵌套对象进行子聚合? [英] How to do sub-aggregations on nested objects with Elastic?

查看:31
本文介绍了如何使用Elastic对嵌套对象进行子聚合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我具有以下架构来表示可以具有多种变体的产品(例如:T恤的尺寸):

I have the following schema to represent products that can have multiple variants (eg: sizes for a t-shirt):

{
    "mappings": {
        "properties": {
            "id": {"type": "keyword"},
            "name": {"type": "text"},
            "variants": {
                "type": "nested",
                "properties": {
                    "inventory": {"type": "long"},
                    "customizations": {"type": "object"},
                    "customizations.name": {"type": "keyword"},
                    "customizations.value": {"type": "keyword"}
                }
            }
        }
    }
}

然后我可以使用它插入如下所示的产品数据:

With which I can then insert product data that looks like:

{
    "id": "prod-1",
    "name": "Shirt Design 1",
    "variants": [
        {"inventory": 78, "customizations": [{"name": "size", "value": "L"}, {"name": "color", "value": "blue"}]},
        {"inventory": 78, "customizations": [{"name": "size", "value": "M"}, {"name": "color", "value": "blue"}]},
        {"inventory": 89, "customizations": [{"name": "size", "value": "S"}, {"name": "color", "value": "blue"}]}
    ]
}
{
    "id": "prod-2",
    "name": "Shirt Design 2",
    "variants": [
        {"inventory": 78, "customizations": [{"name": "size", "value": "L"}, {"name": "color", "value": "green"}]},
        {"inventory": 78, "customizations": [{"name": "size", "value": "M"}, {"name": "color", "value": "green"}]}
    ]
}

在过滤/查询此索引时,我希望能够根据构成产品的自定义来显示构面.这些自定义设置是用户提交的,因此不在我的控制范围内,但其想法是能够显示以下过滤器:

When filtering / querying this index, I want to be able to show facets based on the customizations that make up the product. Those customizations are user submitted and therefore not in my control, but the idea is to be able to display filters like:

☐ Size:
    - S (1)
    - M (2)
    - L (2)
☐ Color:
    - blue (1)
    - green (1)

现在,我可以使用以下查询按自定义名称正确存储分区:

For now I can correctly bucket by customization name with the following query:

{
    "size": 0,
    "aggs": {
        "skus": {
            "nested": {
                "path": "variants"
            },
            "aggs": {
                "customization_names": {
                    "terms": {
                        "field": "variants.customizations.name"
                    }
                }
            }
        }
    }
}

哪个给了我以下存储桶:

Which gives me the following buckets:

"buckets": [
        {
            "doc_count": 2,
            "key": "color"
        },
        {
            "doc_count": 2,
            "key": "size"
        }
    ],

尝试进行子聚合以获取下面的实际自定义列表是我遇到的困难.我尝试过:

Trying to do a sub-aggregation to get the list of actual customizations underneath is where I'm stuck. I've tried:

{
    "size": 0,
    "aggs": {
        "skus": {
            "nested": {
                "path": "variants"
            },
            "aggs": {
                "customization_names": {
                    "terms": {
                        "field": "variants.customizations.name"
                    },
                    "aggs": {
                        "sub": {
                            "reverse_nested": {},
                            "aggs": {
                                "customization_values": {
                                    "terms": {
                                        "field": "variants.customizations.value"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

不返回任何子桶:

buckets": [
                    {
                        "doc_count": 4,
                        "key": "color",
                        "sub": {
                            "doc_count": 2,
                            "customization_values": {
                                "buckets": [],
                                "doc_count_error_upper_bound": 0,
                                "sum_other_doc_count": 0
                            }
                        }
                    },
                    {
                        "doc_count": 4,
                        "key": "size",
                        "sub": {
                            "doc_count": 2,
                            "customization_values": {
                                "buckets": [],
                                "doc_count_error_upper_bound": 0,
                                "sum_other_doc_count": 0
                            }
                        }
                    }
                ],

如果我不使用 reverse_nested ,那么我会在其中获得所有可能的值,而不是空的子存储桶,因此我将获得 red and blue 作为例如 size 子桶.

If I don't use reverse_nested, instead of empty sub-buckets, I get every possible value in there, so I get red and blue as part of the size sub-bucket for example.

最初,我将自定义作为键=>的映射.值,但也无法使其正常工作.但是,定制"的格式不适合于定制".可以在此处进行自定义.

I initially had the customizations as a map of key => value, but couldn't make it work that way either. However, the format for "customizations" is somewhat customizable here.

到目前为止,我发现解决此问题的唯一方法是在自定义项中添加一个字段,该字段是名称+值的json字符串表示形式.

The only way I have found so far to solve this is to add a field to customizations which is a json string representation of name + value.

// mapping:
"customizations.facet_code": {"type": "keyword"}
// data:
"customizations": [{"name": "size", "value": "M", "facet_code": "{name:size,value:M}"],

然后,我可以根据 facet_code 正确地进行存储,并且我的应用程序可以反序列化它以再次将事物重新组合在一起.我希望能弄清楚如何正确"地完成此操作.如果可能的话.

I can then properly bucket based on facet_code and my app can deserialize it to re-group things together again. I would prefer if I could figure out how to do it "properly" if at all possible.

推荐答案

正确"的方法是将自定义设置为嵌套类型,而不是 object .就是说:

The 'proper' way to do this would be to make the customizations of type nested too, instead of an object. That is to say:

{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "name": {
        "type": "text"
      },
      "variants": {
        "type": "nested",
        "properties": {
          "inventory": {
            "type": "long"
          },
          "customizations": {
            "type": "nested",       <-- This
            "properties": {
              "name": {
                "type": "keyword"
              },
              "value": {
                "type": "keyword"
              }
            }
          }
        }
      }
    }
  }
}

查询将是

{
  "size": 0,
  "aggs": {
    "skus": {
      "nested": {
        "path": "variants.customizations"
      },
      "aggs": {
        "customization_names": {
          "terms": {
            "field": "variants.customizations.name"
          },
          "aggs": {
            "customization_values": {
              "terms": {
                "field": "variants.customizations.value"
              }
            }
          }
        }
      }
    }
  }
}

提供所有必需的方面:

{
  ...
  "aggregations":{
    "skus":{
      "doc_count":10,
      "customization_names":{
        "doc_count_error_upper_bound":0,
        "sum_other_doc_count":0,
        "buckets":[
          {
            "key":"color",
            "doc_count":5,
            "customization_values":{
              "doc_count_error_upper_bound":0,
              "sum_other_doc_count":0,
              "buckets":[
                {
                  "key":"blue",
                  "doc_count":3
                },
                {
                  "key":"green",
                  "doc_count":2
                }
              ]
            }
          },
          {
            "key":"size",
            "doc_count":5,
            "customization_values":{
              "doc_count_error_upper_bound":0,
              "sum_other_doc_count":0,
              "buckets":[
                {
                  "key":"L",
                  "doc_count":2
                },
                {
                  "key":"M",
                  "doc_count":2
                },
                {
                  "key":"S",
                  "doc_count":1
                }
              ]
            }
          }
        ]
      }
    }
  }
}

这篇关于如何使用Elastic对嵌套对象进行子聚合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆