Эластичный поиск, возможно ли обновить вложенные объекты без обновления всего документа?
Я индексирую набор документов (представьте их как посты на форуме) с вложенным объектом, который является пользователем, связанным с этим постом. Моя проблема в том, что пользовательские поля могут быть обновлены, но поскольку сообщения не изменяются, они не переиндексируются, а вложенные пользователем объекты становятся устаревшими. Есть ли способ обновить вложенные объекты без повторной индексации всего документа? Или единственное решение состоит в том, чтобы переиндексировать все связанные сообщения пользователя при каждом изменении пользователя?
3 ответа
Вы можете использовать API обновления.
curl -XPOST localhost:9200/docs/posts/post/_update -d '{
"script" : "ctx._source.nested_user = updated_nested_user",
"params" : {
"updated_nested_user" : {"field": "updated"}
}
}'
Смотрите этот так ответ для полной информации.
Обратите внимание, что сценарии обновления поддерживают условную логику, как показано здесь. Таким образом, вы можете помечать сообщения на форуме, когда пользователь меняется, а затем перебирать сообщения, чтобы обновлять только сообщения с измененными пользователями.
curl -XPOST 'localhost:9200/docs/posts/post/_update' -d '{
"script" : "ctx._source.tags.contains(tag) ? "ctx._source.nested_user = updated_nested_John" : ctx.op = "none"",
"params" : {
"tag": "updated_John_tag",
"updated_nested_John" : {"field": "updated"}
}
}'
ОБНОВЛЕНО
Возможно, мой пример троичного оператора был неполным. Это не было упомянуто в вопросе, но при условии, что пользователи изменяют свою информацию в отдельной части приложения, было бы неплохо применить эти изменения к сообщениям на форуме в одном сценарии. Вместо использования тегов попробуйте проверить поле пользователя непосредственно на наличие изменений:
curl -XPOST 'localhost:9200/docs/posts/post/_update' -d '{
"script" : "ctx._source.nested_user.contains(user) ? "ctx._source.nested_user = updated_nested_John" : ctx.op = "none"",
"params" : {
"user": "John",
"updated_nested_John" : {"field": "updated"}
}
}'
Как уже упоминалось, это может быть более медленной операцией, чем переиндексация полных сообщений.
К сожалению,asticsearch не может обновить только часть документа без переиндексации всего документа. Итак, да, вам нужно будет переиндексировать весь документ, чтобы изменить вложенную часть.
Если у вас нет всего документа для повторной отправки, вы можете просто отправить часть, которая требует изменения, с помощью API обновления, но имейте в виду, что существуют проблемы с производительностью.
Ответ @Scott Rice о том, как использовать частичное обновление в этом контексте, очень полезен, в то время как ответ @ramseykhalaf более корректен в том смысле, что это невозможно без переиндексации. Если мы делаем частичное обновление, мы все равно переиндексируем весь документ.
Однако зависит от понимания того, что такое "переиндексация".
Если мы определяем переиндексацию как "повторную отправку всего документа в ES" - тогда мы можем вызвать частичное обновление решения без переиндексации в этом смысле. Если мы определяем переиндексацию как "пересчитывание структур данных, позволяющих эффективно искать обновленный документ в индексе" (что, по моему мнению, является более правильным определением), то это всегда происходит.
Обратите внимание, что вся старая копия документа останется в индексе после частичного обновления, помечена как удаленная (до следующего полного переиндексации с нуля или "оптимизации").
Чтобы избежать этого, вместо вложенных объектов могут использоваться дочерние отношения. Дочерние элементы могут быть добавлены / удалены / обновлены, не затрагивая родительский документ (однако это, конечно, имеет свою стоимость - поддержание леса отношений между дочерними и родительскими элементами в памяти и т. Д.).