Spec-Zone.ru › Elasticsearch 7
›Руководство по Elasticsearch [7.17] ›Сводка или преобразование данных ›Преобразование данных

Примеры преобразований с 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
      """
    }
  }
}

Объект init_script создаёт поле типа long timestamp_latest и строкового типа last_doc в объекте state.

Объект map_script определяет current_date на основе временной метки документа, затем сравнивает current_date с state.timestamp_latest и, наконец, возвращает state.last_doc из фрагмента. Используя new HashMap(...), вы копируете исходный документ, это важно всякий раз, когда вы хотите передать весь исходный объект из одной фазы в следующую.

Объект combine_script возвращает state из каждого фрагмента.

Объект reduce_script итерируется по значению s.timestamp_latest, возвращённому каждым фрагментом, и возвращает документ с самой последней временной меткой (last_doc). В ответе лучшее совпадение (другими словами, latest_doc) вложено под полем latest_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, возвращающий час дня.

Устанавливает date на основе временной метки документа.

Возвращает значение часа из date.

Название агрегации.

Содержит скрипт Painless, возвращающий месяц года.

Устанавливает date на основе временной метки документа.

Возвращает значение месяца из date.

Получение длительности с помощью скрипта корзины

В этом примере показано, как получить длительность сессии по 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" 
        }
      }
    }
  }
}

Для определения длительности сессий используется скрипт корзины.

Путь к корзине — это карта переменных скрипта и соответствующих путей к корзинам, которые нужно использовать для переменной. В данном случае, min и max являются переменными, сопоставленными с time_frame.gte.value и time_frame.lte.value.

Наконец, скрипт вычитает начальную дату сессии из конечной даты, что приводит к длительности сессии.

Подсчёт 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;
        """
      }
    },
  ...
}

Объект aggregations преобразования, содержащий все агрегации.

Объект агрегации scripted_metric.

Этот scripted_metric выполняет распределённую операцию на данных веб-журналов для подсчёта определённых типов HTTP-ответов (ошибки, успехи и другие).

Объект init_script создаёт массив responses в объекте state с тремя свойствами (error, success, other) типа long.

Объект map_script определяет code на основе значения response.keyword документа, затем подсчитывает ошибки, успехи и другие ответы на основе первой цифры ответов.

Объект combine_script возвращает state.responses из каждого фрагмента.

Объект reduce_script создаёт массив counts со свойствами error, success и other, затем итерируется по значению responses, возвращённому каждым фрагментом, и присваивает различные типы ответов соответствующим свойствам объекта counts; ответы об ошибках — счётчикам ошибок, успешные ответы — счётчикам успехов, а другие ответы — счётчикам других ответов. Наконец, возвращает массив 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"
            }
            """
        }
      }
    }
  }
}

Индексы, на которые ссылается объект source, сравниваются друг с другом.

Индекс dest содержит результаты сравнения.

Поле group_by должно быть уникальным идентификатором каждого документа.

Объект агрегации scripted_metric.

Объект map_script определяет doc в объекте состояния. Использование new HashMap(...) позволяет скопировать исходный документ, что важно, когда необходимо передать весь исходный объект в следующую фазу.

combine_script возвращает state из каждого фрагмента.

reduce_script проверяет, равны ли размеры индексов. Если они не равны, возвращается count_mismatch. Затем он итерируется по всем значениям двух индексов и сравнивает их. Если значения равны, возвращается match, в противном случае — 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;
          """
        }
      }
    }
  }
}

Данные сгруппированы по полю sessionid.

Агрегации подсчитывают количество путей и перечисляют просмотренные страницы в рамках сессии.

init_script создаёт массив типа doc в объекте state.

map_script определяет массив span со временем, URL и значением referrer, которые основаны на соответствующих значениях документа, затем добавляет значение массива span в объект doc.

combine_script возвращает state.docs из каждого фрагмента.

reduce_script определяет различные объекты, такие как min_time, max_time и duration, на основе полей документа, затем объявляет объект ret и копирует исходный документ с помощью new HashMap (). Далее скрипт определяет first_time, last_time, duration и другие поля внутри объекта ret на основе соответствующих ранее определённых объектов, и, наконец, возвращает 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API