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

Обзор

Словарь regexp_tree позволяет сопоставлять ключи со значениями на основе иерархии шаблонов регулярных выражений. Он оптимизирован для поиска по совпадению с шаблоном (например, для классификации строк, таких как user agent, по шаблонам регулярных выражений), а не для точного сопоставления ключей.

Использование словаря на основе дерева регулярных выражений с источником YAMLRegExpTree

В ClickHouse open-source словари на основе дерева регулярных выражений определяются с помощью источника YAMLRegExpTree, которому передаётся путь к YAML-файлу, содержащему дерево регулярных выражений.
Query
CREATE DICTIONARY regexp_dict
(
    regexp String,
    name String,
    version String
)
PRIMARY KEY(regexp)
SOURCE(YAMLRegExpTree(PATH '/var/lib/clickhouse/user_files/regexp_tree.yaml'))
LAYOUT(regexp_tree)
...
Источник словаря YAMLRegExpTree описывает структуру дерева регулярных выражений. Например:
- regexp: 'Linux/(\d+[\.\d]*).+tlinux'
  name: 'TencentOS'
  version: '\1'

- regexp: '\d+/tclwebkit(?:\d+[\.\d]*)'
  name: 'Android'
  versions:
    - regexp: '33/tclwebkit'
      version: '13'
    - regexp: '3[12]/tclwebkit'
      version: '12'
    - regexp: '30/tclwebkit'
      version: '11'
    - regexp: '29/tclwebkit'
      version: '10'
Эта конфигурация состоит из списка узлов дерева регулярных выражений. Каждый узел имеет следующую структуру:
  • regexp: регулярное выражение узла.
  • attributes: список пользовательских атрибутов словаря. В этом примере есть два атрибута: name и version. Первый узел определяет оба атрибута. Второй узел определяет только атрибут name. Атрибут version задаётся дочерними узлами второго узла.
    • Значение атрибута может содержать обратные ссылки, указывающие на группы захвата в совпавшем регулярном выражении. В примере значение атрибута version в первом узле состоит из обратной ссылки \1 на группу захвата (\d+[\.\d]*) в регулярном выражении. Номера обратных ссылок находятся в диапазоне от 1 до 9 и записываются как $1 или \1 (для номера 1). При выполнении запроса обратная ссылка заменяется соответствующей совпавшей группой захвата.
  • child nodes: список дочерних узлов узла дерева регулярных выражений, каждый из которых имеет собственные атрибуты и (потенциально) дочерние узлы. Сопоставление строк выполняется в порядке обхода в глубину. Если строка соответствует узлу regexp, словарь проверяет, соответствует ли она также его дочерним узлам. В этом случае присваиваются атрибуты самого глубокого совпавшего узла. Атрибуты дочернего узла перезаписывают одноимённые атрибуты родительских узлов. Имена дочерних узлов в YAML-файлах могут быть произвольными, например versions в приведённом выше примере.
Словарь дерева регулярных выражений поддерживает доступ только с использованием функций dictGet, dictGetOrDefault и dictGetAll. Например:
Query
SELECT dictGet('regexp_dict', ('name', 'version'), '31/tclwebkit1024');
Response
┌─dictGet('regexp_dict', ('name', 'version'), '31/tclwebkit1024')─┐
│ ('Android','12')                                                │
└─────────────────────────────────────────────────────────────────┘
В этом случае мы сначала сопоставляем регулярное выражение \d+/tclwebkit(?:\d+[\.\d]*) со вторым узлом второго уровня. Затем словарь продолжает поиск в дочерних узлах и обнаруживает, что строка также соответствует 3[12]/tclwebkit. В результате значение атрибута name равно Android (определено на первом уровне), а значение атрибута version равно 12 (определено в дочернем узле). С помощью сложного YAML-файла конфигурации вы можете использовать словарь дерева регулярных выражений как парсер строки user agent. ClickHouse поддерживает uap-core, и вы можете посмотреть, как его использовать, в функциональном тесте 02504_regexp_dictionary_ua_parser

Сбор значений атрибутов

Иногда полезно возвращать значения всех совпавших регулярных выражений, а не только значение листового узла. В таких случаях можно использовать специализированную функцию dictGetAll. Если у узла есть значение атрибута типа T, dictGetAll вернёт Array(T), содержащий ноль или более значений. По умолчанию число совпадений, возвращаемых для каждого ключа, не ограничено. Ограничение можно передать в dictGetAll как необязательный четвёртый аргумент. Массив заполняется в топологическом порядке: дочерние узлы идут перед родительскими, а узлы одного уровня следуют порядку, заданному в исходном описании. Пример:
CREATE DICTIONARY regexp_dict
(
    regexp String,
    tag String,
    topological_index Int64,
    captured Nullable(String),
    parent String
)
PRIMARY KEY(regexp)
SOURCE(YAMLRegExpTree(PATH '/var/lib/clickhouse/user_files/regexp_tree.yaml'))
LAYOUT(regexp_tree)
LIFETIME(0)
# /var/lib/clickhouse/user_files/regexp_tree.yaml
- regexp: 'clickhouse\.com'
  tag: 'ClickHouse'
  topological_index: 1
  paths:
    - regexp: 'clickhouse\.com/docs(.*)'
      tag: 'ClickHouse Documentation'
      topological_index: 0
      captured: '\1'
      parent: 'ClickHouse'

