Я хочу найти общие подсчеты документов по основным авторам и основным соавторам, которые являются полями внутри поля библиографических данных источника в индексе.
Что я сейчас делаю:
1. Расчет агрегации по 10 ведущим авторам (A, B, C, D...).
2.Расчет агрегации по 10 ведущим соавторам (X,Y,Z,....).
3. Расчет количества документов пересечения, таких как количество общих документов между этими парами:
[(А,Х), (В,У)....]. <----- РЕЗУЛЬТАТ
Я попробовал агрегацию подсегментов, но это дало мне: [A:(10 лучших, соответствующих A), B:(10 лучших, соответствующих B).....].
спасибо, не могли бы вы объяснить мне это. «Еще один вариант — просто получить 10 лучших по обоим полям, а также простой запрос agg»
хорошо, позвольте мне включить это в ответ, чтобы его было легче читать и чтобы было достаточно символов для заполнения
Хорошо, поэтому из комментариев выше продолжайте в качестве ответа, чтобы его было легче читать и не было ограничений на количество символов.
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
}
}
}
}
но на самом деле это не пересечение топ-10 авторов и топ-10 соавторов. это пересечение всего, а затем попадание в топ-10.
Третий вариант — написать Агрегирование показателей по сценарию. Не было времени тратить на алгоритмическую сторону вещей (она должна быть оптимизирована), но она может выглядеть как эта. Наверняка навыки java вам пригодятся. Также убедитесь, что вы понимаете все этапы выполнения Scripted Metric Aggregation и проблемы с производительностью, которые могут возникнуть при его использовании.
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()). См. другой ответ по похожей проблеме
Я не думаю, что вы можете использовать агрегацию конвейера для достижения этого. Я думаю, на стороне клиента не так много обработки. всего 20 записей (10 для авторов и 10 для соавторов), и это будет простой совокупный запрос. Другим вариантом было бы просто получить 10 лучших по обоим полям, а также простой запрос agg. Но если вам действительно нужно пересечение обеих топ-10 на стороне ES, используйте Агрегирование показателей по сценарию. можно заложить свою логику в код