Opensearch, Logstash и dynamic mapping

от автора

У нас в Домклик огромное количество микросервисов, около 5000. Все они пишут какие‑то логи. В этой статье я хочу рассказать о том, как у нас настроен маппинг в индексах Opensearch и какие «фишки» мы используем, чтобы минимизировать работы по настройке маппинга.

Введение

Конечно же, логи не пишутся в один общий индекс. Для разделения мы используем понятие «продукты», то есть несколько сервисов объединяются в продукт. Всего у нас около 200 продуктов и 200 индексов. Мы не регулируем наименование и вложенность полей, только количество (не более 200 на индекс).

В Opensearch есть чудесная функция — динамический маппинг. Его суть в том, что Opensearch по умолчанию пытается типизировать поле как текст. Но есть и ложка дёгтя (даже половник), маппинг не работает для вложенных полей, если родительские поля не заданы явно как object. Например, для поля host.name потребуется такая конфигурация, иначе будет ошибка:

"mappings": {     "properties": {       "host": {         "type": "object"       }   }   }

Что делать, чтобы ненастраивать маппинг сотен полей в сотнях индексах руками, а также не маппить всё как текст, а получить хоть какую‑то типизацию автоматически? Вот вам пара фишек.

Фишка №1. logstash-filter-flatten_json

Фильтр для Logstash. Нашли его на github и чуть‑чуть доработали. Превращает поля JSON в «плоские», то есть добавляет в название поля всех его «родителей» через точку и выносит его на самый верхний уровень. Например, такой JSON:

{     "key_1": "value_1",     "key_3": {         "nested_key_1": "nested_value_1"     } }

превращается в такой:

{     "key_1": "value_1",     "key_3.nested_key_1": "nested_value_1" }

Если поле содержит массив, то значения в нём приводятся к строке и дальше вложенность не парсится. Если вам такое не подходит, то можно взять исходный плагин из оригинального репозитория, в котором значения массивов парсятся как отдельные поля. Этот плагин решает проблему с динамическим маппингом, гарантируя, что все поля будут проиндексированы как минимум как текст.

Фишка №2. Динамическое распознавание типов

Две функции динамического маппинга:

"mappings": {   "date_detection": true,   "dynamic_date_formats": ["yyyy-MM-dd HH:mm:ss.SSS 'MSK'"],   "numeric_detection": true }

date_detection — распознавание дат. В массиве dynamic_date_formats можно указать любые форматы, подробнее описано в тут (в документации Opensearch этого нет, но есть в документации Elasticsearch).

numeric_detection — распознавание чисел (long, float и т. д.)

Фишка №3. Очистка пустых полей

Бывает, что какое‑то поле приходит пустым или с прочерком. Прочерк считается текстом и проиндексировать такое поле как, например, число не получится. Для этого написали небольшой фильтр для Logstash на Ruby:

ruby {       code => "           Hash[event].each { |k, v|             if v.kind_of?(Array)                 if v.empty? or v.include? '-'                   event.remove(k)                 end             else                 if v == '-'                   event.remove(k)                 end             end           }       "   }

Это «лечит» логи, которые не попали бы в индекс из‑за неверной типизации.

Фишка №4. Индексирование поля с несколькими типами

Для построения дашбордов со статистикой требуется тип keyword. Но поля с таким типом плохо подходят для полнотекстового поиска. Решением будет индексировать их с двумя типами одновременно. Для этого добавляем блок fields:

"mappings": {     "dynamic_templates": [{       "string_fields": {       "mapping": {         "type": "text",         "fields": {           "keyword": {             "ignore_above": 256,             "type": "keyword"           }         }       },       "match_mapping_type": "string",       "match": "*"     }   }] }

Таким образом мы сможем и построить дашборд по таким полям, и использовать все функции полнотекстового поиска.

Подведем итоги

Благодаря этим «фишкам» мы не настраиваем около 90 % индексов. Все поля в них автоматически распознаются и типизируются как текст, даты и числа. Для остальных 10 % приходится настраивать небольшой маппинг руками. Например, если поле содержит IP‑адрес.

Правильная типизация позволяет делать дашборды со статистикой по логам, более гибкий поиск со сравнением чисел и дат, вхождение IP по маске и так далее.


ссылка на оригинал статьи https://habr.com/ru/articles/864128/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *