Indexing¶
AkasicDB text search 인덱스는 PostgreSQL의 CREATE INDEX ... USING texton 문으로 정의합니다. 이 페이지의 SQL은 AkasicDB text search 기능을 사용할 수 있는 데이터베이스에서 실행합니다.
Note
USING texton 인덱스는 대상 데이터베이스에서 확장이 활성화되어 있어야 합니다. 자동 배치 커밋 등 background worker 기능을 함께 쓰려면 서버가 shared_preload_libraries에 등록된 상태여야 합니다. 자세한 내용은 Operations에서 다룹니다.
공통 예제 테이블을 만듭니다.
Whole-Row 인덱스¶
행 전체를 대상으로 검색하려면 whole-row 표현식 인덱스를 만듭니다. @@ 검색 연산자는 whole-row 좌변을 사용하므로, docs @@ ... 형태의 검색에는 이 인덱스가 필요합니다.
CREATE INDEX docs_texton_idx
ON docs
USING texton ((docs.*))
WITH (mapping='{"fields":{"title":{"type":"text"},"body":{"type":"text"}}}');
필드 매핑은 필수입니다. WITH (mapping='...')을 생략하거나 fields를 비워 두면 CREATE INDEX가 거부됩니다. 매핑 문법은 필드 매핑에서 다룹니다.
CREATE INDEX 시점에 이미 테이블에 있는 행은 즉시 초기 색인됩니다.
필드 매핑¶
필드별 타입·analyzer·tokenizer·사전과 정렬·집계 대상 여부는 인덱스 옵션 WITH (mapping='{...}')의 JSON으로 선언합니다. analyzer를 지정하지 않은 text 필드는 언어 중립 standard analyzer로 색인됩니다. tokenizer와 사전 선택은 Tokenization에서 다룹니다.
이 페이지의 예제는 docs_texton_idx라는 한 이름을 재사용합니다. 위에서부터 순서대로 실행할 수 있도록 두 번째 예제부터는 DROP INDEX IF EXISTS를 앞에 둡니다.
DROP INDEX IF EXISTS docs_texton_idx;
CREATE INDEX docs_texton_idx
ON docs
USING texton ((docs.*))
WITH (mapping='{"fields":{
"title":{"type":"text","analyzer":{"tokenizer":{"lindera":{"dictionary":"ko-dic"}}}},
"body":{"type":"text","analyzer":{"tokenizer":{"lindera":{"dictionary":"ko-dic"}}}}
}}');
| 매핑 키 | 설명 |
|---|---|
type |
필드 타입입니다. text, 정수/실수, timestamptz 등 색인 대상 값의 타입을 지정합니다. |
analyzer |
text 필드의 tokenizer와 사전을 지정합니다. 생략하면 standard로 색인됩니다. |
fast |
정렬·집계 대상 필드로 선언합니다. akasicdb.text_search()의 정렬 키나 akasicdb.text_aggregate()의 집계 필드는 fast여야 합니다. 정렬 키는 타입 제약이 하나 더 붙습니다(Fast 필드). |
stored |
하이라이트가 스니펫을 만들 수 있도록 원본 필드 값을 보관합니다. akasicdb.text_highlight()에 쓰는 필드는 stored여야 합니다. |
Warning
필드 매핑은 인덱스를 만든 뒤 in-place로 변경되지 않습니다. 매핑을 바꾸려면 인덱스를 다시 만들어야 합니다(사전 갱신 반영은 REINDEX). 자세한 내용은 Tokenization의 재색인 절을 참고하십시오.
Fast 필드¶
정렬이나 집계에 사용할 필드는 매핑에서 fast로 선언합니다. fast가 아닌 필드는 akasicdb.text_search()의 정렬 키나 akasicdb.text_aggregate()의 대상 필드로 쓸 수 없습니다.
정렬 키에는 타입 제약이 하나 더 있습니다. 정렬은 정수(i64 / u64)·실수(f64)·bool·date 타입만 지원하므로, text와 keyword 필드는 fast로 선언해도 정렬 키로 쓸 수 없습니다. 집계에는 이 제약이 없습니다.
형태소 분석된 text 필드는 토큰 단위로 색인되므로 그 자체로는 terms 집계 키가 될 수 없습니다. title을 그대로 집계하면 제목이 아니라 형태소가 집계됩니다. 분석하지 않은 keyword 서브필드를 함께 선언하고, 해당 서브필드를 fast로 지정하십시오. 서브필드는 점 표기로 참조합니다(title.raw).
DROP INDEX IF EXISTS docs_texton_idx;
CREATE INDEX docs_texton_idx
ON docs
USING texton ((docs.*))
WITH (mapping='{"fields":{
"title":{"type":"text",
"analyzer":{"tokenizer":{"lindera":{"dictionary":"ko-dic"}}},
"fields":{"raw":{"type":"keyword","fast":true}}},
"body":{"type":"text",
"analyzer":{"tokenizer":{"lindera":{"dictionary":"ko-dic"}}},
"stored":true}
}}');
이 매핑에서 title은 형태소 분석되어 검색되고, title.raw는 제목 전체를 분석하지 않은 하나의 term으로 보관해 집계에 쓰입니다. body는 하이라이트가 스니펫을 만들 수 있도록 stored로 선언했습니다.
다중 컬럼 인덱스¶
whole-row 표현식 대신 특정 컬럼만 색인하려면 컬럼을 나열합니다. 컬럼별 매핑은 whole-row 인덱스와 동일하게 mapping으로 선언합니다.
CREATE INDEX docs_title_body_texton_idx
ON docs
USING texton (title, body)
WITH (mapping='{"fields":{
"title":{"type":"text","analyzer":{"tokenizer":{"lindera":{"dictionary":"ko-dic"}}}},
"body":{"type":"text","analyzer":{"tokenizer":{"lindera":{"dictionary":"ko-dic"}}}}
}}');
한 컬럼만 색인하면 되는 경우에도 같은 방식으로 나열합니다.
CREATE INDEX docs_body_texton_idx
ON docs
USING texton (body)
WITH (mapping='{"fields":{
"body":{"type":"text","analyzer":{"tokenizer":{"lindera":{"dictionary":"ko-dic"}}}}
}}');
컬럼 나열 인덱스는 @@가 요구하는 whole-row 좌변을 제공하지 않으므로, docs @@ ... 형태의 검색에는 위의 whole-row 인덱스가 여전히 필요합니다.
파티션 테이블¶
파티션 테이블의 부모에는 컬럼 나열 인덱스만 정의할 수 있습니다. 부모 인덱스는 각 leaf 파티션으로 팬아웃되어 파티션마다 인덱스가 만들어집니다.
이 절의 예제 테이블입니다.
CREATE TABLE docs_part (
id bigint,
title text,
body text
) PARTITION BY RANGE (id);
CREATE TABLE docs_part_p1 PARTITION OF docs_part FOR VALUES FROM (1) TO (1000);
CREATE TABLE docs_part_p2 PARTITION OF docs_part FOR VALUES FROM (1000) TO (2000);
CREATE INDEX docs_part_texton_idx
ON docs_part
USING texton (body)
WITH (mapping='{"fields":{
"body":{"type":"text","analyzer":{"tokenizer":{"lindera":{"dictionary":"ko-dic"}}}}
}}');
whole-row 표현식은 부모에 쓸 수 없습니다. 부모에 USING texton ((docs_part.*))를 시도하면 cannot convert whole-row table reference 오류로 거부됩니다. 파티션 테이블에 @@ 검색이 필요하면 leaf 파티션마다 whole-row 인덱스를 만들고, 부모가 아니라 leaf를 좌변으로 검색하십시오.