CREATE DICTIONARY ... LAYOUT RegexpTree
CREATE DICTIONARY ... LAYOUT RegexpTree
regexp_tree 딕셔너리는 계층적 정규 표현식 패턴을 기반으로 키를 값에 매핑할 수 있게 해줘요. 정확한 키 매칭보다는 패턴 매칭 조회(예: 사용자 에이전트 문자열을 정규식 패턴 매칭으로 분류)에 최적화되어 있어요.
출처: 문서
본문
Overview
regexp_tree 딕셔너리는 계층적 정규 표현식 패턴을 기반으로 키를 값에 매핑할 수 있게 해줘요.
정확한 키 매칭보다는 패턴 매칭 조회(예: 사용자 에이전트 문자열을 정규식 패턴 매칭으로 분류)에 최적화되어 있어요.
Use the regular expression tree dictionary with YAMLRegExpTree source
정규 표현식 트리 딕셔너리는 정규 표현식 트리를 담은 YAML 파일의 경로가 제공되는 YAMLRegExpTree 소스를 사용하여 ClickHouse 오픈소스에서 정의됩니다.
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속성은 두 번째 노드의 자식 노드가 제공합니다.
속성의 값은 일치한 정규 표현식의 캡처 그룹을 참조하는 역참조(back reference)를 포함할 수 있어요. 예시에서 첫 노드의 version 속성 값은 정규 표현식의 캡처 그룹 (\d+[\.\d]*)에 대한 역참조 \1로 구성됩니다. 역참조 번호는 1부터 9까지이며 $1 또는 \1(번호 1의 경우)로 작성됩니다. 역참조는 쿼리 실행 중에 일치한 캡처 그룹으로 대체돼요.
- child nodes: 정규 표현식 트리 노드의 자식 목록으로, 각각 고유한 속성과 (잠재적으로) 자식 노드를 가져요. 문자열 매칭은 깊이 우선(depth-first) 방식으로 진행됩니다. 문자열이 정규식 노드와 일치하면 딕셔너리는 그 노드의 자식 노드와도 일치하는지 확인해요. 그렇다면 가장 깊은 일치 노드의 속성이 할당됩니다. 자식 노드의 속성은 같은 이름의 부모 노드 속성을 덮어씁니다. YAML 파일에서 자식 노드의 이름은 임의일 수 있어요(예: 위 예시의
versions).
정규식 트리 딕셔너리는 함수 dictGet, dictGetOrDefault, dictGetAll로만 접근할 수 있어요. 예를 들어:
SELECT dictGet('regexp_dict', ('name', 'version'), '31/tclwebkit1024');
┌─dictGet('regexp_dict', ('name', 'version'), '31/tclwebkit1024')─┐
│ ('Android','12') │
└─────────────────────────────────────────────────────────────────┘
이 경우, 먼저 최상위 레벨의 두 번째 노드에서 정규 표현식 \d+/tclwebkit(?:\d+[\.\d]*)을 매칭해요.
딕셔너리는 그다음 자식 노드를 계속 살펴보고 문자열이 3[12]/tclwebkit과도 일치함을 발견합니다.
그 결과 name 속성의 값은 Android(첫 레이어에서 정의)이고 version 속성의 값은 12(자식 노드에서 정의)입니다.
정교한 YAML 구성 파일을 사용하면 정규식 트리 딕셔너리를 사용자 에이전트 문자열 파서로 사용할 수 있어요. ClickHouse는 uap-core를 지원하며, 기능 테스트 02504_regexp_dictionary_ua_parser에서 사용하는 방법을 볼 수 있어요.
Collecting attribute values
리프 노드의 값뿐만 아니라 일치한 여러 정규 표현식의 값을 반환하는 것이 유용할 때가 있어요. 이런 경우 전문화된 dictGetAll 함수를 사용할 수 있어요. 노드가 타입 T의 속성 값을 가지면 dictGetAll은 0개 이상의 값을 담은 Array(T)를 반환합니다.
기본적으로 키당 반환되는 일치 수는 제한이 없어요. dictGetAll의 선택적 네 번째 인자로 상한을 전달할 수 있어요. 배열은 위상(topological) 순서로 채워지는데, 즉 자식 노드가 부모 노드보다 먼저 나오고 형제 노드는 소스의 순서를 따릅니다.
예시:
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'
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;
┌─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],[]) │
└────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────┘
Matching modes
패턴 매칭 동작은 특정 딕셔너리 설정으로 수정할 수 있어요.
regexp_dict_flag_case_insensitive: 대소문자 무시 매칭을 사용해요(기본값false). 개별 표현식에서(?i)와(?-i)로 재정의할 수 있어요.regexp_dict_flag_dotall: '.'이 개행 문자를 매칭하도록 허용해요(기본값false).
Use regular expression tree dictionary in ClickHouse Cloud
YAMLRegExpTree 소스는 ClickHouse 오픈소스에서는 동작하지만 ClickHouse Cloud에서는 동작하지 않아요.
ClickHouse Cloud에서 정규식 트리 딕셔너리를 사용하려면, 먼저 ClickHouse 오픈소스에서 YAML 파일로 정규식 트리 딕셔너리를 만든 다음, dictionary 테이블 함수와 INTO OUTFILE 절을 사용해 이 딕셔너리를 CSV 파일로 덤프하세요.
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 노드의 id예요.parent_id UInt64: 노드의 부모의 id예요.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
자세한 내용은 Insert Local Files에서 확인할 수 있어요. 소스 테이블을 초기화한 후 테이블 소스로 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);