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

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

Experimental feature. Learn more.
Not supported in ClickHouse Cloud

Полнотекстовые индексы - это экспериментальный тип вторичных индексов, который предоставляет быстрые возможности текстового поиска для колонок String или FixedString. Основная идея полнотекстового индекса заключается в хранении соответствия от "терминов" к строкам, которые содержат эти термины. "Термины" представляют собой токенизированные ячейки строковой колонки. Например, ячейка строки "Я немного опоздаю" по умолчанию токенизируется на шесть терминов: "Я", "немного", "опоздаю". Другой вид токенизатора - это n-граммы. Например, результат токенизации 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.7M строк комментариев на популярном сайте Hacker News. Вот таблица без полнотекстового индекса:

28.7M строк находятся в файле Parquet в S3 - давайте вставим их в таблицу hackernews:

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

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

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

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

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

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

примечание

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