Проектирование схем на практике
Информационно-поисковые системы (IR), также известные как поиск, необходимы для различных приложений искусственного интеллекта, таких как генерация с расширенным поиском (RAG), поиск изображений и рекомендации товаров. Первым шагом в разработке IR-системы является проектирование модели данных, которое включает в себя анализ бизнес-требований, определение способа организации информации и индексацию данных для обеспечения семантического поиска.
Milvus поддерживает определение модели данных через схему коллекции. Коллекция организует неструктурированные данные, такие как текст и изображения, вместе с их векторными представлениями, включая плотные и разреженные векторы различной точности, используемые для семантического поиска. Кроме того, Milvus поддерживает хранение и фильтрацию невекторных типов данных, называемых "скалярными". К скалярным типам относятся BOOL, INT8/16/32/64, FLOAT/DOUBLE, VARCHAR, JSON и Array.
Пример схемы данных, предназначенной для поиска новостной статьи
Проектирование модели данных поисковой системы включает в себя анализ потребностей бизнеса и абстрагирование информации в виде модели данных, выраженной в виде схемы. Например, для поиска по фрагменту текста его необходимо "проиндексировать", преобразовав буквенную строку в вектор с помощью "встраивания", что позволяет осуществлять векторный поиск. Помимо этого основного требования, может потребоваться хранение других свойств, таких как время публикации и автор. Эти метаданные позволяют уточнить семантический поиск с помощью фильтрации, возвращая только тексты, опубликованные после определенной даты или определенным автором. Кроме того, их может потребоваться получить вместе с основным текстом для отображения результатов поиска в приложении. Чтобы упорядочить эти фрагменты текста, каждому из них должен быть присвоен уникальный идентификатор, выраженный в виде целого числа или строки. Эти элементы необходимы для реализации сложной логики поиска.
Хорошо продуманная схема очень важна, поскольку она абстрагирует модель данных и решает, можно ли достичь бизнес-целей с помощью поиска. Кроме того, поскольку каждая строка данных, вставляемая в коллекцию, должна соответствовать схеме, это значительно помогает поддерживать согласованность данных и их долгосрочное качество. С технической точки зрения, четко определенная схема приводит к хорошо организованному хранению данных в столбцах и более чистой структуре индексов, что повышает производительность поиска.
Пример: Поиск новостей
Допустим, мы хотим создать поиск для новостного сайта, и у нас есть корпус новостей с текстом, уменьшенными изображениями и другими метаданными. Сначала нам нужно проанализировать, как мы хотим использовать эти данные для поддержки бизнес-требований поиска. Представьте, что нам необходимо получать новости на основе уменьшенного изображения и краткого содержания, а также использовать метаданные, такие как информация об авторе и время публикации, в качестве критериев для фильтрации результатов поиска. Эти требования можно разделить на следующие.
Для поиска изображений по тексту мы можем встраивать изображения в векторы с помощью мультимодальной модели встраивания, которая может отображать текстовые и графические данные в одно и то же латентное пространство.
Краткий текст статьи встраивается в векторы с помощью модели встраивания текста.
Для фильтрации по времени публикации даты хранятся в виде скалярного поля, а для эффективной фильтрации необходим индекс для скалярного поля. Другие более сложные структуры данных, такие как JSON, можно хранить в скалярном поле и выполнять поиск по их содержимому (индексирование JSON - это будущая функция).
Чтобы получить байт миниатюры изображения и отобразить его на странице результатов поиска, также хранится url изображения. Аналогично, для текста и заголовка резюме. (В качестве альтернативы мы можем хранить необработанный текст и данные файла изображения как скалярные поля, если это необходимо).
Чтобы улучшить результат поиска по краткому тексту, мы разработали гибридный подход к поиску. Для одного из путей поиска мы используем регулярную модель встраивания для генерации плотного вектора из текста, такую как OpenAI's
text-embedding-3-large
или open-sourcebge-large-en-v1.5
. Эти модели хорошо отражают общую семантику текста. Другой путь - использовать модели разреженного встраивания, такие как BM25 или SPLADE, для генерации разреженного вектора, напоминающего полнотекстовый поиск, который хорошо улавливает детали и отдельные понятия в тексте. Milvus поддерживает использование обоих методов в одной коллекции данных благодаря своей многовекторной функции. Поиск по нескольким векторам может быть выполнен за одну операциюhybrid_search()
.Наконец, нам также необходимо поле ID для идентификации каждой отдельной новостной страницы, формально называемой "сущностью" в терминологии Milvus. Это поле используется в качестве первичного ключа (или сокращенно "pk").
Имя поля | article_id (первичный ключ) | заголовок | автор_инфо | публикация_тс | адрес_изображения | вектор_изображения | резюме | суммарный_плотный_вектор | сводный_разреженный_вектор |
---|---|---|---|---|---|---|---|---|---|
Тип | INT64 | VARCHAR | JSON | INT32 | VARCHAR | FLOAT_VECTOR | VARCHAR | ПЛОСКИЙ_ВЕКТОР | РАЗРЕЖЕННЫЙ_ПЛОСКИЙ_ВЕКТОР |
Нужный индекс | N | N | N (поддержка скоро появится) | Y | N | Y | N | Y | Y |
Как реализовать пример схемы
Создание схемы
Сначала мы создадим экземпляр клиента Milvus, который можно использовать для подключения к серверу Milvus и управления коллекциями и данными.
Чтобы создать схему, мы используем create_schema()
для создания объекта схемы и add_field()
для добавления полей в схему.
from pymilvus import MilvusClient, DataType
collection_name = "my_collection"
# client = MilvusClient(uri="http://localhost:19530")
client = MilvusClient(uri="./milvus_demo.db")
schema = MilvusClient.create_schema(
auto_id=False,
)
schema.add_field(field_name="article_id", datatype=DataType.INT64, is_primary=True, description="article id")
schema.add_field(field_name="title", datatype=DataType.VARCHAR, max_length=200, description="article title")
schema.add_field(field_name="author_info", datatype=DataType.JSON, description="author information")
schema.add_field(field_name="publish_ts", datatype=DataType.INT32, description="publish timestamp")
schema.add_field(field_name="image_url", datatype=DataType.VARCHAR, max_length=500, description="image URL")
schema.add_field(field_name="image_vector", datatype=DataType.FLOAT_VECTOR, dim=768, description="image vector")
schema.add_field(field_name="summary", datatype=DataType.VARCHAR, max_length=1000, description="article summary")
schema.add_field(field_name="summary_dense_vector", datatype=DataType.FLOAT_VECTOR, dim=768, description="summary dense vector")
schema.add_field(field_name="summary_sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR, description="summary sparse vector")
Вы можете заметить аргумент uri
в MilvusClient
, который используется для подключения к серверу Milvus. Вы можете задать эти аргументы следующим образом.
Если вам нужна локальная векторная база данных только для небольших масштабов данных или создания прототипов, установка uri в качестве локального файла, например,
./milvus.db
, является наиболее удобным методом, так как он автоматически использует Milvus Lite для хранения всех данных в этом файле.Если у вас большой объем данных, скажем, более миллиона векторов, вы можете настроить более производительный сервер Milvus на Docker или Kubernetes. В этом случае используйте адрес и порт сервера в качестве uri, например,
http://localhost:19530
. Если вы включили функцию аутентификации на Milvus, используйте "<ваше_имя_пользователя>:<ваш_пароль>" в качестве токена, в противном случае не задавайте токен.Если вы используете Zilliz Cloud, полностью управляемый облачный сервис для Milvus, настройте
uri
иtoken
, которые соответствуют публичной конечной точке и ключу API в Zilliz Cloud.
Что касается auto_id
в MilvusClient.create_schema
, AutoID - это атрибут первичного поля, который определяет, нужно ли включать автоматическое приращение для первичного поля. Поскольку мы установили полеarticle_id
в качестве первичного ключа и хотим добавлять id статьи вручную, мы установили auto_id
False, чтобы отключить эту функцию.
После добавления всех полей в объект схемы наш объект схемы соответствует записям в таблице выше.
Определение индекса
После определения схемы с различными полями, включая метаданные и векторные поля для изображений и сводных данных, на следующем этапе необходимо подготовить параметры индекса. Индексирование имеет решающее значение для оптимизации поиска и извлечения векторов, обеспечивая эффективную работу запросов. В следующем разделе мы определим параметры индекса для указанных векторных и скалярных полей в коллекции.
index_params = client.prepare_index_params()
index_params.add_index(
field_name="image_vector",
index_type="AUTOINDEX",
metric_type="IP",
)
index_params.add_index(
field_name="summary_dense_vector",
index_type="AUTOINDEX",
metric_type="IP",
)
index_params.add_index(
field_name="summary_sparse_vector",
index_type="SPARSE_INVERTED_INDEX",
metric_type="IP",
)
index_params.add_index(
field_name="publish_ts",
index_type="INVERTED",
)
После настройки и применения параметров индекса Milvus оптимизируется для обработки сложных запросов к векторным и скалярным данным. Такое индексирование повышает производительность и точность поиска по сходству в коллекции, позволяя эффективно извлекать статьи, основанные на векторах изображений и суммарных векторах. Благодаря использованию AUTOINDEX
для плотных векторов, SPARSE_INVERTED_INDEX
для разреженных векторов и INVERTED_INDEX
для скаляров, Milvus может быстро определять и возвращать наиболее релевантные результаты, значительно повышая общий пользовательский опыт и эффективность процесса поиска данных.
Существует множество типов индексов и метрик. Для получения дополнительной информации о них вы можете обратиться к разделам Тип индекса Milvus и Тип метрики Milvus.
Создание коллекции
Определив схему и индексы, мы создаем "коллекцию" с этими параметрами. Коллекция для Milvus - это как таблица для реляционной БД.
client.create_collection(
collection_name=collection_name,
schema=schema,
index_params=index_params,
)
Мы можем проверить, что коллекция была успешно создана, описав ее.
collection_desc = client.describe_collection(
collection_name=collection_name
)
print(collection_desc)
Другие соображения
Загрузка индекса
При создании коллекции в Milvus вы можете выбрать загрузку индекса сразу или отложить ее до массового ввода данных. Как правило, вам не нужно делать явный выбор, так как приведенные выше примеры показывают, что индекс автоматически создается для всех поступающих данных сразу после создания коллекции. Это обеспечивает немедленный поиск по поступившим данным. Однако если после создания коллекции выполняется большая массовая вставка и поиск данных не требуется до определенного момента, можно отложить построение индекса, опустив index_params в создании коллекции, и построить индекс, вызвав load явно после того, как будут получены все данные. Этот метод более эффективен для построения индекса на большой коллекции, но поиск не может быть выполнен до вызова load().
Как определить модель данных для нескольких арендаторов
Концепция нескольких арендаторов обычно используется в сценариях, когда одно программное приложение или сервис должны обслуживать несколько независимых пользователей или организаций, каждая из которых имеет свою собственную изолированную среду. Это часто встречается в облачных вычислениях, приложениях SaaS (Software as a Service) и системах баз данных. Например, в облачном сервисе хранения данных может использоваться многопользовательский подход, позволяющий разным компаниям хранить и управлять своими данными отдельно, используя при этом одну и ту же базовую инфраструктуру. Такой подход позволяет максимально эффективно использовать ресурсы, обеспечивая при этом безопасность и конфиденциальность данных для каждого арендатора.
Самый простой способ разграничить арендаторов - изолировать их данные и ресурсы друг от друга. Каждый арендатор либо имеет эксклюзивный доступ к определенным ресурсам, либо использует ресурсы совместно с другими для управления такими сущностями Milvus, как базы данных, коллекции и разделы. Для реализации многопользовательского режима Milvus существуют специальные методы, согласованные с этими сущностями. Для получения дополнительной информации вы можете обратиться к странице Milvus multi-tenancy.