Индекс OpenSearch используется как для организации, так и для распределения данных внутри кластера.
В этой статье мы дадим определение обоих компонентов индекса и расскажем о том, как создавать, добавлять, удалять и переиндексировать индексы в OpenSearch. Мы также затронем вопросы запросов, но более подробно они рассматриваются в статье Как запрашивать OpenSearch.
Роль индекса OpenSearch можно описать двумя способами. Во-первых, индекс - это механизм организации данных в соответствии с требованиями пользователя. И, во-вторых, индекс - это способ распределения данных внутри кластера OpenSearch.
Давайте сначала разберемся, как Индексы используются для организации данных.
Использование индексов для организации данных в OpenSearch
Когда мы обсуждаем, как индексы используются для организации данных в OpenSearch, мы можем представить их как подобие реляционной базы данных типа MySQL. Точно так же в OpenSearch хранятся Документы (Document, строки), у каждого из которых есть Свойства (Columns, столбцы). Каждое свойство можно также рассматривать как ключ в терминологии пар ключ-значение.
Свойства относятся к одной из нескольких категорий, каждая из которых обладает своими индивидуальными возможностями. Например, можно выполнять математические вычисления для свойств с плавающей запятой, но не для свойств со строкой или датой.
Небольшое замечание по поводу капитализации. В этой статье мы везде пишем Index и Document с заглавной буквы. Мы посчитали, что читателям будет полезно видеть эти термины с заглавной буквы, чтобы отличать их от повседневных значений.
Связывание терминов в индексе OpenSearch с базой данных MySQL
OpenSeach | MySQL |
Index | Data Base |
Document | Rows |
Properties | Columns |
Приведем небольшой пример. В розничной компании, скорее всего, есть индекс покупок. Затем в этом индексе есть документ (строка) для каждой отдельной покупки. А затем в каждом документе покупки есть свойства (столбцы), такие как дата/время покупки, купленный товар, стоимость и т.д.
Мы готовим еще несколько статей, посвященных подробному описанию запросов к OpenSearch, а пока давайте быстро рассмотрим, как мы будем запрашивать этот индекс покупок. В консоли OpenSearch Dashboards Dev Console можно использовать следующий код:
1 2 3 4 5 6 7 8 | GET /purchases/_search { "query": { "match": { "item": "New Balance 574" } } } |
В верхней строке запроса указывается "GET" - это API, используемый для получения документа. Затем указывается индекс, в данном случае "purchases". Наконец, указывается операция. Здесь операцией является "_search", поскольку мы ищем все записи (документы) о том, когда была куплена определенная пара бутс New Balance 574.
Если бы вместо "match" мы использовали "match_all", то вернулись бы все документы в индексе. Поскольку индексы обычно содержат тысячи документов, использование "match_all" не является распространенным способом поиска.
Повышение производительности и гибкости с помощью индексов
Хотя показать сходство индексов и баз данных - полезное упражнение, это еще не конец истории. По сравнению с базами данных индексы имеют дополнительные возможности. Например, поскольку индексы имеют небольшой вес, OpenSearch позволяет легко создавать индивидуальные индексы для каждого ежедневного журнала или для каждого пользователя.
Отдельные индексы позволяют повысить производительность и улучшить организацию данных в кластере. Отдельные индексы можно использовать для продуктов, журналов, IoT-устройств, транзакций или любых других групп элементов или событий, представляющих интерес для вашего случая. Однако, скорее всего, вы не захотите иметь индекс для отдельного элемента или события из-за шардинга. В следующем разделе мы рассмотрим причины этого.
Распределение данных с помощью индексов в OpenSearch
Шарды являются субэлементами индексов и позволяют распределять информацию по нескольким узлам кластера.
Реплики используются для повышения производительности поиска, а также для резервного копирования данных. Поскольку реплики помогают масштабировать обработку запросов, их можно добавлять/удалять по мере необходимости в любое время.
В приведенном выше примере, когда мы создали индекс покупок, мы также одновременно создаем набор первичных и репликовых шардов для этого индекса. По умолчанию OpenSearch создает один (1) первичный шард и одну (1) реплику для каждого индекса.
В качестве общего правила рекомендуется настраивать индекс на один шард объемом не менее 20-50 ГБ. Этот рекомендуемый нижний предел обусловлен тем, что каждый индекс представляет собой как минимум один шард.
Каждый отдельный шард требует ресурсов от OpenSearch. Большее количество хранилищ требует от OpenSearch большего объема работы по поддержанию местоположения данных, что снижает возможности OpenSearch по выполнению запросов.
Наличие нескольких хранилищ позволяет OpenSearch распределить поисковую нагрузку между несколькими экземплярами. В некоторых ситуациях может потребоваться большее количество шардов для распараллеливания работы на нескольких экземплярах.
Как создать и удалить индекс в OpenSearch
Теперь, когда мы имеем базовое представление об индексах, давайте разберемся, как их использовать.
Во-первых, для получения полного списка всех индексов в вашем кластере OpenSearch используйте следующий код в консоли OpenSearch Dashboards Dev Console:
1 | GET /_cat/indices |
Создание индекса в OpenSearch
Для создания индекса используется метод PUT. Ниже снова приведен наш пример с покупками. В этом примере мы создаем индекс покупок и указываем его свойства. В качестве свойств здесь указаны "@timestamp", "price" и "item_name". Тип свойств также указан как date, float и string соответственно.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | PUT /purchases { "settings": { "index": { "number_of_shards": 1, "number_of_replicas": 1 }, "analysis": { "analyzer": { "analyzer-name": { "type": "custom", "tokenizer": "keyword", "filter": "lowercase" } } }, "mappings": { "properties": { "@timestamp": { "type": "date" }, "price": { "type": "float" }, "item_name": { "type": "string", "analyzer": "analyzer-name" } } } } } |
Важно отметить, что документы не могут быть добавлены в поток данных с помощью PUT.
После выполнения приведенного выше кода будет получено следующее подтверждение.
1 2 3 | { "acknowledged": true } |
Добавление в индекс в OpenSearch
Теперь, когда индекс покупок создан, мы можем добавить документ. В данном случае документом является одна транзакция. Для добавления документа в индекс мы используем POST API.
Следует также отметить, что документ может быть создан без предварительного создания индекса. Если документ создается без соответствующего индекса, OpenSearch создаст индекс с настройками по умолчанию (обычно это не то, что нам нужно).
1 2 3 4 5 6 | POST /purchases/_doc/ { "@timestamp": "2023-01-09-T14:59:00", "item_name" : "New Balance 574", "price" : 119.99 } |
В ответ будет выдан ответ, в котором Документу будет присвоен уникальный "_id". Этот идентификатор может быть полезен для запроса документа. Далее в этой статье мы покажем, как этот идентификатор может быть использован для выбора документа для удаления.
Если вы хотите указать "_id", а не получить случайный идентификатор, то вместо
1 | POST /my_index/_doc/ |
включите "_id" следующим образом:
1 | POST /my_index/_doc/<_id> |
Хотя вы можете указать свой собственный "_id", это не рекомендуется, поскольку OpenSearch быстрее всего работает с собственной генерацией идентификатора документа. Если вы хотите использовать "ID", то мы рекомендуем использовать собственное уникальное поле, например, "purchase_id".
Как правило, пользователи OpenSearch не должны добавлять поля или имена полей, начинающиеся с символа подчеркивания. Например, не следует добавлять имя поля "id", если существует поле "_id". Также не следует добавлять поле "type", поскольку поле "_type" используется по умолчанию.
Получение данных из индекса в OpenSearch
Для получения данных из индекса мы будем использовать API GET.
Приведенный ниже код является повторением приведенного выше примера, в котором мы запрашиваем все транзакции, включающие покупку бутс "New Balance 574" в индексе "purchases".
1 2 3 4 5 6 7 8 | GET /purchases/_search { "query": { "match": { "item": "New Balance 574" } } } |
Удаление данных из индекса в OpenSearch
Документы могут быть удалены с помощью API POST или DELETE. Ниже мы рассмотрим несколько примеров.
Удаление документа по запросу с использованием совпадения
Здесь мы удаляем все документы, для которых значение поля "item" равно "New Balance 574". Это удаление будет включать запись о паре бутс, которую мы добавили в наш индекс в разделе выше.
1 2 3 4 5 6 7 8 | POST /purchases/_delete_by_query { "query": { "match": { "item": "New Balance 574" } } } |
Вы заметите, что этот код похож на код запроса, приведенного выше, с двумя отличиями - заменой API с "GET" на "POST" и изменением действия с "_search" на "_delete_by_query".
Удаление всех документов в индексе с помощью функции match_all
Если вместо слова "match" использовать "match_all", то это приведет к удалению всех документов из индекса.
1 2 3 4 5 6 | POST /purchases/_delete_by_query { "query": { "match_all": { } } } |
Удаление документов с диапазоном
В следующем примере мы удаляем все документы, цена которых больше или равна ("gte") $100.00.
1 2 3 4 5 6 7 8 9 10 | POST /purchases/_delete_by_query { "query": { "range": { "price": { "gte": 100.00 } } } } |
API DELETE для удаления одного документа в OpenSearch
API DELETE менее громоздкий, но требует указания уникального "_id", о котором говорилось выше.
Указание уникального "_id" - единственный способ убедиться в том, что вы удаляете один документ в OpenSearch. Уникальный "_id" можно также указать, используя описанный выше подход к удалению по запросу. В этом случае имя поля будет "_id".
1 | DELETE /my_index/_doc/<_id> |
Удаление индекса в OpenSearch
Чтобы удалить весь индекс в OpenSearch, используйте API DELETE следующим образом:
1 | DELETE /my_index |
Переиндексация в OpenSearch
Переиндексация используется для копирования документов из источника в место назначения. Для переиндексации в OpenSearch используйте POST API следующим образом:
1 2 3 4 5 6 7 8 9 | POST _reindex { "source": { "index": "my-index" }, "dest": { "index": "my-new-index" } } |