Pular para o conteúdo principal

Visão geral

O dicionário regexp_tree permite mapear chaves para valores com base em padrões hierárquicos de expressões regulares. Ele é otimizado para buscas por correspondência de padrões (por exemplo, classificar strings, como strings de user agent, por meio da correspondência com padrões regex) em vez de correspondência exata de chaves.

Use o dicionário de árvore regexp com a fonte YAMLRegExpTree

Os dicionários de árvore regexp são definidos no ClickHouse open-source usando a fonte YAMLRegExpTree, à qual é fornecido o caminho para um arquivo YAML que contém a árvore regexp.
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)
...
A fonte do dicionário YAMLRegExpTree representa a estrutura de uma árvore regexp. Por exemplo:
- 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'
Esta configuração consiste em uma lista de nós de árvore regexp. Cada nó tem a seguinte estrutura:
  • regexp: a expressão regular do nó.
  • attributes: uma lista de atributos de dicionário definidos pelo usuário. Neste exemplo, há dois atributos: name e version. O primeiro nó define os dois atributos. O segundo nó define apenas o atributo name. O atributo version é fornecido pelos nós filhos do segundo nó.
    • O valor de um atributo pode conter retroreferências, que se referem a grupos de captura da expressão regular correspondente. No exemplo, o valor do atributo version no primeiro nó consiste em uma retroreferência \1 ao grupo de captura (\d+[\.\d]*) na expressão regular. Os números de retroreferência variam de 1 a 9 e são escritos como $1 ou \1 (para o número 1). A retroreferência é substituída pelo grupo de captura correspondente durante a execução da consulta.
  • child nodes: uma lista de filhos de um nó de árvore regexp, cada um com seus próprios atributos e (potencialmente) nós filhos. A correspondência de strings segue uma busca em profundidade. Se uma string corresponder a um nó regexp, o dicionário verifica se ela também corresponde aos nós filhos desse nó. Se isso acontecer, os atributos do nó correspondente mais profundo serão atribuídos. Os atributos de um nó filho substituem os atributos com o mesmo nome dos nós pai. O nome dos nós filhos em arquivos YAML pode ser arbitrário, por exemplo, versions no exemplo acima.
Dicionários de árvore regexp permitem acesso apenas por meio das funções dictGet, dictGetOrDefault e dictGetAll. Por exemplo:
Query
SELECT dictGet('regexp_dict', ('name', 'version'), '31/tclwebkit1024');
Response
┌─dictGet('regexp_dict', ('name', 'version'), '31/tclwebkit1024')─┐
│ ('Android','12')                                                │
└─────────────────────────────────────────────────────────────────┘
Neste caso, primeiro encontramos correspondência para a expressão regular \d+/tclwebkit(?:\d+[\.\d]*) no segundo nó da camada superior. Em seguida, o dicionário continua a procurar nos nós filhos e descobre que a string também corresponde a 3[12]/tclwebkit. Como resultado, o valor do atributo name é Android (definido na primeira camada) e o valor do atributo version é 12 (definido no nó filho). Com um arquivo de configuração YAML sofisticado, você pode usar dicionários de árvore regexp como analisador de strings de user agent. O ClickHouse oferece suporte a uap-core e você pode ver como usá-lo no teste funcional 02504_regexp_dictionary_ua_parser

Coletando valores de atributo

Às vezes, é útil retornar valores de várias expressões regulares correspondentes, em vez de apenas o valor de um nó folha. Nesses casos, a função especializada dictGetAll pode ser usada. Se um nó tiver um valor de atributo do tipo T, dictGetAll retornará um Array(T) contendo zero ou mais valores. Por padrão, o número de correspondências retornadas por chave é ilimitado. Um limite pode ser passado como quarto argumento opcional para dictGetAll. O array é preenchido em ordem topológica, o que significa que os nós filhos vêm antes dos nós pais, e os nós irmãos seguem a ordem da fonte. Exemplo:
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],[])                                          │
└────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────┘

Modos de correspondência

O comportamento da correspondência de padrões pode ser modificado com determinadas configurações do dicionário:
  • regexp_dict_flag_case_insensitive: Usa correspondência sem diferenciar maiúsculas de minúsculas (o padrão é false). Pode ser sobrescrita em expressões individuais com (?i) e (?-i).
  • regexp_dict_flag_dotall: Permite que ’.’ corresponda a caracteres de nova linha (o padrão é false).

Usar dicionário de árvore regexp no ClickHouse Cloud

A fonte YAMLRegExpTree funciona no ClickHouse Open Source, mas não no ClickHouse Cloud. Para usar dicionários de árvore regexp no ClickHouse Cloud, primeiro crie localmente, no ClickHouse Open Source, um dicionário de árvore regexp a partir de um arquivo YAML e, em seguida, exporte esse dicionário para um arquivo CSV usando a função de tabela dictionary e a cláusula INTO OUTFILE.
SELECT * FROM dictionary(regexp_dict) INTO OUTFILE('regexp_dict.csv')
O conteúdo do arquivo 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']"
O esquema do arquivo exportado é:
  • id UInt64: o ID do nó RegexpTree.
  • parent_id UInt64: o ID do nó pai.
  • regexp String: a expressão regular.
  • keys Array(String): os nomes dos atributos definidos pelo usuário.
  • values Array(String): os valores dos atributos definidos pelo usuário.
Para criar o dicionário no ClickHouse Cloud, primeiro crie uma tabela regexp_dictionary_source_table com a estrutura abaixo:
CREATE TABLE regexp_dictionary_source_table
(
    id UInt64,
    parent_id UInt64,
    regexp String,
    keys   Array(String),
    values Array(String)
) ENGINE=Memory;
Em seguida, atualize o CSV local com
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
Para mais detalhes, veja Inserir arquivos locais. Depois de inicializar a tabela de origem, podemos criar uma RegexpTree a partir da tabela de origem:
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);
Última modificação em 10 de junho de 2026