【问题标题】:Elasticsearch Common of two AggregationsElasticsearch 两种聚合的共同点
【发布时间】:2019-12-01 20:08:33
【问题描述】:

我想查找顶级作者和顶级共同作者的聚合的常见文档计数,它们是索引中源的 biblio 数据字段内的字段。

我目前正在做的是:

1.计算前 10 位作者的聚合。(A、B、C、D .....)。

2.计算前 10 位共同作者(X、Y、Z、....)的聚合。

3.计算交叉点的文档计数,例如这些对之间的公共文档计数:

[(A,X), (B,Y)....]。

我尝试了子桶聚合,但它给了我: [A:(前10名对应A),B:(前10名对应B).....].

【问题讨论】:

  • 我不认为你可以使用管道聚合来实现它。我想在客户端处理的并不多。只有 20 条记录(作者 10 条,共同作者 10 条),这将是简单的聚合查询。另一种选择是在两个字段中都获得前 10 名以及简单的聚合查询。但如果你真的需要 ES 端两个 top10 的交集,请使用Scripted Metric Aggregation。你可以把你的逻辑放在代码中
  • 谢谢,你能告诉我清楚吗。 “另一种选择是在两个字段中都获得前 10 名以及简单的聚合查询”
  • 好的,让我把它放到一个答案中,这样更容易阅读并且有足够的字符可以填写

标签: elasticsearch aggregation elasticsearch-aggregation elasticsearch-py


【解决方案1】:

好的,所以从上面的 cmets 继续作为答案,使其更易于阅读并且没有字符限制。

评论

我不认为你可以使用管道聚合来实现它。

我猜在客户端处理的并不多。只有 20 条记录(作者 10 条,共同作者 10 条),这将是简单的聚合查询。

另一种选择是在两个字段中都获得前 10 名以及简单的聚合查询。

但是如果你真的需要 ES 端两个 top10 的交集,请使用Scripted Metric Aggregation。你可以把你的逻辑放在代码中

第一个选项很简单:

GET index_name/_search
{
  "size": 0, 
  "aggs": {
    "firstname_dupes": {
      "terms": {
        "field": "authorFullName.keyword",
        "size": 10
      }
    },
    "lastname_dupes": {
      "terms": {
        "field": "coauthorFullName.keyword",
        "size": 10
      }
    }
  }
}

然后在客户端对结果进行交集。

第二看起来像:

GET index_name/_search
{
  "size": 0, 
  "aggs": {
    "name_dupes": {
      "terms": {
        "script": {
          "source": "return [doc['authorFullName.keyword'].value,doc['coauthorFullName.keyword'].value]"
        }
        , "size": 10
      }
    }
  }
}

但这并不是前 10 位作者和前 10 位合著者的真正交集。这是所有的交集,然后进入前10。

第三个选项是写Scripted Metric Aggregation。没有时间花在算法方面(应该优化),但它可能看起来像这个。当然,java技能会帮助你。还要确保您了解脚本化指标聚合执行的所有阶段以及使用它时可能遇到的性能问题。

GET index_name/_search
{
  "size": 0, 
    "query" : {
        "match_all" : {}
    },
    "aggs": {
        "profit": {
            "scripted_metric": {
                "init_script" : "state.fnames = [:];state.lnames = [:];", 
                "map_script" :
                """
                def key = doc['authorFullName.keyword'];
                def value = '';
                if (key != null && key.value != null) {
                  value = state.fnames[key.value];
                  if(value==null) value = 0;
                  state.fnames[key.value] = value+1
                }
                key = doc['coauthorFullName.keyword'];
                if (key != null && key.value != null) {
                  value = state.lnames[key.value];
                  if(value==null) value = 0;
                  state.lnames[key.value] = value+1
                }
                """,
                "combine_script" : "return state",
                "reduce_script" : 
                """
                def intersection = [];
                def f10_global = new HashSet();
                def l10_global = new HashSet();
                for (state in states) {
                  def f10_local = state.fnames.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).limit(10).map(e->e.getKey()).collect(Collectors.toList());
                  def l10_local = state.lnames.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).limit(10).map(e->e.getKey()).collect(Collectors.toList());
                  for(name in f10_local){f10_global.add(name);}
                  for(name in l10_local){l10_global.add(name);}
                }

                for(name in f10_global){
                  if(l10_global.contains(name)) intersection.add(name);
                }
                return intersection;
                """
            }
        }
    }
}

请注意,这里的查询假设您在这些属性上有 keyword。如果不只是根据您的情况调整它们。

更新

PS,刚刚注意到您提到您需要通用计数,而不是通用名称。不知道是什么情况,但不要使用map(e->e.getKey()),而是使用map(e->e.getValue().toString())。类似问题见the other answer

【讨论】:

    猜你喜欢
    • 2013-09-21
    • 2016-11-23
    • 2016-11-06
    • 2017-01-06
    • 1970-01-01
    • 2017-09-24
    • 1970-01-01
    • 1970-01-01
    • 2014-11-18
    相关资源
    最近更新 更多