【问题标题】:Sorting a reverse nested back to parent aggregation将反向嵌套排序回父聚合
【发布时间】:2021-05-23 10:34:42
【问题描述】:

我目前正在通过一个多级嵌套字段聚合一个集合,并从这个集合中计算一些子聚合指标,这正在使用弹性搜索的反向嵌套功能,如 Sub-aggregate a multi-level nested composite aggregation 所述。

我目前的努力是找到一种方法来按计算的指标之一对聚合进行排序。例如,考虑到以下文档和我当前的搜索调用,我想按点击总和对所有聚合进行排序。

我尝试在back_to_parent 级别的内部aggs 中使用bucket_sort,但得到以下java 异常。

class org.elasticsearch.search.aggregations.bucket.nested.InternalReverseNested cannot be cast to class org.elasticsearch.search.aggregations.InternalMultiBucketAggregation 
(org.elasticsearch.search.aggregations.bucket.nested.InternalReverseNested and org.elasticsearch.search.aggregations.InternalMultiBucketAggregation are in unnamed module of loader 'app')
{
  id: '32ead132eq13w21',
  statistics: {
    clicks: 123,
    views: 456
  },
  categories: [{ //nested type
    name: 'color',
    tags: [{ //nested type
      slug: 'blue'
    },{
      slug: 'red'
    }]
  }]
}
GET /acounts-123321/_search
{
  size: 0,
  aggs: {
    categories_parent: {
        nested: {
          path: 'categories.tags'
        },
        aggs: {
          filtered: {
            filter: {
              term: { 'categories.tags.category': 'color' }
            },
            aggs: {
              by_slug: {
                terms: {
                  field: 'categories.tags.slug',
                  size: perPage
                },
                aggs: {
                  back_to_parent: {
                    reverse_nested: {},
                    aggs: {
                      clicks: {
                        sum: {
                          field: 'statistics.clicks'
                        }
                      },
                      custom_metric: {
                        scripted_metric: {
                          init_script: 'state.accounts = []',
                          map_script: 'state.accounts.add(new HashMap(params["_source"]))',
                          combine_script: 'double result = 0;
                            for (acc in state.accounts) {
                              result += ( acc.statistics.clicks + acc.statistics.impressions);
                            }
                            return result;',
                          reduce_script: 'double sum = 0;
                            for (state in states) {
                              sum += state;
                            }                            
                            return sum;'
                        }
                      },
                      by_tag_sort: {
                        bucket_sort: {
                          sort: [{ 'clicks.value': { order: 'desc' } }]
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }

更新:

如果了解如何通过通过无痛scripted_metric 计算的自定义指标对存储桶进行排序,也将是一件好事。我更新了上面的搜索调用,添加了一个示例custom_metric,我希望允许对其进行排序。

我发现直接使用bucket_sort 不适用于我们用于具体字段的标准排序数组。所以下面似乎没有对事情进行排序。它也不适用于排序脚本,因为[bucket_sort] only supports field based sorting

by_tag_sort: {
  bucket_sort: {
    sort: [{ 'custom_metric.value': { order: 'desc' } }]
  }
}

【问题讨论】:

    标签: elasticsearch elasticsearch-aggregation


    【解决方案1】:

    bucket_sort 期望在多桶上下文中运行,但您的 reverse_nested 聚合是单桶(不管它是多桶 terms 聚合的子节点)。

    诀窍是使用empty-ishfilters aggregation 生成多桶上下文,然后运行桶排序:

    {
      "size": 0,
      "aggs": {
        "categories_parent": {
          "nested": {
            "path": "categories.tags"
          },
          "aggs": {
            "filtered": {
              "filter": {
                "term": {
                  "categories.tags.category": "color"
                }
              },
              "aggs": {
                "by_slug": {
                  "terms": {
                    "field": "categories.tags.slug",
                    "size": 10
                  },
                  "aggs": {
                    "back_to_parent": {
                      "reverse_nested": {},
                      "aggs": {
                        "multi_bucket_emulator": {
                          "filters": {
                            "filters": {
                              "placeholder_match_all_query": {
                                "match_all": {}
                              }
                            }
                          },
                          "aggs": {
                            "clicks": {
                              "sum": {
                                "field": "statistics.clicks"
                              }
                            },
                            "by_tag_sort": {
                              "bucket_sort": {
                                "sort": [
                                  {
                                    "clicks.value": {
                                      "order": "desc"
                                    }
                                  }
                                ]
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    

    更新:按自定义脚本指标值的结果排序

    {
      "size": 0,
      "aggs": {
        "categories_parent": {
          "nested": {
            "path": "categories.tags"
          },
          "aggs": {
            "filtered": {
              "filter": {
                "term": {
                  "categories.tags.category": "color"
                }
              },
              "aggs": {
                "by_slug": {
                  "terms": {
                    "field": "categories.tags.slug",
                    "size": 10
                  },
                  "aggs": {
                    "back_to_parent": {
                      "reverse_nested": {},
                      "aggs": {
                        "multi_bucket_emulator": {
                          "filters": {
                            "filters": {
                              "placeholder_match_all_query": {
                                "match_all": {}
                              }
                            }
                          },
                          "aggs": {
                            "clicks": {
                              "sum": {
                                "field": "statistics.clicks"
                              }
                            },
                            "custom_metric": {
                              "scripted_metric": {
                                "init_script": "state.accounts = []",
                                "map_script": """state.accounts.add(params["_source"])""",
                                "combine_script": """
                                    double result = 0;
                                    for (def acc : state.accounts) {
                                      result += ( acc.statistics.clicks + acc.statistics.impressions);
                                    }
                                    return result;
                                """,
                                "reduce_script": """
                                  double sum = 0;
                                  for (def state : states) {
                                    sum += state;
                                  }                            
                                  return sum;
                                """
                              }
                            },
                            "by_tag_sort": {
                              "bucket_sort": {
                                "sort": [
                                  {
                                    "custom_metric.value": {
                                      "order": "desc"
                                    }
                                  }
                                ]
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    

    【讨论】:

    • 嘿@joe-sorocin,我发现这种排序方法在使用脚本计算聚合指标的情况下不起作用。我也尝试过使用排序脚本,但 bucket_sort 也不允许。 [bucket_sort] only supports field based sorting。有什么我可以做的解决方法吗?谢谢!
    • 您能相应地更新您的问题吗? statistics.clicks 是一个具体的字段。
    • 刚刚使用自定义指标示例对其进行了更新。如果您认为它应该有所不同或仍然缺少一些信息,请告诉我。
    • 请先重新阅读我的原始答案——bucket_sort 需要多桶上下文。但无论如何,按自定义指标排序确实是可能的——请参阅我的答案更新。我更正了您的脚本循环,因为 java 中没有 for ... in 循环...只需确保在将其放入 JS 代码时将三引号 """ 替换为反引号 ` ... `
    【解决方案2】:

    Joe - Elasticsearch 手册 - 我有一个与您的查询等效的查询(按自定义脚本指标的结果排序),我希望您对查询的响应如下所示。

    我注意到bucket_sort 指定的排序不会应用于最上面的存储桶(即by_slug.buckets),它们仍按默认的doc_count 排序进行排序。这也可以通过将custom_metric.value 排序从desc 更改为asc 来验证,这对结果的顺序没有影响。

    我对@9​​87654321@ 的理解表明,基于custom_metric 的排序应用于上一层聚合,在本例中为multi_bucket_emulator.buckets(但因为这是一个模拟器,它没有实际的存储桶来排序)。

    是否可以根据custom_metric 值对by_slug.buckets 进行排序?

    我正在使用 Elasticsearch v7.10。

    非常感谢。

    (很抱歉发布这个问题作为答案;评论太长了。)

    响应(近似值):

    {
        "aggregations": {
            "categories_parent": {
                "filtered": {
                    "by_slug": {
                        "buckets": [
                            {
                                "key": "xxxxxx",
                                "back_to_parent": {
                                    "multi_bucket_emulator": {
                                        "buckets": {
                                            "placeholder_match_all_query": {
                                                "clicks": {
                                                    "buckets": [
                                                        {
                                                            "key": 5.0,
                                                            "doc_count": 1
                                                        },
                                                        …
                                                    ]
                                                },
                                                "custom_metric": {
                                                    "value": 20.0
                                                }
                                            }
                                        }
                                    }
                                }
                            },
                            …
                        ]
                    }
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-13
      • 1970-01-01
      • 2020-09-02
      • 1970-01-01
      • 2022-07-13
      • 1970-01-01
      • 2015-12-30
      • 2018-07-14
      • 1970-01-01
      相关资源
      最近更新 更多