Индексы Elasticsearch — это то, благодаря чему вы можете хранить и быстро находить нужные данные. В данной статье рассмотрим несколько шаблонов индексов, которые могут быть полезны для разных случаев.
Индекс Elasticsearch можно настроить с помощью маппинга, настроек и псевдонимов:
- Определения маппинга задают схему данных.
- Настройки задают размер шардов и частоту обновления.
- Псевдонимы используются для присвоения индексу альтернативных имен.
Когда мы индексируем документ в первый раз или создаем пустой индекс с помощью API Create Index, индекс будет создан с настройками по умолчанию, без схемы данных и без псевдонимов. Эти настройки по умолчанию хорошо работают в средах разработки и тестирования, но нам может понадобиться настроить наши индексы для производственных сред.
Работа с маппингами и настройками по умолчанию в производстве может привести к низкой производительности индексирования и поиска. Создание индексов вручную - утомительный и трудоемкий процесс. Воссоздание таких индексов в каждой среде особенно непрактично, если у нас есть сложная схема маппинга, а также индивидуальные настройки и псевдонимы.
К счастью, Elasticsearch предоставляет нам инструмент для автоматического применения предопределенной конфигурации при создании индексов в виде шаблонов индексов.
Шаблоны индексов
Шаблоны индексов позволяют создавать индексы с заданной пользователем конфигурацией. При инсталляции индекс может получить конфигурацию из этих шаблонов, например, заданное количество шардов и реплик или маппинги полей. Шаблон будет определен с шаблоном имени и некоторой конфигурацией в нем. Если имя индекса совпадает с шаблоном, то новый индекс будет создан с конфигурацией, заданной в шаблоне.
В версии 7.8 Elasticsearch усовершенствовал функциональность шаблонов, добавив композитные шаблоны. Эта новая версия позволяет создавать гораздо больше шаблонов индексов многократного использования, как показано в этой статье.
Типы шаблонов
Шаблоны индексов можно разделить на две категории:
- Индексные шаблоны (или композиционные индексные шаблоны): Композитные индексные шаблоны могут существовать как сами по себе, так и состоять из одного или нескольких компонентных шаблонов (см. вторую категорию).
- Компонентные шаблоны: Шаблон компонента - это самостоятельный шаблон многократного использования, определяющий необходимую конфигурацию. Обычно предполагается, что шаблон компонента связан с шаблоном индекса. Каждый из шаблонов компонентов может быть связан с одним или несколькими индексными шаблонами.
Как видно на изображении ниже, индексные шаблоны A и B разделяют между собой шаблоны компонентов (в данном случае только один - Шаблон 3). Шаблон индекса может состоять из нескольких или нескольких шаблонов компонентов, и каждый из шаблонов компонентов может быть связан с одним или несколькими шаблонами индекса. Оба типа шаблонов могут существовать сами по себе, однако шаблоны компонентов бесполезны, если они не привязаны к шаблону индекса.
Общая идея заключается в разработке каталога шаблонов компонентов, который организация может использовать для различных нужд (например, определяя различные шаблоны компонентов для отдельных сред) и прикреплять их к различным индексам с помощью композитных шаблонов индексов.
Как создавать композитные (индексные) шаблоны
Elasticsearch предоставляет конечную точку _index_template для управления шаблонами индексов. Пользователь предоставляет все необходимые маппинги, настройки и псевдонимы, а также шаблон имени индекса в этом шаблоне. Давайте рассмотрим пример создания шаблона для микросервисного приложения customer-order-service, которое отвечает за логику формирования заказов.
Допустим, нам требуется создать шаблон для заказов клиентов, представленный шаблоном с подстановочными знаками: *orders. Предполагается, что этот шаблон будет содержать определенные маппинги и настройки, такие как поле order_date, а также шарды и номера реплик.
Любой индекс, который при создании сопоставляется с этим шаблоном, наследует конфигурации, определенные в этом шаблоне. Например, индекс black_friday_orders будет иметь поле order_date, количество шардов будет равно 5, а количество реплик - 2. Кроме того, все индексы, созданные по этому шаблону, наследуют и одно имя псевдонима! Давайте создадим этот шаблон orders_template с шаблоном индекса, определенным как *orders, и схемой маппинга, состоящей из одного поля oder_date с предопределенным форматом даты dd-MM-yyy. В приведенном ниже коде показано, как создать этот индексный шаблон.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | PUT _index_template/orders_template { "index_patterns": ["*orders"], "priority": 300, "template": { "mappings": { "properties": { "order_date": { "type": "date", "format":"dd-MM-yyyy" } } }, "settings":{ "number_of_shards":5, "number_of_replicas":2 }, "aliases":{ "all_orders":{} } } } |
Когда вы выполняете этот запрос в DevTools Kibana, создается шаблон с шаблоном индекса *orders вместе с предопределенным маппингом, настройками и псевдонимом. index_patterns - это массив шаблонов соответствия; любой индекс, соответствующий этому шаблону, будет использоваться для создания конфигурации шаблона. Чтобы получить сохраненный шаблон, можно выполнить следующие действия, которые должны повторить то, что мы сделали:
1 | GET _index_template/orders_template |
Существует также приоритет, положительное число, определяемое при создании атрибута шаблона: каждый шаблон определяется с приоритетом, так что любые конфликтующие изменения из разных шаблонов будут разрешаться с использованием этого значения, причем приоритет будет отдаваться значению с более высоким приоритетом. Более подробно о приоритете шаблона мы поговорим ниже.
Создание индекса с помощью шаблона
Теперь у нас есть шаблон - образец для создания индексов - следующим шагом будет создание индекса. Когда имя индекса совпадает с заданным шаблоном, шаблонные конфигурации применяются автоматически. Чтобы доказать это, как показывает код ниже, давайте создадим совершенно новый индекс с именем: blackfriday_orders:
1 | PUT blackfriday_orders |
Поскольку имя индекса (blackfriday_orders) совпадает с шаблоном именования, определенным в шаблоне (т. е. *orders), индекс должен получить всю конфигурацию, полученную из шаблона. Давайте получим этот свежесозданный индекс и проверим, так ли это на самом деле, выполнив следующий код:
1 | GET blackfriday_orders |
Это должно вернуться:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | { "blackfriday_orders" : { "aliases" : { "all_orders" : { } }, "mappings" : { "properties" : { "order_date" : { "type" : "date", "format" : "dd-MM-yyyy" } } }, "settings" : { "index" : { ... "number_of_shards" : "5", "number_of_replicas" : "2" } } } } |
Как следует из ответа, конфигурация blackfriday_orders была унаследована от шаблона. Мы можем попробовать различные комбинации индексов, которые успешно унаследуют конфигурацию шаблона:
1 2 3 4 | PUT blackfriday_orders PUT americaorders PUT cancelled--orders PUT undefined101orders |
Однако следующие индексы не наследуют конфигурацию, поскольку их имена не совпадают с шаблоном:
1 2 3 | PUT blackfriday_orders2 PUT open_orders_ PUT allorders_total |
Важно помнить, что в данном случае все индексы, полученные из шаблона, имеют один и тот же псевдоним - all_orders. Преимущество такого псевдонима в том, что мы можем просто запрашивать по этому единственному псевдониму, а не по нескольким индексам.
1 2 3 4 5 6 7 8 9 10 11 12 | GET blackfriday_orders,americaorders,undefined101orders/_search GET all_orders/_search { "query": { "range": { "order_date": { "gte": "01-12-2021", "lte": "31-12-2021" } } } } |
Если мы создаем шаблон для *orders, то ожидается, что любой соответствующий индекс примет конфигурацию шаблона. Обычно, осознанно или неосознанно, команды могут создавать еще несколько шаблонов по разным причинам. Это означает, что иногда имя индекса может соответствовать двум разным шаблонам! Elasticsearch должен решить, какую из конфигураций из этих шаблонов ему нужно применить. К счастью, эту дилемму можно решить с помощью приоритета шаблона.
Создание шаблонов компонентов
В предыдущей части этой статьи мы узнали о шаблонах индексов. Есть несколько недостатков создания шаблонов со встроенной конфигурацией - один из них заключается в том, что конфигурация не может быть экспортирована для других шаблонов. Если мы захотим иметь подобную конфигурацию, скажем, для шаблонов, связанных с клиентами (*customers), нам, возможно, придется заново создавать весь шаблон. Это означает, что в типичной организации мы можем создать десятки таких шаблонов (плюс у вас может быть еще несколько, исходя из окружения).
Поскольку мы всегда стремимся к многократному использованию, Elasticsearch переработал шаблоны с учетом возможности повторного использования. Шаблоны компонентов как нельзя лучше подходят для этого. Если вы работаете в DevOps, то, скорее всего, у вас есть потребность в создании индексов с заданной конфигурацией для каждого окружения. Вместо того чтобы вручную применять каждую из этих конфигураций, можно создать шаблон компонента для каждой среды.
Шаблон компонента - это не что иное, как многократно используемый блок конфигураций, который мы можем использовать для создания других шаблонов индексов. Обратите внимание, что шаблоны компонентов не имеют ценности, если они не объединены с шаблонами индексов. Они открываются через конечную точку _component_template. Давайте посмотрим, как все это сочетается.
Шаблон настроек
Давайте извлечем настройки, которые мы ранее определили в шаблоне индекса, и создадим из них шаблон компонента. Предполагается, что шаблон settings_component_template будет иметь пять первичных шардов с двумя репликами на каждый первичный шард. Первый шаг, как показано в приведенном ниже листинге кода, заключается в объявлении и выполнении шаблона компонента с этой конфигурацией.
1 2 3 4 5 6 7 8 9 | PUT _component_template/settings_component_template { "template":{ "settings":{ "number_of_shards":5, "number_of_replicas":2 } } } |
Как показано в приведенном выше коде, мы используем конечную точку _component_template для создания шаблона компонента. Тело запроса содержит информацию о шаблоне в объекте шаблона. Шаблон settings_component_template теперь доступен для использования в других шаблонах индекса. Заметным отличием является то, что этот шаблон не определяет никакой шаблон индекса; это просто блок кода, который настраивает некоторые свойства для нас.
Шаблон маппинга
Аналогичным образом создадим еще один шаблон. На этот раз извлечем схему маппинга, которую мы определили ранее в шаблонах автономных индексов. В приведенном ниже коде показан сценарий:
1 2 3 4 5 6 7 8 9 10 11 12 13 | PUT _component_template/mappings_component_template { "template": { "mappings": { "properties": { "order_date": { "type": "date", "format":"dd-MM-yyyy" } } } } } |
Шаблон псевдонимов
Следуя тому же потоку, мы также можем иметь шаблон компонента с псевдонимами - двумя псевдонимами (all_orders и sales_orders):
1 2 3 4 5 6 7 8 9 | PUT _component_template/aliases_component_template { "template": { "aliases": { "all_orders": {}, "sales_orders":{} } } } |
Шаблон составного индекса
Теперь, когда у нас есть эти три шаблона компонентов, следующий шаг - использовать их. Мы можем сделать это, позволив шаблону индекса, скажем, christmas_orders, использовать их:
1 2 3 4 5 6 7 8 9 10 11 12 | PUT _index_template/composed_orders_template { "index_patterns": [ "*orders" ], "priority": 500, "composed_of": [ "settings_component_template", "mappings_component_template", "aliases_component_template" ] } |
Тег composed_of представляет собой коллекцию всех шаблонов компонентов, составляющих данный шаблон. В данном случае мы выбираем шаблоны компонентов настроек, маппингов и псевдонимов. Мы также повышаем приоритет, чтобы этот шаблон превзошел все остальные. Когда шаблон будет готов, все индексы, соответствующие шаблону *orders, унаследуют конфигурацию от этих трех шаблонов компонентов.
Тем не менее, если мы захотим создать новый шаблон, скажем, customers, с одним из существующих (settings_component_template) и вновь созданным шаблоном aliases (aliases_component_template - см. ниже), мы можем сделать это с помощью:
1 2 3 4 5 6 7 8 | PUT _component_template/aliases_component_template2 { "template": { "aliases": { "all_customers": {} } } } |
Шаблон индекса выглядит следующим образом:
1 2 3 4 5 6 7 8 9 10 11 | PUT _index_template/composed_customers_template { "index_patterns": [ "*customers*" ], "priority": 200, "composed_of": [ "settings_component_template", "aliases_component_template2" ] } |
Вы заметили, что шаблон settings_component_template был (повторно) использован в двух разных шаблонах? В этом и заключается сила шаблонов компонентов.
Приоритет шаблонов
Существует вероятность того, что разработчики могут создать несколько шаблонов индексов, не обращая внимания на существующий запас. Важно установить приоритет для каждого из этих шаблонов, чтобы использовался тот, у которого приоритет выше. Например, шаблон my_orders_template_1 перекрывает шаблон my_orders_template_2 в следующем фрагменте кода:
1 2 3 4 5 6 7 8 9 10 11 12 | PUT _index_template/my_orders_template_1 { "index_patterns": ["*orders"], "priority": 1000, "template": { ... } } PUT _index_template/my_orders_template2 { "index_patterns": ["*orders"], "priority": 300, "template": { ... } } |
Если у вас есть несколько шаблонов, соответствующих создаваемым индексам, Elasticsearch применяет все конфигурации из всех подходящих шаблонов, но отменяет все, что имеет более высокий приоритет.
Старшинство шаблонов
Наконец, вы можете задаться вопросом о старшинстве шаблонов - имеет ли конфигурация, определенная в шаблоне компонента, приоритет над конфигурацией, определенной в самом шаблоне главного индекса? Или наоборот? Есть несколько правил:
- Индекс, созданный с явными конфигурациями, имеет приоритет над всеми - это означает, что если вы создаете индекс с явными конфигурациями, не ожидайте, что они будут переопределены шаблонами.
- Устаревшие шаблоны (шаблоны, созданные до версии 7.8) имеют более низкий приоритет, чем композитные шаблоны.
Заключение
- Индекс содержит маппинги, настройки и псевдонимы: маппинги определяют схему полей, настройки задают параметры индекса, такие как количество шардов и реплик, а псевдонимы дают индексу альтернативные имена.
- Шаблоны позволяют создавать индексы с предопределенными конфигурациями. Если назвать индекс именем, которое соответствует шаблону index-pattern, определенному в конкретном шаблоне, то индекс будет автоматически сконфигурирован в соответствии с шаблоном.
- Elasticsearch представил композитные шаблоны индексов в версии 7.8. Композитные шаблоны индексов обеспечивают модульность и версионность шаблонов.
- Композитные шаблоны состоят из одного или нескольких шаблонов-компонентов.
- Шаблон индекса также может иметь свою собственную конфигурацию.
- Шаблон компонента - это многократно используемый шаблон с предопределенной конфигурацией, как и композитный шаблон индекса.
- Однако ожидается, что компонентные шаблоны будут частью индексного шаблона; они бесполезны, если они не "составлены" в индексный шаблон.
- Шаблоны компонентов не имеют определенного шаблона индекса - это еще одна причина, по которой они "ожидаются" как часть шаблона индекса.
- Каждый из шаблонов имеет приоритет - положительное число. Чем выше это число, тем больше приоритет для применения этого шаблона.