- regexp: '/docs(/|$)'
  tag: 'Documentation'
  topological_index: 2

- regexp: 'github.com'
  tag: 'GitHub'
  topological_index: 3
  captured: 'NULL'
Query
CREATE TABLE urls (url String) ENGINE=MergeTree ORDER BY url;
INSERT INTO urls VALUES ('clickhouse.com'), ('clickhouse.com/docs/en'), ('github.com/clickhouse/tree/master/docs');
SELECT url, dictGetAll('regexp_dict', ('tag', 'topological_index', 'captured', 'parent'), url, 2) FROM urls;
Response
┌─url────────────────────────────────────┬─dictGetAll('regexp_dict', ('tag', 'topological_index', 'captured', 'parent'), url, 2)─┐
│ clickhouse.com                         │ (['ClickHouse'],[1],[],[])                                                            │
│ clickhouse.com/docs/en                 │ (['ClickHouse Documentation','ClickHouse'],[0,1],['/en'],['ClickHouse'])              │
│ github.com/clickhouse/tree/master/docs │ (['Documentation','GitHub'],[2,3],[NULL],[])                                          │
└────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────┘

Режимы сопоставления

Поведение сопоставления с шаблоном можно изменять с помощью некоторых настроек словаря:
  • regexp_dict_flag_case_insensitive: использовать регистронезависимое сопоставление (по умолчанию false). Можно переопределить в отдельных выражениях с помощью (?i) и (?-i).
  • regexp_dict_flag_dotall: разрешить символу . соответствовать символам новой строки (по умолчанию false).

Использование словаря на основе дерева регулярных выражений в ClickHouse Cloud

Источник YAMLRegExpTree поддерживается в ClickHouse Open Source, но не в ClickHouse Cloud. Чтобы использовать словари на основе дерева регулярных выражений в ClickHouse Cloud, сначала создайте словарь на основе дерева регулярных выражений из YAML-файла в локальной установке ClickHouse Open Source, затем выгрузите этот словарь в CSV-файл с помощью табличной функции dictionary и оператора INTO OUTFILE.
SELECT * FROM dictionary(regexp_dict) INTO OUTFILE('regexp_dict.csv')
Содержимое CSV-файла:
1,0,"Linux/(\d+[\.\d]*).+tlinux","['version','name']","['\\1','TencentOS']"
2,0,"(\d+)/tclwebkit(\d+[\.\d]*)","['comment','version','name']","['test $1 and $2','$1','Android']"
3,2,"33/tclwebkit","['version']","['13']"
4,2,"3[12]/tclwebkit","['version']","['12']"
5,2,"3[12]/tclwebkit","['version']","['11']"
6,2,"3[12]/tclwebkit","['version']","['10']"
Схема файла дампа:
  • id UInt64: идентификатор узла RegexpTree.
  • parent_id UInt64: идентификатор родительского узла.
  • regexp String: строка регулярного выражения.
  • keys Array(String): имена пользовательских атрибутов.
  • values Array(String): значения пользовательских атрибутов.
Чтобы создать словарь в ClickHouse Cloud, сначала создайте таблицу regexp_dictionary_source_table со структурой, приведённой ниже:
CREATE TABLE regexp_dictionary_source_table
(
    id UInt64,
    parent_id UInt64,
    regexp String,
    keys   Array(String),
    values Array(String)
) ENGINE=Memory;
Затем обновите локальный CSV следующим образом:
clickhouse client \
    --host MY_HOST \
    --secure \
    --password MY_PASSWORD \
    --query "
    INSERT INTO regexp_dictionary_source_table
    SELECT * FROM input ('id UInt64, parent_id UInt64, regexp String, keys Array(String), values Array(String)')
    FORMAT CSV" < regexp_dict.csv
Подробнее см. в разделе Вставка локальных файлов. После инициализации исходной таблицы мы можем создать RegexpTree на основе исходной таблицы:
CREATE DICTIONARY regexp_dict
(
    regexp String,
    name String,
    version String
PRIMARY KEY(regexp)
SOURCE(CLICKHOUSE(TABLE 'regexp_dictionary_source_table'))
LIFETIME(0)
LAYOUT(regexp_tree);
Последнее изменение 10 июня 2026 г.