blog-post

О колонковом хранилище в Manticore Search

Введение

В этой статье мы рассмотрим назначение колонкового хранилища Manticore, чем оно отличается от построчного хранилища и в каких случаях имеет смысл его использовать. Мы также познакомимся с основной структурой формата хранения и особенностями его интеграции в процесс обработки запросов демона поиска.

Хранение атрибутов по умолчанию (построчное)

В Manticore есть две отдельные сущности: полнотекстовые поля, которые поддерживают только полнотекстовые запросы, и атрибуты различных типов, которые могут использоваться для группировки, сортировки и фильтрации. Хранилище по умолчанию (engine='rowwise') хранит все атрибуты всех документов в памяти.

Для загрузки атрибутов в память используется mmap, который можно настроить через параметры access_plain_attrs и access_blob_attrs. Первый параметр отвечает за загрузку файлов .spa, которые содержат все атрибуты фиксированной длины (целое число, bigint, float и т.д.). Второй параметр предназначен для загрузки файлов .spb, которые содержат атрибуты переменной длины (строка, mva, float_vector и т.д.). Поскольку mmap загружает данные в память только по мере обращения к ним, первоначальные запросы с использованием атрибутов могут быть медленнее. Чтобы смягчить это, параметры 'access_plain_attrs' и 'access_blob_attrs' по умолчанию установлены в режим 'mmap_preread', в котором Manticore загружает файлы .spa и .spb в фоновом потоке при запуске. Это обычно означает (но не гарантирует), что файлы атрибутов будут в памяти, что позволяет избежать необходимости считывать данные с диска во время запросов. Однако, если система решит, что памяти недостаточно, атрибуты могут быть частично или полностью выгружены из памяти, что снова замедлит запросы. Чтобы избежать этого, можно указать 'mlock' в access_plain_attrs / access_blob_attrs. Если памяти достаточно, атрибуты будут гарантированно оставаться в памяти, и система не будет их выгружать. Однако, если памяти недостаточно, никаких гарантий нет.

Зачем нам колонковое хранилище?

В ситуациях, когда доступной памяти достаточно для хранения всех атрибутов, традиционное 'построчное' хранилище работает эффективно. Проблемы возникают, когда памяти недостаточно для всех атрибутов.
Действительно, mmap может автоматически выгружать и загружать части файлов атрибутов по мере необходимости, позволяя выполнять операции даже при ограниченной памяти. Однако на практике этот подход может значительно снизить производительность до неприемлемых уровней. Проблема частично заключается в архитектуре построчного хранилища, которое хранит все атрибуты одного документа последовательно, за которыми следуют атрибуты следующего документа и так далее. Вот пример такой таблицы данных:

Файл .spa имеет следующую структуру:

Файл .spb выглядит так:

Когда запрос включает группировку по конкретному атрибуту, необходимо извлечь только значение этого атрибута для каждого документа. Однако mmap работает таким образом, что не может читать отдельные байты; вместо этого он загружает одну или несколько страниц памяти, каждая из которых обычно имеет размер 4 КБ. Это означает, что при попытке прочитать значение одного атрибута система часто загружает значения всех соседних атрибутов, даже если они не нужны для обработки запроса.

Еще одной особенностью rowwise хранилища является отсутствие сжатия данных. Поскольку оно работает через прямой доступ к памяти, код предполагает, что готовые к использованию данные доступны немедленно. Кроме того, данные различных атрибутов в одном документе являются гетерогенными, что затрудняет эффективное сжатие одного документа. Более того, в этом формате хранения нет концепции блоков документов, которые можно было бы сжать.

Колонковое хранилище (engine='columnar') было разработано именно для ситуаций, когда недостаточно памяти для загрузки всех атрибутов. Этот формат хранения предлагает следующие преимущества:

  • Данные для каждого атрибута хранятся отдельно и могут быть прочитаны без влияния на другие атрибуты.
  • Поскольку данные внутри одного атрибута обычно однородны, можно применять сжатие.
  • Значения атрибутов могут быть разделены на блоки нескольких документов для сжатия.
  • После распаковки блоков можно применять оптимизации для потоковой обработки.
  • В оперативной памяти хранится очень небольшое количество метаданных, все остальное на диске.
  • Для быстрого доступа к горячим данным вместо загрузки страниц в память через mmap используется кэш файловой системы.

Схематически структура данных в колонковом хранилище может быть представлена следующим образом:

Колонковое хранилище поставляется в отдельной библиотеке под названием MCL (Manticore Columnar Library). Эта библиотека отвечает за создание хранилища, упаковку и чтение данных.
Кроме того, в сам демон поиска было добавлено значительное количество кода для работы с атрибутами, учитывая особенности колонкового хранилища.

