Перейти к основному содержимому
Перейти к основному содержимому

Полнотекстовый поиск с использованием полнотекстовых индексов

Experimental feature. Learn more.
Not supported in ClickHouse Cloud

Полнотекстовые индексы — это экспериментальный тип вторичных индексов, которые обеспечивают быстрые возможности поиска по тексту для String или FixedString столбцов. Основная идея полнотекстового индекса заключается в том, чтобы хранить отображение от "терминов" к строкам, которые содержат эти термины. "Термины" — это токенизированные ячейки строкового столбца. Например, строковая ячейка "Я немного опоздаю" по умолчанию токенизируется на шесть терминов "Я", "немного", "опоздаю". Другой вид токенизатора — n-grams. Например, результат токенизации 3-граммами будет 21 термин "Я н", " н", "не", "е", "ем", "м ", " о", "о п", " п", "по", "о ", "н", "н", " н", "н", "н", "н". Чем более тонко токенизируются входные строки, тем больше, но также и более полезный будет результативный полнотекстовый индекс.

примечание

Полнотекстовые индексы являются экспериментальными и не должны использоваться в производственных средах. Они могут измениться в будущем с несовместимыми изменениями, например, в отношении их синтаксиса DDL/DQL или характеристик производительности/сжатия.

Использование

Чтобы использовать полнотекстовые индексы, сначала включите их в конфигурации:

Полнотекстовый индекс может быть определен для строкового столбца с использованием следующего синтаксиса:

примечание

В более ранних версиях ClickHouse соответствующее название типа индекса было inverted.

где N указывает на токенизатор:

  • full_text(0) (или короче: full_text()) устанавливает токенизатор на "токены", т.е. разбивает строки по пробелам,
  • full_text(N) с N от 2 до 8 устанавливает токенизатор на "ngrams(N)"

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

  • full_text(ngrams, max_rows_per_postings_list): Используйте данный max_rows_per_postings_list (при условии, что он не равен 0)
  • full_text(ngrams, 0): Без ограничения максимального числа строк в списке публикаций
  • full_text(ngrams): Используйте значение по умолчанию, максимальное количество строк, которое равно 64K.

Будучи типом пропуска индекса, полнотекстовые индексы могут быть удалены или добавлены к столбцу после создания таблицы:

Чтобы использовать индекс, не требуются специальные функции или синтаксис. Типичные предикаты поиска строк автоматически используют индекс. В качестве примеров рассмотрим:

Полнотекстовый индекс также работает со столбцами типа Array(String), Array(FixedString), Map(String) и Map(String).

Как и для других вторичных индексов, каждая часть столбца имеет свой собственный полнотекстовый индекс. Более того, каждый полнотекстовый индекс внутренне делится на "сегменты". Наличие и размер сегментов обычно не прозрачны для пользователей, но размер сегмента определяет потребление памяти во время создания индекса (например, когда сливаются две части). Параметр конфигурации "max_digestion_size_per_segment" (по умолчанию: 256 МБ) контролирует количество прочитанных данных из основного столбца перед созданием нового сегмента. Увеличение этого параметра повышает промежуточное потребление памяти при создании индекса, но также улучшает производительность поиска, поскольку в среднем необходимо проверять меньшее количество сегментов для выполнения запроса.

Полнотекстовый поиск по набору данных Hacker News

Давайте рассмотрим улучшения производительности полнотекстовых индексов на большом наборе данных с множеством текста. Мы будем использовать 28,7 млн строк комментариев на популярном сайте Hacker News. Вот таблица без полнотекстового индекса:

28,7 млн строк находятся в файле Parquet в S3 — давайте вставим их в таблицу hackernews:

Рассмотрим следующий простой поиск термина ClickHouse (и его различные варианты верхнего и нижнего регистра) в столбце comment:

Обратите внимание, что выполнение запроса занимает 3 секунды:

Мы используем ALTER TABLE и добавляем полнотекстовый индекс на строчные буквы столбца comment, затем материализуем его (что может занять некоторое время — подождите, пока он не материализуется):

Мы выполняем тот же запрос...

...и замечаем, что запрос выполняется в 4 раза быстрее:

Мы также можем искать один или все несколько терминов, т.е. дизъюнкции или конъюнкции:

примечание

В отличие от других вторичных индексов, полнотекстовые индексы (пока) отображаются на номера строк (ID строк), а не на ID гранул. Причина этой разработки — производительность. На практике пользователи часто ищут несколько терминов одновременно. Например, предикат фильтрации WHERE s LIKE '%little%' OR s LIKE '%big%' может быть оценен напрямую, используя полнотекстовый индекс, формируя объединение списков ID строк для терминов "little" и "big". Это также означает, что параметр GRANULARITY, указанный при создании индекса, не имеет значения (он может быть удален из синтаксиса в будущем).