#elasticsearch
#elasticsearch
Вопрос:
Я новичок в ES, и я не знаю, как разрешить этот простой сценарий:
Значение типа данных 1 A 1 A 1 B 2 B 3 A 3 A 4 A 4 B
Мне нужно знать, сколько типов данных имеют только значение ‘A’, сколько имеют только значение ‘B’ и сколько имеют оба. Ожидаемый результат для этого примера будет:
Only A = 1 (dataType 3)
Only B = 1 (dataType 2)
Both = 2 (dataTypes 1 and 4)
Не могли бы вы мне помочь? Спасибо.
ChintanShah25 Привет, большое спасибо за ваш быстрый ответ. Я попробовал код, который вы разработали, но, похоже, не работает должным образом:
"Aggregations": {
"Datatypes": {
"Value": {
"Both": 0,
"Onlya": 1,
"OnlyB": 1
}
}
}
Если я удалю "reduce_script", я смогу отлаживать, получая:
"Агрегации": { "Типы данных": { "Значение": [ [ [ "1" ], [] ], [ [] [] ], [ [ "1" ], [ "1", "2" ] ], [ [ "4" ], [] ], [ [ "3" ], [ "4" ] ] ] } }
Типы данных сгруппированы правильно, но кажется, что они разделены на разные сегменты или сегменты, и последний шаг "reduce_script" завершается неудачей.
Документация "Scripted Metric" оставляет желать лучшего, и, хотя я тестирую, желаемых результатов не получается.
Приветствую.
Ответ №1:
Я думаю, это сложно, это может быть сделано с помощью скриптовой агрегации метрик. Я создал тестовый индекс и вставил предоставленные вами образцы данных. Следующий запрос дает желаемые результаты
{
"query": {
"match_all": {}
},
"aggs": {
"Datatypes": {
"scripted_metric": {
"init_script": "_agg['onlya'] = [];_agg['onlyb'] = [];",
"map_script": "if (doc['value'].value == "A")
{ _agg.onlya.add(doc['datatype'].value) };
if (doc['value'].value == "B")
{ _agg.onlyb.add(doc['datatype'].value) };",
"combine_script": "onlya = _agg['onlya'].unique();
onlyb = _agg['onlyb'].unique();
return[onlya, onlyb]",
"reduce_script": "both_bucket=[];a_bucket=[];b_bucket=[];
for(a in _aggs)
{both_bucket=a[0].intersect(a[1]);
a_bucket=a[0]-a[1];
b_bucket=a[1]-a[0]};
return ['Both' : both_bucket.size(),
'OnlyA' : a_bucket.size(),
'OnlyB' : b_bucket.size()];"
}
}
},
"size": 0
}
Это результат, который я получаю
"aggregations": {
"Datatypes": {
"value": {
"Both": 2,
"OnlyA": 1,
"OnlyB": 1
}
}
}
Для этого вам нужно будет включить динамические сценарии или поместить эти сценарии в папку scripts.
Во время init_script я объявляю две переменные, которые будут содержать значение типа данных.
map_script просматривает каждый документ и добавляет тип данных в onlya, если значение равно "A" или onlyb. Вы можете заменить второе if на else, если вы уверены, что у вас будет либо A, либо B
combine_script преобразует список в уникальные значения, так [1,1,3,3,4]
что становится [1,3,4]
reduce_script получает результаты из всех сегментов. Пересечение даст вам корзину со значением типа данных, а вычитание даст вам только часть. size()
дает вам длину списка. Удалите метод size, чтобы узнать, какие значения типа данных совпадают.
Пожалуйста, ознакомьтесь с документацией, чтобы узнать больше о том, как работают все эти различные этапы агрегирования
Ответ №2:
В конце концов я заставил его работать так, как я хочу. Большое вам спасибо за вашу помощь.
"aggs": {
"Datatypes": {
"scripted_metric": {
"init_script": "_agg['onlya'] = [];_agg['onlyb'] = [];",
"map_script": "valueAdd=doc['datatype'].value; if (doc['value'].value == "a") { _agg['onlya'].add(valueAdd) }; if (doc['value'].value == "b") { _agg['onlyb'].add(valueAdd) };",
"combine_script": "onlya = _agg['onlya'].unique(); onlyb = _agg['onlyb'].unique(); return[onlya, onlyb]",
"reduce_script": "a_bucket=[];b_bucket=[];for(a in _aggs){ a_bucket =a[0]; b_bucket =a[1];}; return ['Both' : a_bucket.intersect(b_bucket).size(), 'OnlyA' : (a_bucket-b_bucket).size(), 'OnlyB' : (b_bucket-a_bucket).size()];"
}
}
}