我想查找顶级作者和顶级合著者的汇总汇总文档数,它们是索引中源的书目数据字段内的字段。
我目前正在做的是:
1.计算排名前10位的作者的汇总(A,B,C,D .....)。
2.计算排名前十位的合著者(X,Y,Z,...)的汇总。
3.计算交叉对的文档数,例如这些对之间的通用文档数:
[(A,X),(B,Y)....]。 <-----结果
我尝试了子桶聚合,但是它给了我:
[A :(前10个对应于A),B :(前10个对应于B)...]。
最佳答案
好的,因此从上面的评论继续作为答案,使它更易于阅读且不受字符限制。
Comment
I don't think you can use pipeline aggregation to achieve it.
It's not a lot to process on client side i guess. only 20 records (10 for authors and 10 for co-authors) and it would be simple aggregate query.
Another option would be to just get top 10 across both fields and also simple agg query.
But if you really need intersection of both top10s on ES side go with Scripted Metric Aggregation. you can lay your logic in the code
第一个选项很简单:
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
}
}
}
}
但这并不是十大作者和十大合著者的交集。这是所有要素的交叉点,然后再进入top10。
第三个选项是编写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
关于elasticsearch - 两个聚合的Elasticsearch共同点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57169903/