Примеры преобразований с Painless
Эти примеры демонстрируют, как использовать Painless в преобразованиях. Подробнее о языке сценариев Painless можно узнать в руководстве по Painless.
- Получение лучших совпадений с помощью агрегации скриптовых метрик
- Получение временных характеристик с помощью агрегаций
- Получение длительности с помощью скрипта корзины
- Подсчёт HTTP-ответов с помощью агрегации скриптовых метрик
- Сравнение индексов с помощью агрегаций скриптовых метрик
- Получение деталей веб-сессии с помощью агрегации скриптовых метрик
- Хотя контекст следующих примеров — преобразования, скрипты Painless в фрагментах кода ниже также могут использоваться в других агрегациях поиска Elasticsearch.
- Все следующие примеры используют скрипты; преобразования не могут выводить сопоставления выходных полей, когда поля создаются скриптом. Преобразования не создают никаких сопоставлений в целевом индексе для этих полей, что означает, что они будут динамически сопоставлены. Создайте целевой индекс перед запуском преобразования, если вы хотите явные сопоставления.
Получение лучших совпадений с помощью агрегации скриптовых метрик
Этот фрагмент показывает, как найти последний документ, другими словами, документ с самым последним временным отметкой. С технической точки зрения, это помогает достичь функции Top hits с помощью агрегации скриптовых метрик в преобразовании, которая предоставляет метрический вывод.
"aggregations": {
"latest_doc": {
"scripted_metric": {
"init_script": "state.timestamp_latest = 0L; state.last_doc = ''",
"map_script": """
def current_date = doc['@timestamp'].getValue().toInstant().toEpochMilli();
if (current_date > state.timestamp_latest)
{state.timestamp_latest = current_date;
state.last_doc = new HashMap(params['_source']);}
""",
"combine_script": "return state",
"reduce_script": """
def last_doc = '';
def timestamp_latest = 0L;
for (s in states) {if (s.timestamp_latest > (timestamp_latest))
{timestamp_latest = s.timestamp_latest; last_doc = s.last_doc;}}
return last_doc
"""
}
}
} | Объект | |
| Объект | |
| Объект | |
| Объект |
Подробное объяснение соответствующих скриптов можно найти в разделе Область действия скриптов.
Вы можете получить последнее значение аналогичным образом:
"aggregations": {
"latest_value": {
"scripted_metric": {
"init_script": "state.timestamp_latest = 0L; state.last_value = ''",
"map_script": """
def current_date = doc['@timestamp'].getValue().toInstant().toEpochMilli();
if (current_date > state.timestamp_latest)
{state.timestamp_latest = current_date;
state.last_value = params['_source']['value'];}
""",
"combine_script": "return state",
"reduce_script": """
def last_value = '';
def timestamp_latest = 0L;
for (s in states) {if (s.timestamp_latest > (timestamp_latest))
{timestamp_latest = s.timestamp_latest; last_value = s.last_value;}}
return last_value
"""
}
}
} Получение временных характеристик с помощью агрегаций
Этот фрагмент показывает, как извлечь временные характеристики с помощью Painless в преобразовании. Фрагмент использует индекс, где @timestamp определён как поле типа date.
"aggregations": {
"avg_hour_of_day": {
"avg":{
"script": {
"source": """
ZonedDateTime date = doc['@timestamp'].value;
return date.getHour();
"""
}
}
},
"avg_month_of_year": {
"avg":{
"script": {
"source": """
ZonedDateTime date = doc['@timestamp'].value;
return date.getMonthValue();
"""
}
}
},
...
} | Название агрегации. | |
| Содержит скрипт Painless, возвращающий час дня. | |
| Устанавливает | |
| Возвращает значение часа из | |
| Название агрегации. | |
| Содержит скрипт Painless, возвращающий месяц года. | |
| Устанавливает | |
| Возвращает значение месяца из |
Получение длительности с помощью скрипта корзины
В этом примере показано, как получить длительность сессии по IP-адресу клиента из журнала данных с помощью bucket script. В примере используется набор данных веб-журналов Kibana.
PUT _transform/data_log
{
"source": {
"index": "kibana_sample_data_logs"
},
"dest": {
"index": "data-logs-by-client"
},
"pivot": {
"group_by": {
"machine.os": {"terms": {"field": "machine.os.keyword"}},
"machine.ip": {"terms": {"field": "clientip"}}
},
"aggregations": {
"time_frame.lte": {
"max": {
"field": "timestamp"
}
},
"time_frame.gte": {
"min": {
"field": "timestamp"
}
},
"time_length": {
"bucket_script": {
"buckets_path": {
"min": "time_frame.gte.value",
"max": "time_frame.lte.value"
},
"script": "params.max - params.min"
}
}
}
}
} | Для определения длительности сессий используется скрипт корзины. | |
| Путь к корзине — это карта переменных скрипта и соответствующих путей к корзинам, которые нужно использовать для переменной. В данном случае, | |
| Наконец, скрипт вычитает начальную дату сессии из конечной даты, что приводит к длительности сессии. |
Подсчёт HTTP-ответов с помощью агрегации скриптовых метрик
Можно подсчитать различные типы HTTP-ответов в наборе данных веб-журналов с помощью агрегации скриптовых метрик в рамках преобразования. Аналогичную функцию можно реализовать с помощью агрегаций фильтрации; подробности см. в примере Поиск подозрительных IP-адресов клиентов.
В примере ниже предполагается, что коды HTTP-ответов хранятся в виде ключевых слов в поле response документов.
"aggregations": {
"responses.counts": {
"scripted_metric": {
"init_script": "state.responses = ['error':0L,'success':0L,'other':0L]",
"map_script": """
def code = doc['response.keyword'].value;
if (code.startsWith('5') || code.startsWith('4')) {
state.responses.error += 1 ;
} else if(code.startsWith('2')) {
state.responses.success += 1;
} else {
state.responses.other += 1;
}
""",
"combine_script": "state.responses",
"reduce_script": """
def counts = ['error': 0L, 'success': 0L, 'other': 0L];
for (responses in states) {
counts.error += responses['error'];
counts.success += responses['success'];
counts.other += responses['other'];
}
return counts;
"""
}
},
...
} | Объект | |
| Объект агрегации | |
| Этот | |
| Объект | |
| Объект | |
| Объект | |
| Объект |
Сравнение индексов с помощью агрегаций метрик на основе сценариев
В этом примере показано, как сравнить содержимое двух индексов с помощью трансформации, использующей агрегацию метрик на основе сценариев.
POST _transform/_preview
{
"id" : "index_compare",
"source" : {
"index" : [
"index1",
"index2"
],
"query" : {
"match_all" : { }
}
},
"dest" : {
"index" : "compare"
},
"pivot" : {
"group_by" : {
"unique-id" : {
"terms" : {
"field" : "<unique-id-field>"
}
}
},
"aggregations" : {
"compare" : {
"scripted_metric" : {
"map_script" : "state.doc = new HashMap(params['_source'])",
"combine_script" : "return state",
"reduce_script" : """
if (states.size() != 2) {
return "count_mismatch"
}
if (states.get(0).equals(states.get(1))) {
return "match"
} else {
return "mismatch"
}
"""
}
}
}
}
} | Индексы, на которые ссылается объект | |
| Индекс | |
| Поле | |
| Объект агрегации | |
| Объект | |
|
| |
|
|
Получение данных о веб-сессии с помощью агрегаций метрик на основе сценариев
В этом примере показано, как извлечь несколько функций из одной транзакции. Давайте рассмотрим пример исходного документа из данных:
Исходный документ
{
"_index":"apache-sessions",
"_type":"_doc",
"_id":"KvzSeGoB4bgw0KGbE3wP",
"_score":1.0,
"_source":{
"@timestamp":1484053499256,
"apache":{
"access":{
"sessionid":"571604f2b2b0c7b346dc685eeb0e2306774a63c2",
"url":"http://www.leroymerlin.fr/v3/search/search.do?keyword=Carrelage%20salle%20de%20bain",
"path":"/v3/search/search.do",
"query":"keyword=Carrelage%20salle%20de%20bain",
"referrer":"http://www.leroymerlin.fr/v3/p/produits/carrelage-parquet-sol-souple/carrelage-sol-et-mur/decor-listel-et-accessoires-carrelage-mural-l1308217717?resultOffset=0&resultLimit=51&resultListShape=MOSAIC&priceStyle=SALEUNIT_PRICE",
"user_agent":{
"original":"Mobile Safari 10.0 Mac OS X (iPad) Apple Inc.",
"os_name":"Mac OS X (iPad)"
},
"remote_ip":"0337b1fa-5ed4-af81-9ef4-0ec53be0f45d",
"geoip":{
"country_iso_code":"FR",
"location":{
"lat":48.86,
"lon":2.35
}
},
"response_code":200,
"method":"GET"
}
}
}
}
... Используя поле sessionid в качестве поля группировки, вы можете перечислить события в рамках сессии и получить более подробную информацию о ней с помощью агрегации метрик на основе сценариев.
POST _transform/_preview
{
"source": {
"index": "apache-sessions"
},
"pivot": {
"group_by": {
"sessionid": {
"terms": {
"field": "apache.access.sessionid"
}
}
},
"aggregations": {
"distinct_paths": {
"cardinality": {
"field": "apache.access.path"
}
},
"num_pages_viewed": {
"value_count": {
"field": "apache.access.url"
}
},
"session_details": {
"scripted_metric": {
"init_script": "state.docs = []",
"map_script": """
Map span = [
'@timestamp':doc['@timestamp'].value,
'url':doc['apache.access.url'].value,
'referrer':doc['apache.access.referrer'].value
];
state.docs.add(span)
""",
"combine_script": "return state.docs;",
"reduce_script": """
def all_docs = [];
for (s in states) {
for (span in s) {
all_docs.add(span);
}
}
all_docs.sort((HashMap o1, HashMap o2)->o1['@timestamp'].millis.compareTo(o2['@timestamp'].millis));
def size = all_docs.size();
def min_time = all_docs[0]['@timestamp'];
def max_time = all_docs[size-1]['@timestamp'];
def duration = max_time.millis - min_time.millis;
def entry_page = all_docs[0]['url'];
def exit_path = all_docs[size-1]['url'];
def first_referrer = all_docs[0]['referrer'];
def ret = new HashMap();
ret['first_time'] = min_time;
ret['last_time'] = max_time;
ret['duration'] = duration;
ret['entry_page'] = entry_page;
ret['exit_path'] = exit_path;
ret['first_referrer'] = first_referrer;
return ret;
"""
}
}
}
}
} | Данные сгруппированы по полю | |
| Агрегации подсчитывают количество путей и перечисляют просмотренные страницы в рамках сессии. | |
|
| |
|
| |
|
| |
|
|
Результат вызова API аналогичен:
{
"num_pages_viewed" : 2.0,
"session_details" : {
"duration" : 131374,
"first_referrer" : "https://www.bing.com/",
"entry_page" : "http://www.leroymerlin.fr/v3/p/produits/materiaux-menuiserie/porte-coulissante-porte-interieure-escalier-et-rambarde/barriere-de-securite-l1308218463",
"first_time" : "2017-01-10T21:22:52.982Z",
"last_time" : "2017-01-10T21:25:04.356Z",
"exit_path" : "http://www.leroymerlin.fr/v3/p/produits/materiaux-menuiserie/porte-coulissante-porte-interieure-escalier-et-rambarde/barriere-de-securite-l1308218463?__result-wrapper?pageTemplate=Famille%2FMat%C3%A9riaux+et+menuiserie&resultOffset=0&resultLimit=50&resultListShape=PLAIN&nomenclatureId=17942&priceStyle=SALEUNIT_PRICE&fcr=1&*4294718806=4294718806&*14072=14072&*4294718593=4294718593&*17942=17942"
},
"distinct_paths" : 1.0,
"sessionid" : "000046f8154a80fd89849369c984b8cc9d795814"
},
{
"num_pages_viewed" : 10.0,
"session_details" : {
"duration" : 343112,
"first_referrer" : "https://www.google.fr/",
"entry_page" : "http://www.leroymerlin.fr/",
"first_time" : "2017-01-10T16:57:39.937Z",
"last_time" : "2017-01-10T17:03:23.049Z",
"exit_path" : "http://www.leroymerlin.fr/v3/p/produits/porte-de-douche-coulissante-adena-e168578"
},
"distinct_paths" : 8.0,
"sessionid" : "000087e825da1d87a332b8f15fa76116c7467da6"
}
...
© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/transform-painless-examples.html