Изначально демон реализовал rowwise хранилище, которое предназначено для случайного доступа к данным. Можно было бы просто заменить доступ к данным в памяти на колонковое хранилище, но сделать это, не учитывая, что колонковое хранилище предназначено для потоковой обработки и хранит данные в сжатых блоках, значительно ухудшило бы производительность.

Вот несколько примеров того, что было добавлено в демон для работы с колонковым хранилищем:

  • Колонковый сортировщик
    В архитектуре Manticore документы, найденные с помощью полнотекстового поиска, немедленно отправляются в то, что называется Сортировщиком. Сортировщик может просто сортировать или группировать документы, вычислять агрегаты и многое другое. Однако доступ к атрибутам в колонковом хранилище медленный, потому что значения извлекаются по одному.
    Если запрос относительно легкий — то есть полнотекстовый поиск быстрый или вообще отсутствует — извлечение атрибутов из хранилища по одному может значительно повлиять на производительность. Поэтому в некоторых случаях полезно использовать дополнительный сортировщик поверх стандартного Sorter. Этот дополнительный сортировщик не сортирует, а накапливает документы и извлекает колоннарные атрибуты партиями, прежде чем передать документы основному Sorter для окончательной обработки, что значительно быстрее.

  • Колоннарный группировщик
    Группировщик в Manticore отвечает за преобразование входящих документов в один или несколько ключей группировки для последующей передачи в Sorter. Основная цель колоннарного группировщика — улучшить производительность, уменьшая количество виртуальных вызовов . Например, когда работает обычный группировщик, он запрашивает данные из выражения, которое извлекает данные из хранилища. Это выражение реализовано на стороне демона и предоставляет прозрачный доступ к различным типам хранилищ атрибутов. Внутри оно использует колоннарный итератор (обсуждается ниже), реализованный на стороне библиотеки MCL, который напрямую обращается к хранилищу. Однако специализированный колоннарный группировщик знает, что будет работать только с колоннарным хранилищем и убирает некоторые абстракции, работая напрямую с колоннарным итератором.
    При группировке по строкам используется другой механизм. Когда строки добавляются в колоннарное хранилище, автоматически вычисляется и сохраняется хэш каждой строки (с учетом текущей коллации ) как отдельный целочисленный атрибут. Колоннарный группировщик извлекает эти хэши из колоннарного хранилища вместо того, чтобы читать саму строку и вычислять хэш для использования в качестве ключа группировки.

  • Аналогично, убирая колоннарное выражение, которое через колоннарный итератор извлекает значение атрибута для текущего документа, колоннарные фильтры и колоннарные агрегаты реализуются в демоне.

  • Оптимизатор запросов ( Оптимизатор на основе стоимости , CBO) также должен быть осведомлен о колоннарном хранилище. CBO определяет путь выполнения запроса. Например, он может заменить один из фильтров на поиск через соответствующий вторичный индекс, убирая фильтр из запроса. В результате вторичный индекс вернет номера документов (ID строк), по которым будут работать оставшиеся фильтры.
    Когда используется колоннарное хранилище, оптимизатор должен сравнить производительность вторичного индекса и колоннарного анализатора (который выполняет быстрый поиск по колоннарному хранилищу, подробнее об этом ниже). В зависимости от данных и количества доступных потоков иногда один метод работает быстрее другого. Например, колоннарный анализатор лучше параллелизуется.

Что включено в MCL?

Среди компонентов, которые непосредственно являются частью библиотеки MCL, можно выделить две основные группы:

1.Строитель
Ответственный за получение сырых данных от демона и построение колоннарного хранилища.

2.Доступы
Ответственные за доступ к данным. Существует два основных типа:

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

  • Анализаторы
    Значительно более быстрый метод доступа к данным. Анализаторы принимают набор фильтров в качестве входных данных и выводят номера документов (ID строк), которые удовлетворяют этим фильтрам. Они работают быстро, потому что используют все доступные метаданные колоннарного хранилища во время обработки данных и могут немедленно распаковывать и обрабатывать множество документов за один вызов. Например, они могут полностью пропустить блоки данных (без их распаковки), если минимальные и максимальные значения блока указывают на то, что желаемые значения отсутствуют.
    В демоне этот тип доступа автоматически включается на основе анализа CBO, но также может быть включен вручную через подсказки индекса; этот тип подсказки называется ColumnarScan.

Заключение

В этой статье мы в общих чертах рассмотрели принципы колоннарного хранилища Manticore и некоторые детали его интеграции в демон Manticore Search.

Установить Manticore Search

Установить Manticore Search