如何使用Elastic对嵌套对象进行子聚合? [英] How to do sub-aggregations on nested objects with 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屋!