Основы индексов Manticore

В этой статье мы обсуждаем введение в индексы Manticore.

Manticore Search поддерживает два типа индексов:

  • простой (также называемый оффлайн или дисковым) индекс. Данные индексируются один раз при создании, он поддерживает онлайн перестройку и онлайн обновления для не текстовых атрибутов

  • индекс RealTime. Похож на таблицу базы данных, онлайн обновления возможны в любое время

Кроме того, специальный индекс на основе типа RealTime, называемый percolate, может использоваться для хранения <span class="std std-ref">Запросов перколяции</span> .

В текущей версии индексы используют схему, как в обычной таблице базы данных. Схема может иметь 3 больших типа столбцов:

  • первый столбец всегда является беззнаковым 64-битным ненулевым числом, называемым id. В отличие от базы данных, здесь нет механизма автоинкремента, поэтому необходимо убедиться, что идентификаторы документов уникальны

  • полнотекстовые поля - они содержат индексируемый контент. В индексе может быть несколько полнотекстовых полей. Полнотекстовые поиски могут выполняться по всем полям или выборочно. В настоящее время оригинальный текст не хранится, если требуется показать его содержимое в результатах поиска, необходимо обратиться к исходному источнику, используя идентификаторы (или другой идентификатор), предоставленные результатом поиска

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

Следующие типы данных могут храниться в атрибутах:

  • беззнаковые 32-битные и знаковые 64-битные целые числа

  • 32-битные числа с плавающей запятой одинарной точности

  • временные метки UNIX

  • булевы значения

  • строки

  • объекты JSON

  • список атрибутов с несколькими значениями беззнаковых 32-битных целых чисел или знаковых 64-битных целых чисел

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

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

Простые индексы


За исключением числовых (включая MVA) атрибутов, остальные данные в простом индексе неизменяемы. Если вам нужно обновить/добавить новые записи, вам нужно снова выполнить перестройку. Пока индекс перестраивается, существующий индекс все еще доступен для обработки запросов. Когда новая версия готова, выполняется процесс, называемый rotation, который ставит новую версию в онлайн и отбрасывает старую.

Производительность индексации зависит от нескольких факторов:

  • насколько быстро источник может предоставлять данные

  • настройки токенизации

  • аппаратные ресурсы (мощность ЦП, скорость хранения)

В самом простом сценарии использования мы бы использовали один простой индекс, который мы перестраиваем время от времени.

Это подразумевает:

  • индекс не так свеж, как данные из источника

  • продолжительность индексации увеличивается с объемом данных

Если мы хотим, чтобы данные были более свежими, нам нужно сократить интервал индексации. Если индексация занимает слишком много времени, это может даже пересекаться с временем между индексациями, что является серьезной проблемой. Однако Manticore Search может выполнять поиск по нескольким индексам. Из этого родилась идея использовать вторичный индекс, который захватывает только самые последние обновления.

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

Это можно сделать либо повторной индексацией основного индекса, либо объединением дельты с основным. Схема основного+дельта индекса подробно описана в <span class="std std-ref">Обновления дельта индекса</span> .

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

Для этого есть опция, которая позволяет определить список идентификаторов документов, которые подавляются дельта-индексом. Для получения дополнительной информации смотрите <span class="std std-ref">sql_query_killlist</span> .

Индексы Real-Time


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

Индекс RealTime начинается пустым, и вы можете добавлять, заменять, обновлять или удалять данные так же, как для таблицы базы данных. Обновления сначала хранятся в области памяти (называемой RAM chunk), определяемой <span class="std std-ref">rt_mem_limit</span> . Когда это заполняется, оно сбрасывается как диск-чанк - структура которого похожа на простой индекс. По мере увеличения количества диск-чанков производительность поиска снижается, так как поиск выполняется последовательно по чанкам. Чтобы преодолеть это, чанки необходимо объединить в один, что делается с помощью команды <span class="std std-ref">OPTIMIZE INDEX</span> .

The RAM chunk can be also be force to discard on disk with FLUSH RAMCHUNK . Лучшие показатели производительности RT индекса достигаются после сброса RAM chunk и оптимизации индекса - RT индекс будет иметь все данные в одном фрагменте и будет иметь такую же производительность, как обычный индекс.

Заполнение RealTime может быть выполнено двумя способами: отправка INSERT или конвертация обычного индекса в RealTime. Существующие данные могут быть вставлены по одной записи за раз или путем пакетной вставки нескольких записей в одну вставку. Несколько параллельных рабочих процессов, которые вставляют данные, ускорят процесс, но будет использоваться больше ЦП.

Размер RAM chunk влияет на скорость обновлений, больший RAM chunk обеспечит лучшую производительность, но его необходимо подбирать в зависимости от доступной памяти. Также следует отметить, что rt_mem_limit ограничивает только размер RAM chunk. Дисковые фрагменты (которые в значительной степени являются обычным индексом) будут иметь свои собственные требования к памяти (для загрузки словаря или атрибутов).

Содержимое RAM chunk записывается на диск во время чистого завершения работы или периодически, что определяется директивой rt_flush_period (это можно принудительно выполнить с помощью команды FLUSH RTINDEX). RT индекс также может использовать бинарное логирование для записи изменений. Бинлог может быть воспроизведен при запуске демона для восстановления после некорректного завершения работы и очищается после сброса RAM chunk на диск.

Стратегия сброса бинлога strategy (аналогично innodb_flush_log_at_trx_commit в MySQL) может повлиять на производительность. Бинлог также может быть отключен (установив пустой путь бинлога), но это оставляет без защиты обновления, которые еще не были сброшены на диск.

Локальные распределенные индексы


Распределенный индекс в Manticore Search не содержит никаких данных. Вместо этого он действует как «главный узел», чтобы отправить запрашиваемый запрос на другие индексы и предоставить объединенные результаты из ответов, которые он получает от «узловых» индексов. Распределенный индекс может подключаться к локальным индексам или индексам, расположенным на других серверах. В нашем случае распределенный индекс будет выглядеть так:

index_dist {
  type = distributed
  local = index1
  local = index2
  ...
 }

Последний шаг для включения многопроцессорного поиска - это определить dist_threads в разделе searchd. Dist_threads сообщает движку максимальное количество потоков, которые он может использовать для распределенного индекса.

Удаленные распределенные индексы и высокая доступность


index mydist {
          type = distributed
          agent = box1:9312:shard1
          agent = box2:9312:shard2
          agent = box3:9312:shard3
          agent = box4:9312:shard4
}

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

index mydist {
          type = distributed
          agent = box1:9312|box5:9312:shard1
          agent = box2:9312:|box6:9312:shard2
          agent = box3:9312:|box7:9312:shard3
          agent = box4:9312:|box8:9312:shard4
}

Теперь мы добавили зеркала, каждый шард находится на 2 серверах. По умолчанию мастер (экземпляр searchd с распределенным индексом) случайным образом выберет одно из зеркал.

Режим, используемый для выбора зеркал, можно установить с помощью ha_strategy. В дополнение к случайному, еще одним простым методом является выбор по кругу (ha_strategy= roundrobin).

Более интересные стратегии основаны на вероятностях с учетом задержки. noerrors и nodeads не только исключают зеркала с проблемами, но также контролируют время отклика и выполняют балансировку. Если зеркало отвечает медленнее (например, из-за выполнения некоторых операций на нем), оно будет получать меньше запросов. Когда зеркало восстанавливается и предоставляет лучшие времена, оно будет получать больше запросов.

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

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