Каждая коллекция данных разделена на сегменты. У каждого сегмента есть независимое векторное хранилище, хранилище полезной нагрузки и индекс.

Данные в сегментах обычно не пересекаются. Однако сохранение одной и той же точки в разных сегментах не вызывает проблем, поскольку поиск содержит механизм дедупликации.

Сегменты включают в себя векторное хранилище, хранилище полезной нагрузки, векторный индекс, индекс полезной нагрузки и отображение идентификаторов для хранения связи между внутренними и внешними идентификаторами.

Сегменты могут быть "добавляемыми" или "недобавляемыми" в зависимости от типа используемого хранилища и индекса. Вы можете свободно добавлять, удалять и запрашивать данные в "добавляемых" сегментах, в то время как в "недобавляемых" сегментах можно только читать и удалять данные.

Конфигурация сегментов в коллекции может быть разной и независимой друг от друга, но по крайней мере один сегмент должен быть "добавляемым".

Векторное хранилище

В зависимости от потребностей приложения Qdrant может использовать один из следующих вариантов хранения данных. Выбор должен сбалансировать скорость поиска и использование оперативной памяти.

Хранилище в памяти - Сохраняет все векторы в оперативной памяти, обеспечивая высочайшую скорость, так как доступ к диску требуется только во время сохранения.

Хранилище с отображением в память (memmap) - Создает виртуальное адресное пространство, связанное с файлом на диске. Отображаемые файлы не загружаются напрямую в оперативную память, а доступ к ним осуществляется с помощью кэширования страниц. Этот подход позволяет гибко использовать доступную память. При достаточном объеме оперативной памяти его скорость почти такая же быстрая, как у хранилища в памяти.

Настройка хранилища с отображением в память (memmap)

Есть два способа настроить использование отображения в память (также известного как хранение на диске):

  • Установите параметр on_disk для векторов в API создания коллекции:

Применяется только к версии v1.2.0 и выше

PUT /collections/{collection_name}

{
    "vectors": {
      "size": 768,
      "distance": "Cosine",
      "on_disk": true
    }
}

Это создаст коллекцию, которая немедленно сохраняет все векторы в хранилище с отображением в память. Это рекомендуемый подход, когда экземпляр Qdrant использует быстрые диски и нужно обрабатывать большие коллекции.

  • Установите параметр memmap_threshold_kb. Этот параметр устанавливает порог для преобразования сегментов в хранилище с отображением в память.

Есть два способа реализации этого:

  1. Установите порог глобально в файле конфигурации. Имя параметра - memmap_threshold_kb.
  2. Установите порог индивидуально для каждой коллекции при создании или обновлении.
PUT /collections/{collection_name}

{
    "vectors": {
      "size": 768,
      "distance": "Cosine"
    },
    "optimizers_config": {
        "memmap_threshold": 20000
    }
}

Правило установки параметра порога memmap простое:

  • Если сценарий использования сбалансирован - установите порог memmap таким же, как у indexing_threshold (по умолчанию 20000). В этом случае оптимизатор не выполнит никаких дополнительных запусков и оптимизирует все пороговые значения сразу.
  • Если нагрузка на запись высока, а оперативной памяти мало - установите порог memmap ниже, чем у indexing_threshold, например 10000. В этом случае оптимизатор сначала преобразует сегменты в хранилище с отображением в память, а затем выполнит индексацию.

Кроме того, отображаемое хранилище можно использовать не только для векторов, но также для индексов HNSW. Чтобы включить эту функцию, установите параметр hnsw_config.on_disk в true при создании коллекции.

PUT /collections/{collection_name}

{
    "vectors": {
      "size": 768,
      "distance": "Cosine"
    },
    "optimizers_config": {
        "memmap_threshold": 20000
    },
    "hnsw_config": {
        "on_disk": true
    }
}

Хранение данных

Qdrant поддерживает два типа хранения данных: InMemory и OnDisk.

Хранение данных InMemory организует данные payload таким же образом, как и вектора в памяти. Данные payload загружаются в память при запуске сервиса, в то время как на диске и RocksDB используются только для постоянного хранения. Этот тип хранения очень быстр, но может потребовать большого объема памяти для хранения всех данных, особенно если payload включает в себя большие значения (такие как текстовые сводки или даже изображения).

Для больших значений payload предпочтительно использовать хранение данных OnDisk. Этот тип хранения напрямую считывает и записывает payload в RocksDB, тем самым не требуя большого объема памяти для хранения. Однако, есть недостаток в виде задержки доступа. Если вам необходимо запросить векторы на основе условий payload, проверка значений, хранящихся на диске, может занять слишком много времени. В этом случае мы рекомендуем создать индекс payload для каждого поля, используемого для фильтрационных условий, чтобы избежать доступа к диску. После создания индекса поля Qdrant всегда будет держать все значения индексированного поля в памяти, независимо от типа хранения payload.

Вы можете указать желаемый тип хранения payload через файл конфигурации или используя параметр коллекции on_disk_payload при создании коллекции.

Контроль версий

Для обеспечения целостности данных Qdrant выполняет все изменения данных в двух этапах. Сначала данные записываются в журнал транзакций (WAL), который сортирует и присваивает последовательные номера всем операциям.

Как только изменения добавлены в WAL, они не теряются даже в случае сбоя питания. Затем изменения попадают в сегмент. Каждый сегмент хранит последнюю версию примененных к нему изменений, а также версию каждой отдельной точки. Если последовательный номер нового изменения меньше текущей версии точки, обновление будет игнорироваться. Этот механизм позволяет Qdrant эффективно восстанавливать хранение данных из WAL в случае аварийного выключения.