КатегорииElasticsearch

Elasticsearch — Урок 5.4 Организация данных

В этом разделе мы обсудим, как разделить ваши данные на несколько индексов. Elasticsearch предоставляет псевдонимы индексов, которые позволяют легко запросить сразу несколько индексов. Он также поддерживает шаблоны индексов для настройки автоматического создания индекса. Мы также обсудим, как обрабатывать временные данные, такие как журналы, которые являются обычным примером использования Elasticsearch.

Псевдоним индекса

Псевдоним индекса — это указатель на один или несколько индексов. Операция поиска, выполняемая  к псевдониму, выполняется по всем индексам, на которые указывает псевдоним. Координационный узел выполняет запрос по всем индексам, собирает результаты и отправляет их обратно клиенту. С другой стороны, операция индексации не может выполняться в псевдониме, который указывает на несколько индексов. Рекомендуется использовать псевдоним вместо фактического имени индекса в вашем приложении. Если псевдоним должен указывать на другой индекс позже, это будет простой переключатель.

Из-за того, что данные, хранящиеся в инвертированном индексе, сопоставления существующих полей не могут быть изменены «на лету». Например, вы хотите обработать поле, которое ранее индексировалось как строка в качестве даты. Для этого вам нужно создать новый индекс с правильными сопоставлениями и переиндексировать данные. Если ваше приложение в настоящее время использует псевдоним индекса application_logs и псевдоним в настоящее время указывает на индекс index_with_date_as_string, псевдоним можно легко изменить, чтобы использовать новый индекс, index_with_date_as_date как показано здесь:

POST /_aliases
 {
   "actions": [
     {
       "remove": {
         "index": "index_with_date_as_string",
         "alias": "application_logs"
       }
     },
     {
       "add": {
         "index": "index_with_date_as_date",
         "alias": "application_logs"
       }
     }
   ]
 }

Поскольку приложение использует псевдоним, мы можем изменить индекс без каких-либо изменений кода клиента. Ответ на предыдущий запрос выглядит следующим образом:

 {
   "acknowledged": true
 }

Поскольку псевдоним может указывать на несколько индексов, мы использовали _aliases конечную точку для переключения индекса, на который указывает псевдоним. Мы можем добавить индекс index_with_date_as_string в псевдоним application_logs двумя способами. Используя _alias, как показано здесь:

PUT index_with_date_as_string/_alias/application_logs

Или используя _aliases конечную точку, как показано здесь:

POST /_aliases
 {
   "actions": [
     {
       "add": {
         "index": "index_with_date_as_string",
         "alias": "application_logs"
       }
     }
   ]
 }

Вы можете проверить индексы, на которые указывает псевдоним, как показано ниже:

GET /*/_alias/application_logs

Ответ на предыдущий запрос выглядит следующим образом:

{
   "index_with_date_as_string": {
     "aliases": {
       "application_logs": {}
     }
   }
 }

Псевдоним индекса можно также использовать для группировки одного или нескольких индексов. Это особенно полезно при запросе данных временных рядов. Например, вы сохраняете журналы приложений в Elasticsearch. В зависимости от объема данных вы решили хранить в одном индексе месяц данных. Все журналы, которые производятся в том же месяце, индексируются по одному и тому же индексу. Например индекс, в котором хранятся данные за апрель logs_04_17. Предположим, вы заботитесь о последних журналах, вы можете создать logs_last_2_months псевдоним, который указывает на индексы последних двух месяцев. Пользователь или приложение могут запрашивать псевдоним, а не вычислять индексы за последние 2 месяца на основе текущей даты.

Псевдоним индекса также может использоваться для просмотра данных с помощью фильтра. Это похоже на представление в реляционной базе данных. Например, документ журнала выглядит следующим образом:

POST logs_04_17/log/
 {
   "level": "ERROR",
   "application": "Service A",
   "timestamp" : "2017-04-13T16:39:00-07:00",
   "message": "Exception in thread java.lang.NullPointerException at chapter5.main(ServiceA.java:23)"
 }

Предположим, мы только что развернули последний код и хотим убедиться, что в приложении нет ошибок. Мы можем создать псевдоним с фильтром для ошибок, как показано здесь:

POST /_aliases
 {
   "actions": [
     {
       "add": {
         "index": "logs_04_17",
         "alias": "logs_latest_error",
         "filter": {
           "match": {
             "level": "ERROR"
           }
         }
       }
     }
   ]
 }

Чтобы получить только ошибки, вы можете запросить logs_latest_error:

GET logs_latest_error/_search

Вы можете искать ошибки, которые регистрируются Service A в течение последнего 1 часа:

POST logs_latest_error/_search
 {
   "query": {
     "bool": {
       "must": [
         {
           "match": {
              "application": "Service A"
           }
         },
         {
           "range": {
             "timestamp": {
               "gte": "now-1h",
               "time_zone": "-07:00"
             }
           }
         }
       ]
     }
   }
 }

Ответ:

{
   "took": 1,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 1,
     "max_score": 1.5162321,
     "hits": [
       {
         "_index": "logs_04_17",
         "_type": "log",
         "_id": "AVtpudeslh63sHCyBgdB",
         "_score": 1.5162321,
         "_source": {
           "level": "ERROR",
           "application": "Service A",
           "timestamp": "2017-04-13T16:39:00-07:00",
           "message": "Exception in thread java.lang.NullPointerException at chapter5.main(ServiceA.java:23)"
         }
       }
     ]
   }
 }

Шаблоны индексов

Когда вы индексируете документ, если индекс не существует, Elasticsearch автоматически создаст индекс, основанный на настройках по умолчанию. Отображения документа динамически отображаются. Вы можете перезаписать настройки по умолчанию и отображение поля с помощью шаблонов индексов. По умолчанию новый индекс создается с 5 осколками и 1 репликой. В следующем шаблоне,  следующий созданный индекс будет иметь 1 осколок и 0 реплик:

 PUT _template/default_template
 {
   "template": "*",
   "order": 0,
   "settings": {
     "number_of_shards": 1
   }
 }

Шаблоны индексов работают с использованием имени индекса. Давайте определим шаблон для индекса журналов, который мы обсуждали в предыдущем разделе. Пример журнала выглядит следующим образом:

 POST logs_04_17/log/
 {
   "level": "ERROR",
   "application": "Service A",
   "timestamp" : "2017-04-13T16:39:00-07:00",
   "message": "Exception in thread java.lang.NullPointerException at chapter5.main(ServiceA.java:23)"
 }

При определении шаблона индекса вместе с настройками индекса, можно указать сопоставление индекса, как показано здесь:

PUT _template/logs_template
 {
   "template": "logs*", 
   "order": 1,
   "settings": {
     "number_of_shards": 3
   },
   "mappings": {
     "log": {
       "properties": {
         "level": {
           "type": "keyword"
         },
         "application": {
           "type": "keyword"
         },
         "timestamp": {
           "type": "date",
           "format": "date_optional_time"
         },
         "message": {
           "type": "text"
         }
       }
     }
   }
 }

Если имя индекса начинается со слова logs, настройки и сопоставления в шаблоне автоматически применяются к вновь созданному индексу. Удалим существующий индекс и переиндексируем образец журнала следующим образом:

 #Удаляем
 DELETE logs_04_17

 #Индексируем
 POST logs_04_17/log/
 {
   "level": "ERROR",
   "application": "Service A",
   "timestamp" : "2017-04-13T16:39:00-07:00",
   "message": "Exception in thread java.lang.NullPointerException at chapter5.main(ServiceA.java:23)"
 }

 #Проверяем
 GET logs_04_17

Параметры индекса logs_04_17:

{
   "logs_04_17": {
     "aliases": {},
     "mappings": {
       "log": {
         "properties": {
           "application": {
             "type": "keyword"
           },
           "level": {
             "type": "keyword"
           },
           "message": {
             "type": "text"
           },
           "timestamp": {
             "type": "date",
             "format": "date_optional_time"
           }
         }
       }
     },
     "settings": {
       "index": {
         "creation_date": "1492140374212",
         "number_of_shards": "3",
         "number_of_replicas": "1",
         "uuid": "9NjtgYx6Q2uCOWP6Csc95Q",
         "version": {
           "created": "5010299"
         },
         "provided_name": "logs_04_17"
       }
     }
   }
 }

С помощью шаблона можно создавать новые индексы, не беспокоясь о настройках или сопоставлениях. Кроме того, с настройками и отображением мы можем определить псевдоним к которому принадлежит индекс. Как только индекс создается, индекс автоматически добавляется к псевдониму. Мы можем добавить logs_04_17 индекс к logs_last_2_months псевдониму, как показано ниже:

PUT _template/logs_template
 {
   "template": "logs*",
   "order": 1,
   "settings": {
     "number_of_shards": 3
   },
   "aliases": {
     "logs_last_2_months": {}
   },
   "mappings": {
     "log": {
       "properties": {
         "level": {
           "type": "keyword"
         },
         "application": {
           "type": "keyword"
         },
         "timestamp": {
           "type": "date",
           "format": "date_optional_time"
         },
         "message": {
           "type": "text"
         }
       }
     }
   }
 }

Заметка

Используя шаблоны индексов, в псевдоним могут быть добавлены новые индексы, но существующие индексы не могут быть удалены. Например, когда logs_04_17 добавляется в logs_last_2_months псевдоним, псевдоним теперь указывает на более двух индексов. Вы должны вручную удалить старые индексы или добавить фильтр.

Когда создается новый индекс журналов, он автоматически добавляется к logs_last_2_month псевдониму. Любой выполненный запрос logs_last_2_month будет включать результаты только что созданного индекса.

Управление временными индексами

Данные временных рядов — очень распространенный шаблон использования Elasticsearch. Данные чувствительны к времени; мы можем заботиться только о последних данных. Например, журналы приложений, журналы более определенного времени больше не актуальны. Самые свежие данные — это то, что мы хотим запросить. Поскольку старые данные больше не важны, чтобы сохранить дисковое пространство и избежать ненужных циклов вычисления, нам нужно удалить старые данные. Самый простой способ обработки данных временных рядов — группировать индексы на основе временного интервала, чтобы старые индексы можно было легко удалить.

В этом разделе мы суммируем различные API, которые мы обсуждали до сих пор, для управления временными индексами. Например, мы хотим хранить журналы приложений в дневных индексах. Мы будем использовать один индекс в день. Чтобы управлять ежедневными индексами, мы можем сделать следующее:

  • Определите шаблон индекса, чтобы автоматически устанавливать сопоставления при создании индекса
  • Используйте ingest node для преобразования необработанных журналов в документ JSON, индексируйте документ в правильный индекс в зависимости от дня
  • Определите logs_last_3_daysпсевдоним, который указывает на индексы, содержащие журналы за последние 3дни
  • Удаление старых индексов из псевдонима

Приложение, вызывающее Elasticsearch, может использовать узел ingest для преобразования данных перед индексированием. Мы можем определить конвейер для выполнения необходимых преобразований. Мы можем использовать date_index_name процессор для чтения метки времени из документа и определения индекса, к которому принадлежит документ. Если мы используем ежедневные индексы, документ с 2017-04-14T09:02:34.234+07:00 меткой времени попадет в log_2017_04_14 индекс. Здесь date_index_name показан конвейер с процессором для дневных индексов:

{
   "pipeline": {
     "description": "Item View Pipeline",
     "processors": [
       {
         "date_index_name": {
           "field": "timestamp",
           "index_name_prefix": "log_",
           "date_rounding": "d",
           "index_name_format": "yyyy_MM_dd"
         }
       }
     ]
   }
 }

Для получения дополнительной информации о том, как использовать узел ingest, обратитесь к разделу Ingest Node .

Затем давайте определим шаблон индекса, чтобы автоматически применить отображение, когда имя индекса начинается со слова log. Когда индекс создается, он также будет добавлен в logs_last_3_days псевдоним:

PUT _template/logs_template
 {
   "template": "log*",
   "aliases": {
     "logs_last_3_days": {}
   }
}

Затем мы удалим старые индексы из logs_last_3_days псевдонима:

POST /_aliases
 {
   "actions": [
     {
       "remove": {
         "index": "log_2017_04_14",
         "alias": "logs_last_3_days"
       }
     }
   ]
 }

В следующем разделе мы обсудим API Shrink, который можно использовать для уменьшения количества осколков индекса.

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

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