Привет, Хабр!
Правильно настроенные индексы могут значительно ускорить доступ к данным и улучшить производительность запросов. В NoSQL разнообразие решений настолько велико, что порой можно заблудиться.
В статье разберемся, какие виды индексов существуют, какие задачи они помогают решать и как выбирать подходящий индекс.
Типы индексов в NoSQL
Первичные индексы:
Первичные индексы дают уникальную идентификацию каждой записи в базе данных и организуют данные в соответствии с определенным ключом. В NoSQL-базах данных первичные индексы играют основную роль в распределении данных между узлами.
Первичные индексы определяются автоматически при создании записи и не требуют доп. усилий для их поддержки. Например, в MongoDB _id
является первичным индексом по умолчанию, а в Cassandra используется первичный ключ, определяемый пользователем.
В MongoDB поле _id
автоматически индексируется:
// поиск документа по первичному индексу _id db.collection.find({ _id: ObjectId("64bd1c9f4a4e19d8f84f06f9") })
В Cassandra первичный ключ определяется при создании таблицы, который автоматически индексируется:
-- cоздание таблицы с первичным ключом CREATE TABLE users ( user_id UUID PRIMARY KEY, name TEXT, email TEXT ); -- поиск по первичному индексу SELECT * FROM users WHERE user_id = '550e8400-e29b-41d4-a716-446655440000';
Первичные индексы дают быстрый доступ к записям, т.к данные отсортированы по ключу. Но при этом подходят только для операций, связанных с ключом.
Вторичные индексы
Вторичные индексы дают возможность быстрого поиска по полям, отличным от первичного ключа. Они помогают выполнять сложные запросы, которые не могут быть реализованы с использованием только первичных индексов.
MongoDB:
Создание вторичного индекса для оптимизации поиска по полю name
:
// создание вторичного индекса на поле name db.collection.createIndex({ name: 1 }); // поиск по вторичному индексу db.collection.find({ name: "Artem" });
Cassandra:
Создание вторичного индекса для оптимизации поиска по полю email
:
-- создание вторичного индекса на поле email CREATE INDEX ON users (email); -- поиск по вторичному индексу SELECT * FROM users WHERE email = 'artem@example.com';
Рассмотрим пример использования первичных и вторичных ключей, где идет работа с коллекцией пользователей в MongoDB и нужно оптимизировать поиск по нескольким полям:
// создание коллекции пользователей с автоматическим первичным индексом _id db.users.insertMany([ { name: "Ivan", email: "ivan@example.com", age: 28 }, { name: "Artem", email: "artem@example.com", age: 32 }, { name: "Kolya", email: "kolya@example.com", age: 25 } ]); // создание вторичных индексов db.users.createIndex({ name: 1 }); db.users.createIndex({ email: 1 }); // поиск пользователя по имени db.users.find({ name: "Alice" }); // поиск пользователя по email db.users.find({ email: "bob@example.com" });
Создали индексы на полях name
и email
, таким образом можно быстро находить пользователей по этим параметрам.
Индексы на основе диапазонов
Индексы на основе диапазонов позволяют обрабатывать запросы, где необходимо работать с интервалами значений: временные метки, числовые диапазоны или алфавитные строки.
Elasticsearch активно использует индексы на основе диапазонов для обработки временных данных и сложных запросов. Пример:
PUT /logs { "mappings": { "properties": { "timestamp": { "type": "date" }, "message": { "type": "text" } } } } // поиск по диапазону дат GET /logs/_search { "query": { "range": { "timestamp": { "gte": "2024-08-01", "lte": "2024-08-31" } } } }
Cassandra поддерживает индексацию на основе диапазонов для числовых и временных данных:
-- создание таблицы с временными метками CREATE TABLE events ( event_id UUID PRIMARY KEY, timestamp TIMESTAMP, description TEXT ); -- поиск событий за определенный период SELECT * FROM events WHERE timestamp >= '2024-08-01' AND timestamp <= '2024-08-31';
Представим задачу, в которой идет работа с логами событий и нужно быстро находить события за определенные временные промежутки:
// создание коллекции логов событий db.logs.insertMany([ { timestamp: new Date("2024-08-01T10:00:00Z"), message: "User login" }, { timestamp: new Date("2024-08-02T12:00:00Z"), message: "Data backup" }, { timestamp: new Date("2024-08-03T14:00:00Z"), message: "System update" } ]); // создание индекса на поле timestamp db.logs.createIndex({ timestamp: 1 }); // поиск событий за август 2024 db.logs.find({ timestamp: { $gte: new Date("2024-08-01"), $lte: new Date("2024-08-31") } });
Геопространственные индексы
Геопространственные индексы предназначены для работы с географическими данными, такими как координаты точек, линии и полигоны. Они позволяют выполнять географические запросы, например: «поиск ближайших» и «вхождение в область«.
В MongoDB используется 2dsphere
индекс для поддержки сложных географических запросов:
// создание коллекции с географическими данными db.places.insertMany([ { name: "Central Park", location: { type: "Point", coordinates: [-73.9654, 40.7829] } }, { name: "Golden Gate Park", location: { type: "Point", coordinates: [-122.4862, 37.7694] } } ]); // создание геопространственного индекса db.places.createIndex({ location: "2dsphere" }); // поиск мест в радиусе 10 км от заданной точки db.places.find({ location: { $near: { $geometry: { type: "Point", coordinates: [-73.935242, 40.730610] }, $maxDistance: 10000 } } });
Elasticsearch поддерживает геопространственные индексы для быстрого поиска по координатам:
PUT /places { "mappings": { "properties": { "location": { "type": "geo_point" } } } } // Поиск ближайших мест GET /places/_search { "query": { "geo_distance": { "distance": "10km", "location": { "lat": 40.730610, "lon": -73.935242 } } } }
Допустим, мы разрабатываем приложение для поиска ближайших кафе, используя MongoDB:
// создание коллекции с данными о кафе db.cafes.insertMany([ { name: "Cafe 1", location: { type: "Point", coordinates: [-73.935242, 40.730610] } }, { name: "Cafe 2", location: { type: "Point", coordinates: [-73.985428, 40.748817] } } ]); // создание геопространственного индекса db.cafes.createIndex({ location: "2dsphere" }); // поиск кафе в радиусе 5 км от заданной точки db.cafes.find({ location: { $near: { $geometry: { type: "Point", coordinates: [-73.961452, 40.768063] }, $maxDistance: 5000 } } });
Полнотекстовые индексы
Полнотекстовые индексы позволяют обрабатывать запросы, связанные с текстовым содержимым.
MongoDB поддерживает полнотекстовые индексы с использованием text
индекса для текстового поиска:
// создание коллекции с текстовыми данными db.articles.insertMany([ { title: "NoSQL: A Comprehensive Guide", content: "This article explains the key concepts of NoSQL databases." }, { title: "Understanding MongoDB Indexes", content: "Indexes in MongoDB are crucial for performance optimization." } ]); // создание полнотекстового индекса db.articles.createIndex({ content: "text" }); // поиск по ключевым словам db.articles.find({ $text: { $search: "NoSQL databases" } });
А вот Elasticsearch изначально проектировался для полнотекстового поиска:
PUT /articles { "mappings": { "properties": { "content": { "type": "text" } } } } // Поиск по ключевым словам GET /articles/_search { "query": { "match": { "content": "NoSQL databases" } } }
Представим, что хотим реализовать поиск по статьям с MongoDB:
// MongoDB: Создание коллекции статей db.blog.insertMany([ { title: "The Rise of NoSQL", content: "NoSQL databases have become increasingly popular..." }, { title: "Indexing in MongoDB", content: "Indexes are essential for query performance in MongoDB..." } ]); // создание полнотекстового индекса на поле content db.blog.createIndex({ content: "text" }); // поиск статей, содержащих слово "NoSQL" db.blog.find({ $text: { $search: "NoSQL" } });
Индексация — это мощный инструмент, который может улучшить производительность и гибкость проектов.
Если есть еще темы или вопросы, которые стоит рассмотреть, дайте знать!
В заключение напоминаю про ближайшие открытые уроки, которые пройдут в рамках онлайн-курса «NoSQL»:
15 августа: «Практические кейсы использования ClickHouse». Запись по ссылке
22 августа: «Интеграция ClickHouse с системами ETL». Запись по ссылке
ссылка на оригинал статьи https://habr.com/ru/articles/834310/
Добавить комментарий