我想查找顶级作者和顶级合著者的通用文档计数,它们是索引中源的书目数据字段内的字段。
我当前正在做的是:
1。计算排名前10位的作者的汇总(A,B,C,D .....)。
2。计算排名前10位的合著者(X,Y,Z,...)的汇总。
3。计算相交点的文档计数,例如这些对之间的通用文档计数:
[(A,X),(B,Y)....]。 <-----结果
我尝试了子存储桶聚合,但是它给了我: [A :(与A对应的前10位,B :(与B对应的前10位).....]。
答案 0 :(得分:1)
好,因此,从上面的评论继续作为答案,使其更易于阅读且不受字符限制。
评论
我认为您不能使用管道聚合来实现它。
我想在客户端处理的内容并不多。仅20条记录(作者10条,合著者10条),这将是简单的汇总查询。
另一种选择是在两个字段中都获得前十名,并且还可以进行简单的agg查询。
但是,如果您真的需要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名合著者的交集。这是所有要素的交集,然后获得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