Перейти к основному содержимому
Версия: 6.0

Реиндексация данных

Реиндексация - процесс переноса документов из одного индекса Smart Monitor Data Storage в другой при помощи API операции _reindex. Данная операция используется, когда нужно изменить структуру хранения или обработки данных без ручной выгрузки и повторной загрузки документов.

Реиндексация не изменяет исходный индекс и не переносит автоматически его settings, mappings, aliases и index template. Целевой индекс рекомендуется создавать заранее, чтобы явно зафиксировать нужную схему и настройки.

Термины

ТерминОписание
Исходный индексИндекс, из которого копируются документы
Целевой индексНовый индекс, в который записываются документы
AliasЛогическое имя индекса. Позволяет переключить приложение на новый индекс без изменения его конфигурации
Ingest pipelineНабор процессоров, применяемых к документам при записи
SliceЧасть задачи реиндексации. Используется для параллельной обработки больших индексов
TaskФоновая задача Smart Monitor Data Storage, если _reindex запущен асинхронно

Когда требуется реиндексация

  • изменение типа поля в mapping
  • изменение анализаторов, нормализаторов или количества primary shard
  • переименование индекса
  • переименование, удаление или преобразование полей
  • объединение нескольких индексов в один
  • копирование части данных по фильтру
  • применение ingest pipeline к уже существующим документам

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


Предварительные требования

Перед началом работ необходимо убедиться, что:

  • есть доступ к Dev Tools, curl или другому HTTP-клиенту
  • у пользователя есть права на чтение исходного индекса и запись в целевой
  • на диске достаточно места для временного хранения двух копий данных
  • кластер находится в состоянии green или допустимом для обслуживания yellow
  • создан snapshot или другой способ восстановления данных (при необходимости)

Общая схема без простоя

Рекомендуемый сценарий для production с использованием alias:

  1. Создать новый индекс с новой версией имени, например orders-v2
  2. Скопировать данные из текущего индекса через _reindex
  3. Проверить количество документов, выборочные документы, mapping и поисковые запросы
  4. Остановить или ограничить запись в старый индекс на короткое время
  5. Досинхронизировать документы, которые изменились во время основной реиндексации
  6. Атомарно переключить alias со старого индекса на новый
  7. Проверить приложение
  8. Удалить старый индекс только после периода наблюдения

Переключение alias выполняется одним запросом, чтобы в любой момент времени alias указывал ровно на один индекс:

POST _aliases
{
"actions": [
{ "remove": { "index": "old-index", "alias": "index-alias" } },
{ "add": { "index": "new-index", "alias": "index-alias" } }
]
}

Переиндексация всех документов

1. Создание целевого индекса

Сначала необходимо создать целевой индекс с требуемой структурой полей (маппингом) и настройками. Их можно задать вручную или скопировать из исходного индекса.

Рекомендация по производительности

При создании временных индексов рекомендуется устанавливать количество реплик (number_of_replicas) в 0 на время реиндексации. После завершения необходимо вернуть исходное значение.

Обратите внимание!

Не стоит полагаться на автоматическое создание индекса во время _reindex - Smart Monitor Data Storage создаст его с динамическим mapping, который может не соответствовать требуемой схеме.

PUT <index-name>
{
"mappings": {
... // Укажите нужный маппинг
},
"settings": {
... // Укажите нужные настройки
}
}

2. Выполнение операции Reindex

Для небольших индексов подходит синхронный запуск:

POST _reindex
{
"source":{
"index":"source"
},
"dest":{
"index":"<index-name>"
}
}

Для больших индексов необходимо использовать асинхронный запуск:

POST _reindex?wait_for_completion=false&slices=auto&requests_per_second=1000
{
"source": {
"index": "source",
"size": 1000
},
"dest": {
"index": "<index-name>",
"op_type": "create"
},
"conflicts": "proceed"
}

Параметры запуска:

ПараметрНазначение
wait_for_completion=falseЗапускает операцию в фоне и возвращает task_id
slices=autoВключает автоматическое параллельное выполнение
requests_per_secondОграничивает скорость, чтобы снизить нагрузку на кластер
source.sizeРазмер batch для чтения документов
dest.op_type=createНе перезаписывает существующие документы в целевом индексе
conflicts=proceedПродолжает выполнение при конфликте версий или существующих _id

Выборочная реиндексация документов

Операция _reindex позволяет копировать не весь индекс, а только документы, соответствующие поисковому запросу.

По условию

POST _reindex
{
"source":{
"index":"source",
"query": {
"match": {
"field_name": "text"
}
}
},
"dest":{
"index":"<index-name>"
}
}
Обратите внимание!

Полный перечень доступных операций приведен в официальной документации OpenSearch.

Только отдельные поля

POST _reindex
{
"source": {
"index": "source",
"_source": [
"field_1",
"field_2",
"field_3"
]
},
"dest": {
"index": "<index-name>"
}
}

