API разделения индекса
Разделяет существующий индекс на новый индекс с большим количеством первичных фрагментов.
resp = client.indices.split(
index="my-index-000001",
target="split-my-index-000001",
settings={
"index.number_of_shards": 2
},
)
print(resp) response = client.indices.split(
index: 'my-index-000001',
target: 'split-my-index-000001',
body: {
settings: {
'index.number_of_shards' => 2
}
}
)
puts response const response = await client.indices.split({
index: "my-index-000001",
target: "split-my-index-000001",
settings: {
"index.number_of_shards": 2,
},
});
console.log(response); POST /my-index-000001/_split/split-my-index-000001
{
"settings": {
"index.number_of_shards": 2
}
} Запрос
POST /<index>/_split/<target-index>
PUT /<index>/_split/<target-index>
Предварительные условия
- Если включены функции безопасности Elasticsearch, у вас должны быть
manageправа доступа к индексу для индекса. -
Прежде чем вы сможете разделить индекс:
- Индекс должен быть только для чтения.
- Состояние кластера должно быть зеленым (cluster health).
Вы можете сделать индекс только для чтения с помощью следующего запроса, используя API добавления блокировки индекса:
resp = client.indices.add_block(
index="my_source_index",
block="write",
)
print(resp) response = client.indices.add_block( index: 'my_source_index', block: 'write' ) puts response
const response = await client.indices.addBlock({
index: "my_source_index",
block: "write",
});
console.log(response); PUT /my_source_index/_block/write
Текущий индекс записи потока данных разделить нельзя. Для разделения текущего индекса записи необходимо сначала перенести поток данных, чтобы создать новый индекс записи, а затем разделить предыдущий индекс записи.
Описание
API для разделения индекса позволяет разделить существующий индекс на новый индекс, где каждый исходный первичный фрагмент разделяется на два или более первичных фрагментов в новом индексе.
Количество раз, которое индекс может быть разделен (и количество фрагментов, на которые может быть разделен каждый исходный фрагмент), определяется настройкой index.number_of_routing_shards. Количество фрагментов маршрутизации определяет пространство хэширования, которое используется внутри для распределения документов по фрагментам с помощью согласованного хэширования. Например, индекс с 5 фрагментами, где настройка number_of_routing_shards установлена в значение 30 (5 x 2 x 3), может быть разделен на фактор 2 или 3. Другими словами, он может быть разделен следующим образом:
-
5→10→30(разделение на 2, затем на 3) -
5→15→30(разделение на 3, затем на 2) -
5→30(разделение на 6)
index.number_of_routing_shards является статической настройкой индекса. Вы можете установить index.number_of_routing_shards только при создании индекса или для закрытого индекса.
Пример создания индекса
Следующий API для создания индекса создает индекс my-index-000001 с настройкой index.number_of_routing_shards со значением 30.
resp = client.indices.create(
index="my-index-000001",
settings={
"index": {
"number_of_routing_shards": 30
}
},
)
print(resp) response = client.indices.create(
index: 'my-index-000001',
body: {
settings: {
index: {
number_of_routing_shards: 30
}
}
}
)
puts response const response = await client.indices.create({
index: "my-index-000001",
settings: {
index: {
number_of_routing_shards: 30,
},
},
});
console.log(response); PUT /my-index-000001
{
"settings": {
"index": {
"number_of_routing_shards": 30
}
}
} Значение по умолчанию для настройки index.number_of_routing_shards зависит от количества первичных фрагментов в исходном индексе. Значение по умолчанию разработано, чтобы позволить разделение на множители 2 до максимального значения в 1024 фрагментов. Однако, необходимо учитывать исходное количество первичных фрагментов. Например, индекс, созданный с 5 первичными фрагментами, может быть разделен на 10, 20, 40, 80, 160, 320 или максимум 640 фрагментов (с одним действием разделения или несколькими действиями разделения).
Если исходный индекс содержит один первичный фрагмент (или многофрагментный индекс был сжат до одного первичного фрагмента), то индекс может быть разделен на произвольное количество фрагментов, большее 1. Свойства значения по умолчанию для фрагментов маршрутизации будут применяться к новому разделенному индексу.
Как работает разделение
Операция разделения:
- Создаёт новый целевой индекс с таким же определением, как и исходный индекс, но с большим количеством первичных фрагментов.
- Создаёт жёсткие ссылки на сегменты из исходного индекса в целевой индекс. (Если файловая система не поддерживает жёсткие ссылки, то все сегменты копируются в новый индекс, что является намного более длительным процессом.)
- После создания низкоуровневых файлов снова хэширует все документы, чтобы удалить документы, принадлежащие другому фрагменту.
- Восстанавливает целевой индекс, как если бы он был закрытым индексом, который только что был повторно открыт.
Почему Elasticsearch не поддерживает инкрементное решардинг?
Переход от N фрагментов к N+1 фрагментам, т.е. инкрементное решардинг, действительно поддерживается многими хранилищами данных типа ключ-значение. Добавление нового фрагмента и перенос новых данных только в этот новый фрагмент не является вариантом: это, вероятно, станет узким местом при индексировании, и выяснение того, к какому фрагменту относится документ, учитывая его _id, что необходимо для запросов get, delete и update, станет достаточно сложным. Это означает, что нам нужно перебалансировать существующие данные с использованием другой схемы хэширования.
Наиболее распространённый способ эффективного выполнения этого в хранилищах данных типа ключ-значение — использование согласованного хэширования. Согласованное хэширование требует перераспределения только 1/N-й части ключей при увеличении количества фрагментов с N до N+1. Однако единицей хранения Elasticsearch являются фрагменты, которые представляют собой индексы Lucene. Из-за их ориентированной на поиск структуры данных, взятие значительной части индекса Lucene, будь то только 5% документов, удаление их и индексирование их в другом фрагменте, как правило, стоит намного дороже, чем в хранилище данных типа ключ-значение. Эта стоимость остается приемлемой при увеличении количества фрагментов в множители, как описано в предыдущем разделе: это позволяет Elasticsearch выполнять разделение локально, что, в свою очередь, позволяет выполнять разделение на уровне индекса, а не переиндексировать документы, которые нужно переместить, а также использовать жёсткие ссылки для эффективного копирования файлов.
В случае данных только для добавления можно получить больше гибкости, создав новый индекс и перенеся новые данные в него, добавив алиас, охватывающий как старый, так и новый индекс для операций чтения. Предполагая, что старые и новые индексы имеют соответственно M и N фрагмента, это не имеет издержек по сравнению с поиском в индексе, который будет содержать M+N фрагмента.
Разделить индекс
Чтобы разделить my_source_index на новый индекс под названием my_target_index, выполните следующий запрос:
resp = client.indices.split(
index="my_source_index",
target="my_target_index",
settings={
"index.number_of_shards": 2
},
)
print(resp) response = client.indices.split(
index: 'my_source_index',
target: 'my_target_index',
body: {
settings: {
'index.number_of_shards' => 2
}
}
)
puts response const response = await client.indices.split({
index: "my_source_index",
target: "my_target_index",
settings: {
"index.number_of_shards": 2,
},
});
console.log(response); POST /my_source_index/_split/my_target_index
{
"settings": {
"index.number_of_shards": 2
}
} Вышеуказанный запрос возвращает результат сразу после добавления целевого индекса в состояние кластера — он не ожидает начала операции разделения.
Индексы могут быть разделены только в случае выполнения следующих требований:
- Целевой индекс не должен существовать
- Исходный индекс должен иметь меньше первичных фрагментов, чем целевой индекс.
- Количество первичных фрагментов в целевом индексе должно быть кратным количеству первичных фрагментов в исходном индексе.
- Узел, обрабатывающий процесс разделения, должен иметь достаточно свободного дискового пространства для размещения второй копии существующего индекса.
API для _split аналогичен API create index и принимает параметры settings и aliases для целевого индекса:
resp = client.indices.split(
index="my_source_index",
target="my_target_index",
settings={
"index.number_of_shards": 5
},
aliases={
"my_search_indices": {}
},
)
print(resp) response = client.indices.split(
index: 'my_source_index',
target: 'my_target_index',
body: {
settings: {
'index.number_of_shards' => 5
},
aliases: {
my_search_indices: {}
}
}
)
puts response const response = await client.indices.split({
index: "my_source_index",
target: "my_target_index",
settings: {
"index.number_of_shards": 5,
},
aliases: {
my_search_indices: {},
},
});
console.log(response); POST /my_source_index/_split/my_target_index
{
"settings": {
"index.number_of_shards": 5
},
"aliases": {
"my_search_indices": {}
}
} | Количество фрагментов в целевом индексе. Это значение должно быть кратно количеству фрагментов в исходном индексе. |
Карты не могут быть указаны в запросе _split.
Отслеживание процесса разделения
Процесс разделения можно отслеживать с помощью API _cat recovery, или можно использовать API cluster health для ожидания, пока все первичные фрагменты не будут распределены, установив параметр wait_for_status в значение yellow.
API _split возвращает результат, как только целевой индекс добавлен в состояние кластера, до того, как какие-либо фрагменты будут распределены. В этот момент все фрагменты находятся в состоянии unassigned. Если по какой-либо причине целевой индекс не может быть распределен, его первичный фрагмент останется в состоянии unassigned до тех пор, пока он не сможет быть распределён на этот узел.
После того, как первичный фрагмент распределен, он переходит в состояние initializing, и начинается процесс разделения. После завершения операции разделения фрагмент станет active. В этот момент Elasticsearch попытается распределить любые реплики и может принять решение о перераспределении первичного фрагмента на другой узел.
Ожидание активных фрагментов
Поскольку операция разделения создаёт новый индекс для разделения фрагментов, настройка ожидания активных фрагментов при создании индекса также применяется к действию разделения индекса.
Параметры пути
-
<index> - (Обязательно, строка) Название исходного индекса для разделения.
-
<target-index> -
(Обязательно, строка) Название целевого индекса для создания.
Имена индексов должны соответствовать следующим критериям:
- Только строчные буквы
- Не может содержать
\,/,*,?,",<,>,|, ` ` (пробел),,,# - Индексы до версии 7.0 могли содержать двоеточие (
:), но это устарело и не будет поддерживаться в версии 7.0+ - Не может начинаться с
-,_,+ - Не может быть
.или.. - Не может быть длиннее 255 байтов (обратите внимание, что это байты, поэтому многобайтовые символы будут быстрее достигать лимита 255)
- Имена, начинающиеся с
., устарели, за исключением скрытых индексов и внутренних индексов, управляемых плагинами
Параметры запроса
-
wait_for_active_shards -
(Необязательно, строка) Количество копий каждого фрагмента, которые должны быть активны перед выполнением операции. Установите в
allили любое неотрицательное целое число до общего количества копий каждого фрагмента в индексе (number_of_replicas+1). По умолчанию1, что означает ожидание активации каждого первичного фрагмента.См. Активные фрагменты.
-
master_timeout - (Необязательно, единицы времени) Время ожидания мастер-узла. Если мастер-узел недоступен до истечения срока ожидания, запрос завершается ошибкой. По умолчанию
30s. Также можно установить в-1, чтобы указать, что запрос никогда не должен истекать. -
timeout - (Необязательно, единицы времени) Время ожидания ответа от всех соответствующих узлов в кластере после обновления метаданных кластера. Если ответ не получен до истечения срока ожидания, обновление метаданных кластера все равно применяется, но ответ укажет, что он не был полностью подтвержден. По умолчанию
30s. Также можно установить в-1, чтобы указать, что запрос никогда не должен истекать.
Тело запроса
-
aliases -
(Необязательно, объект объектов) Псевдонимы для результирующего индекса.
Свойства объектов
aliases-
<alias> -
(Обязательно, объект) Ключ — имя псевдонима. Имена псевдонимов индексов поддерживают date math.
Тело объекта содержит параметры для псевдонима. Поддерживается пустой объект.
Свойства
<alias>-
filter - (Необязательно, объект Query DSL) Запрос, используемый для ограничения документов, к которым может получить доступ псевдоним.
-
index_routing - (Необязательно, строка) Значение, используемое для маршрутизации операций индексирования на определённый фрагмент. При указании переписывает значение
routingдля операций индексирования. -
is_hidden - (Необязательно, Boolean) Если
true, псевдоним является скрытым. По умолчаниюfalse. Все индексы для псевдонима должны иметь одинаковое значениеis_hidden. -
is_write_index - (Необязательно, Boolean) Если
true, индекс является индексом записи для псевдонима. По умолчаниюfalse. -
routing - (Необязательно, строка) Значение, используемое для маршрутизации операций индексирования и поиска на определённый фрагмент.
-
search_routing - (Необязательно, строка) Значение, используемое для маршрутизации операций поиска на определённый фрагмент. При указании переписывает значение
routingдля операций поиска.
-
-
-
settings - (Необязательно, объект настроек индекса) Параметры конфигурации для целевого индекса. См. Настройки индекса.
© 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/8.17/indices-split-index.html