Elasticsearch — Урок 4.2 Обновление данных

В этом уроке мы обсудим различные способы обновления существующих документов. Внутренне обновление всегда является удалением и повторным индексом. Вы можете обновить весь документ (заменить исходный документ) или обновить одно поле или добавить новое поле или обновить поле с помощью сценариев, например, увеличить счетчик.

Обновление с использованием всего документа

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

Ответ:

Из ответа видно что result равен updated, _version (версия) равна 2 и что документ не был сейчас создан (created: false).

Частичные обновления

В предыдущем разделе мы обсудили, как обновить весь документ. В этом разделе мы обсудим, как обновить только одно или два поля в документе. Elasticsearch предоставляет API обновления, чтобы частично обновить существующий документ. API-интерфейс обновления сначала извлекает старый документ, а затем использует _source документа для применения изменений, удаляет старый документ и индексирует документ в качестве нового. Обновляемые поля указываются в теле запроса в поле doc.

Чтобы работали частичные обновления _source должно быть включено, по умолчанию так и есть, но лучше проверить. Что такое _source смотрите раздел Хранение оригинального документа

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

Ответ следующий:

Как видно в ответе версия увеличилась и теперь равна 3.

Сценарий обновления

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

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

Elasticsearch поддерживает множество языков сценариев для выполнения встроенных скриптов, язык сценариев по умолчанию — Painless. Предположим, мы хотим классифицировать документ, который мы проиндексировали ранее, по взрослым и подросткам. Мы можем использовать встроенный скрипт, как показано ниже, чтобы проверить возраст человека и добавить новое поле person_type. Следующая команда обновит документ на основе сценария:

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

Из ответа можно увидеть, что в документе появилось новое поле person_type = adult (взрослый).

Upsert

При частичном обновлении документа, если документ еще не существует, обновление завершится неудачно. Если вы хотите создать новый документ, если документ не существует, вы можете установить doc_as_upsert флаг в true. Установка upsert в true приведет к созданию нового документа с полями в поле doc. Приведем пример:

В предыдущем примере, поскольку документ id 3 не существует, создается новый документ. Теперь давайте посмотрим на него. Ответ следующий:

Из ответа видно, что новый документ содержит только поле name.

NOOP

В предыдущем разделе мы обновили документ id 2, где имени присвоили значение «name update 2»:

Если вы попытаетесь снова запустить обновление, операция будет проигнорирована, так как изменений нет. Ответ будет содержать result (результат) равный noop, как показано здесь:

Вы можете отключить это поведение, установив detect_noop в false:

С detect_noop установленным значением false, произойдет обновление документа не взирая что данные уже есть в документе. Ответ следующий:

Что происходит при обновлении документа?

В предыдущем разделе мы обсудили, что происходит, когда вы индексируете документ. В этом разделе мы обсудим, как обрабатываются обновления документов и почему обновление является дорогостоящей операцией.

Как обсуждалось ранее, когда документ индексируется, он сохраняется в сегменте. По дизайну сегмент, после создания, не может быть изменен. Будучи неизменным, вы получаете несколько преимуществ. Например, как только файл сегмента считывается в кеш файловой системы, он может жить там вечно, поскольку он не изменяется, и Lucene не нужно беспокоиться о блокировке файла для любых изменений. Но если сегмент не может быть изменен, как мы можем обновить существующий документ? Чтобы выполнить обновление, сначала существующий документ будет мягко удален, а обновленный документ будет проиндексирован как новый документ.

Слияние сегментов

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

Сегменты также нуждаются в большом количестве ресурсов, таких как обработчики файлов, процессор, дисковое пространство и память. Чтобы уменьшить количество сегментов, Lucene объединяет сегменты аналогичного размера в более крупный сегмент. При слиянии сегментов документы, помеченные как удаленные, не копируются в объединенный сегмент. Пока сегменты объединяться, документ физически не удаляется с диска:

В то время как сегменты объединяются в более крупный сегмент, поисковые запросы по-прежнему обслуживаются из изначальных сегментов. После завершения слияния новые сегменты могут обслуживать запросы поиска, а старые сегменты удаляются с диска. Чем больше обновлений, тем чаще объединяются сегменты. Слияние активно использует ресурсы процессора, памяти и ввода-вывода, из-за чего данная операция очень дорогая.