Объединение нескольких индексов

Чтобы объединить документы из нескольких индексов в один, необходимо указать индексы-источники в виде списка.

POST _reindex
{
"source":{
"index":[
"source_1",
"source_2"
]
},
"dest":{
"index":"destination"
}
}
Обратите внимание!

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


Преобразование документов во время реиндексации

Способ 1: Скрипт

Для простых преобразований используется раздел script. Рекомендуемый язык - Painless.

Пример: переименование поля client_id в customer_id

POST _reindex
{
"source": {
"index": "source"
},
"dest": {
"index": "<index-name>"
},
"script": {
"source": "ctx._source.customer_id = ctx._source.remove('client_id')"
}
}

Способ 2: Ingest pipeline

Для более сложных преобразований используется ingest pipeline.

  1. Сначала необходимо создать pipeline с нужными процессорами:
PUT _ingest/pipeline/pipeline-test
{
"description": "Преобразует текстовое поле в список. Вычисляет длину поля 'word' и сохраняет ее в новом поле 'word_count'. Удаляет поле 'test'",
"processors": [
{
"split": {
"field": "text",
"separator": "\\s+",
"target_field": "word"
}
},
{
"script": {
"lang": "painless",
"source": "ctx.word_count = ctx.word.length"
}
},
{
"remove": {
"field": "test"
}
}
]
}
  1. Затем необходимо указать pipeline в dest:
POST _reindex
{
"source": {
"index": "source"
},
"dest": {
"index": "<index-name>",
"pipeline": "pipeline-test"
}
}

Обновление документов в текущем индексе

Для обновления данных непосредственно в текущем индексе без создания нового используется операция update_by_query.

Особенности операции:

  • выполняется методом POST
  • одновременно может работать только с одним индексом
Пример команды
POST <index_name>/_update_by_query
Обратите внимание!

Если запустить эту команду без параметров, она увеличит номер версии для всех документов в указанном индексе.


Отслеживание выполнения

Список активных задач реиндексации
GET _tasks?actions=*reindex*&detailed=true
Проверка конкретной задачи
GET _tasks/<node_id>:<task_id>
Отмена задачи
POST _tasks/<node_id>:<task_id>/_cancel

Признаки, что нагрузку необходимо снизить:

  • растет latency поисковых или write-запросов
  • появляются rejected-запросы в thread pool
  • растет JVM heap pressure
  • диск приближается к flood-stage watermark
  • кластер долго находится в red или нестабильном yellow

В таком случае необходимо отменить задачу и перезапустить её с меньшим requests_per_second или количеством slices.


Rollback

Если после переключения обнаружена проблема, необходимо вернуть alias на старый индекс:

POST _aliases
{
"actions": [
{ "remove": { "index": "new-index", "alias": "index-alias" } },
{ "add": { "index": "old-index", "alias": "index-alias" } }
]
}
Обратите внимание!

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


Ограничения и риски

  • _reindex копирует документы, но не переносит автоматически настройки индекса, шаблоны и alias
  • изменения в исходном индексе во время операции не блокируются
  • при активной записи требуется стратегия досинхронизации
  • большая реиндексация создает нагрузку на disk I/O, CPU, heap и thread pools
  • при нехватке диска индекс может перейти в read-only из-за watermark
  • скрипты и pipeline могут замедлить операцию
  • ошибки mapping в целевом индексе приведут к rejected-документам
  • conflicts=proceed пропускает конфликты, но не исправляет их причину

Параметры исходного индекса

ПараметрДопустимые значенияОписаниеОбязательный
indexStringИмя исходного индекса. Можно указать несколько индексов в виде списка.ДА
max_docsIntegerМаксимальное количество документов для переиндексации.НЕТ
queryObjectПоисковый запрос для выбора документов при операции переиндексации.НЕТ
sizeIntegerКоличество документов для переиндексации.НЕТ
sliceStringЗадает ручную или автоматическую параллелизацию (слайсинг) для ускорения процесса переиндексации.НЕТ

Параметры целевого индекса

ПараметрДопустимые значенияОписаниеОбязательный
indexStringИмя целевого индекса.ДА
version_typeEnumТип контроля версий для операции индексации. Допустимые значения: internal, external, external_gt, external_gte.НЕТ

Чек-лист перед запуском

  • создан snapshot или подтвержден другой способ восстановления (при необходимости)
  • проверено состояние кластера
  • создан целевой индекс с нужными settings и mappings
  • выполнена тестовая реиндексация
  • оценено место на диске
  • определена стратегия обработки записей во время миграции
  • подготовлен rollback через alias

Чек-лист после запуска

  • задача _reindex завершилась без критичных ошибок
  • количество документов сверено
  • проверены выборочные документы
  • возвращены production-настройки индекса
  • alias переключен одним атомарным запросом
  • приложение проверено после переключения
  • старый индекс оставлен на период наблюдения