Как осуществляется управление данными в Milvus
Автор: Yihua Mo
Дата: 2019-11-08
Как осуществляется управление данными в Milvus
Прежде всего, несколько основных понятий Milvus:
- Таблица: Таблица - это набор данных, состоящий из векторов, причем каждый вектор имеет уникальный идентификатор. Каждый вектор и его ID представляют собой строку таблицы. Все векторы в таблице должны иметь одинаковые размеры. Ниже приведен пример таблицы с 10-мерными векторами:
таблица
- Индекс: Построение индекса - это процесс кластеризации векторов по определенному алгоритму, который требует дополнительного дискового пространства. Некоторые типы индексов требуют меньше места, так как они упрощают и сжимают векторы, в то время как другие типы требуют больше места, чем необработанные векторы.
В Milvus пользователи могут выполнять такие задачи, как создание таблицы, вставка векторов, построение индексов, поиск векторов, получение информации о таблице, удаление таблиц, удаление части данных в таблице и удаление индексов и т. д.
Предположим, что у нас есть 100 миллионов 512-мерных векторов, и нам нужно вставить и управлять ими в Milvus для эффективного векторного поиска.
(1) Вставка векторов
Давайте рассмотрим, как векторы вставляются в Milvus.
Поскольку каждый вектор занимает 2 КБ, минимальное пространство для хранения 100 миллионов векторов составляет около 200 ГБ, что делает нереальным однократную вставку всех этих векторов. Необходимо иметь несколько файлов данных вместо одного. Производительность вставки - один из ключевых показателей эффективности. Milvus поддерживает единовременную вставку сотен или даже десятков тысяч векторов. Например, единовременная вставка 30 тысяч 512-мерных векторов обычно занимает всего 1 секунду.
вставка
Не каждая вставка вектора загружается на диск. Для каждой создаваемой таблицы Milvus резервирует в памяти процессора буфер с изменяемыми данными, в который можно быстро записать вставленные данные. А когда данные в буфере достигнут определенного размера, это пространство будет помечено как неизменяемое. В это время будет зарезервирован новый буфер. Данные в неизменяемом буфере регулярно записываются на диск, а соответствующая память процессора освобождается. Механизм регулярной записи на диск похож на тот, что используется в Elasticsearch, который записывает буферизованные данные на диск каждые 1 секунду. Кроме того, пользователи, знакомые с LevelDB/RocksDB, могут увидеть здесь некоторое сходство с MemTable.
Цели механизма вставки данных следующие:
- Вставка данных должна быть эффективной.
- Вставленные данные могут быть использованы мгновенно.
- Файлы данных не должны быть слишком фрагментированы.
(2) Файл необработанных данных
Когда векторы записываются на диск, они сохраняются в файле Raw Data File, содержащем необработанные векторы. Как уже говорилось, векторы большого масштаба необходимо сохранять и управлять ими в нескольких файлах данных. Размер вставляемых данных варьируется: пользователь может вставить 10 векторов или 1 миллион векторов за один раз. Однако операция записи на диск выполняется раз в 1 секунду. Таким образом, генерируются файлы данных разного размера.
Фрагментированными файлами данных неудобно управлять и к ним нелегко получить доступ для векторного поиска. Milvus постоянно объединяет эти маленькие файлы данных, пока размер объединенного файла не достигнет определенного размера, например, 1 ГБ. Этот конкретный размер можно настроить в API-параметре index_file_size
при создании таблицы. Таким образом, 100 миллионов 512-мерных векторов будут распределены и сохранены примерно в 200 файлах данных.
Учитывая сценарии инкрементных вычислений, в которых векторы вставляются и ищутся одновременно, нам необходимо убедиться, что после записи векторов на диск они будут доступны для поиска. Таким образом, до слияния малых файлов данных к ним можно получить доступ и выполнить поиск. После завершения слияния файлы с малыми данными будут удалены, а для поиска будут использоваться новые объединенные файлы.
Вот как выглядят запрашиваемые файлы до слияния:
rawdata1
Запрашиваемые файлы после слияния:
rawdata2
(3) Индексный файл
Поиск по файлу Raw Data File - это грубый поиск, который сравнивает расстояния между векторами запроса и исходными векторами и вычисляет k ближайших векторов. Грубый поиск неэффективен. Эффективность поиска может быть значительно увеличена, если поиск основан на индексном файле, в котором векторы индексируются. Создание индекса требует дополнительного дискового пространства и обычно занимает много времени.
Так в чем же разница между файлами сырых данных и индексными файлами? Проще говоря, в Raw Data File записывается каждый вектор вместе с его уникальным идентификатором, а в Index File - результаты кластеризации векторов, такие как тип индекса, центроиды кластеров и векторы в каждом кластере.
индексный файл
Вообще говоря, Index File содержит больше информации, чем Raw Data File, но при этом размер файлов гораздо меньше, так как векторы упрощаются и квантуются в процессе построения индекса (для определенных типов индексов).
Вновь созданные таблицы по умолчанию ищутся методом грубого вычисления. После создания индекса в системе Milvus будет автоматически строить индекс для объединенных файлов, размер которых достигает 1 ГБ, в отдельном потоке. По завершении построения индекса генерируется новый индексный файл. Необработанные файлы данных будут заархивированы для построения индекса на основе других типов индексов.
Milvus автоматически строит индекс для файлов, размер которых достигает 1 ГБ:
buildindex
Построение индекса завершено:
indexcomplete
Индекс не будет автоматически строиться для файлов необработанных данных, которые не достигают 1 ГБ, что может замедлить скорость поиска. Чтобы избежать этой ситуации, необходимо вручную принудительно построить индекс для этой таблицы.
forcebuild
После принудительного построения индекса для файла производительность поиска значительно повышается.
indexfinal
(4) Метаданные
Как упоминалось ранее, 100 миллионов 512-мерных векторов хранятся в 200 дисковых файлах. При построении индекса для этих векторов потребуется еще 200 индексных файлов, что в сумме составит 400 файлов (включая дисковые и индексные файлы). Необходим эффективный механизм для управления метаданными (статусами файлов и другой информацией) этих файлов, чтобы проверять статусы файлов, удалять или создавать файлы.
Использование баз данных OLTP для управления этой информацией является хорошим выбором. Автономный Milvus использует SQLite для управления метаданными, а в распределенном развертывании Milvus использует MySQL. При запуске сервера Milvus в SQLite/MySQL создаются 2 таблицы (а именно 'Tables' и 'TableFiles') соответственно. В 'Tables' записывается информация о таблицах, а в 'TableFiles' - информация о файлах данных и индексных файлах.
Как показано на схеме ниже, "Tables" содержит метаданные, такие как имя таблицы (table_id), размерность вектора (dimension), дата создания таблицы (created_on), статус таблицы (state), тип индекса (engine_type), а также количество кластеров вектора (nlist) и метод вычисления расстояния (metric_type).
А 'TableFiles' содержит имя таблицы, к которой принадлежит файл (table_id), тип индекса файла (engine_type), имя файла (file_id), тип файла (file_type), размер файла (file_size), количество строк (row_count) и дату создания файла (created_on).
метаданные
С помощью этих метаданных можно выполнять различные операции. Ниже приведены примеры:
- Чтобы создать таблицу, Meta Manager достаточно выполнить SQL-оператор:
INSERT INTO TABLES VALUES(1, 'table_2, 512, xxx, xxx, ...)
. - Чтобы выполнить векторный поиск в таблице_2, Meta Manager выполнит запрос в SQLite/MySQL, который де-факто является SQL-оператором:
SELECT * FROM TableFiles WHERE table_id='table_2'
для получения информации о файлах таблицы_2. Затем эти файлы будут загружены в память планировщиком запросов для вычисления поиска. - Мгновенное удаление таблицы недопустимо, так как на нее могут выполняться запросы. Поэтому существуют мягкое и жесткое удаление таблицы. При удалении таблицы она будет помечена как "мягкое удаление", и дальнейшие запросы или изменения в ней запрещены. Однако запросы, которые выполнялись до удаления, все еще будут выполняться. Только когда все эти запросы перед удалением будут завершены, таблица вместе с ее метаданными и связанными файлами будет удалена навсегда.
(5) Планировщик запросов
Приведенная ниже диаграмма демонстрирует процесс поиска векторов на CPU и GPU путем запроса файлов (файлов исходных данных и индексных файлов), которые копируются и сохраняются на диске, в памяти CPU и в памяти GPU для поиска topk наиболее похожих векторов.
topkresult
Алгоритм планирования запросов значительно повышает производительность системы. Основная философия разработки заключается в достижении наилучшей производительности поиска за счет максимального использования аппаратных ресурсов. Ниже приведено лишь краткое описание планировщика запросов, в будущем этой теме будет посвящена отдельная статья.
Первый запрос к заданной таблице мы называем "холодным" запросом, а последующие - "теплыми". При первом запросе к таблице Milvus выполняет много работы по загрузке данных в память CPU и некоторых данных в память GPU, что отнимает много времени. При последующих запросах поиск происходит гораздо быстрее, так как часть или все данные уже находятся в памяти процессора, что экономит время на чтение с диска.
Чтобы сократить время поиска при первом запросе, Milvus предлагает конфигурацию Preload Table (preload_table
), которая обеспечивает автоматическую предварительную загрузку таблиц в память процессора при запуске сервера. Для таблицы, содержащей 100 миллионов 512-мерных векторов, что составляет 200 ГБ, скорость поиска будет самой высокой, если памяти процессора достаточно для хранения всех этих данных. Однако если таблица содержит миллиарды векторов, то иногда неизбежно приходится освобождать память CPU/GPU для добавления новых данных, которые не запрашиваются. В настоящее время мы используем LRU (Latest Recently Used) в качестве стратегии замены данных.
Как показано на диаграмме ниже, предположим, что на диске хранится 6 индексных файлов. Память CPU может хранить только 3 индексных файла, а память GPU - только 1 индексный файл.
Когда начинается поиск, в память CPU загружаются 3 индексных файла для запроса. Первый файл будет освобожден из памяти CPU сразу после запроса. Тем временем в память процессора загружается четвертый файл. Точно так же, когда файл запрашивается в памяти GPU, он мгновенно освобождается и заменяется новым файлом.
Планировщик запросов в основном обрабатывает 2 набора очередей задач, одна из которых связана с загрузкой данных, а другая - с выполнением поиска.
queryschedule
(6) Редуктор результатов
Существует 2 ключевых параметра, связанных с векторным поиском: первый - 'n', означающий n количество целевых векторов; второй - 'k', означающий k наиболее похожих векторов. Результаты поиска на самом деле представляют собой n наборов KVP (пар ключ-значение), каждый из которых содержит k пар ключ-значение. Поскольку запросы должны выполняться к каждому отдельному файлу, независимо от того, является ли он файлом необработанных данных или индексным файлом, для каждого файла будет получено n наборов топ-k наборов результатов. Все эти наборы результатов объединяются, чтобы получить наборы результатов top-k для таблицы.
В примере ниже показано, как объединяются и сокращаются наборы результатов для векторного поиска по таблице с 4 индексными файлами (n=2, k=3). Обратите внимание, что каждый набор результатов имеет 2 столбца. Левый столбец представляет собой идентификатор вектора, а правый - евклидово расстояние.
результат
(7) Будущая оптимизация
Ниже приведены некоторые мысли о возможных оптимизациях управления данными.
- Что если данные в неизменяемом буфере или даже мутабельном буфере можно будет также мгновенно запрашивать? В настоящее время данные в неизменяемом буфере не могут быть запрошены, пока они не будут записаны на диск. Некоторые пользователи больше заинтересованы в мгновенном доступе к данным после их вставки.
- Предоставьте функциональность разбиения таблиц, которая позволит пользователю разделить очень большие таблицы на более мелкие разделы и выполнять векторный поиск по заданному разделу.
- Добавить к векторам некоторые атрибуты, которые можно фильтровать. Например, некоторые пользователи хотят искать только среди векторов с определенными атрибутами. Требуется получить атрибуты векторов и даже необработанные векторы. Один из возможных подходов - использование базы данных KV, например RocksDB.
- Обеспечить функциональность миграции данных, позволяющую автоматически переносить устаревшие данные в другое пространство хранения. В некоторых сценариях, где данные поступают постоянно, они могут устаревать. Поскольку некоторым пользователям важны только данные за последний месяц и они выполняют поиск по ним, старые данные становятся менее полезными, занимая много места на диске. Механизм миграции данных помогает освободить дисковое пространство для новых данных.
Резюме
В этой статье в основном представлена стратегия управления данными в Milvus. Другие статьи о распределенном развертывании Milvus, выборе методов векторного индексирования и планировщике запросов будут опубликованы в ближайшее время. Следите за новостями!
Похожие блоги
- Резюме
- Похожие блоги
On This Page
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word