Querying¶
AkasicDB text search는 @@ 검색 연산자로 색인된 텍스트를 검색하고, BM25 점수로 관련도를 정렬합니다. 우변에는 문자열을 그대로 쓸 수 없으며, 반드시 akasicdb.text_query(...) 또는 질의 DSL 빌더 함수로 감쌉니다.
Note
이 페이지의 예제는 Indexing의 Fast 필드 절 매핑으로 만든 docs_texton_idx를 전제합니다. 하이라이트는 body의 stored를, 집계는 title.raw keyword 서브필드를 필요로 합니다. Tokenization의 예제를 실행했다면 그 인덱스가 같은 이름을 덮어썼으므로, Fast 필드 절의 CREATE INDEX를 다시 실행하십시오.
@@ 검색 연산자¶
@@는 whole-row 좌변과 texton.query 우변을 받습니다. akasicdb.text_query(text)는 파서 문법 문자열로 질의 값을 만듭니다.
lindera ko-dic으로 매핑한 필드는 한국어 형태소 분석되어 색인·검색됩니다. 국제공항에서는 국제 / 공항 / 에서로 분리되므로, 위 질의는 공항이 어절 안에 들어 있는 행도 찾습니다. 매핑에서 analyzer를 생략한 필드는 standard로 색인된다는 점에 유의하십시오 (자세한 내용은 Tokenization을 참고하세요).
질의 DSL¶
구조화된 질의는 texton.query를 만드는 DSL 빌더 함수로 조합합니다. 빌더는 서로 중첩할 수 있습니다.
SELECT * FROM docs
WHERE docs @@ akasicdb.text_bool(
must => ARRAY[ akasicdb.text_match('body', '공항') ],
should => ARRAY[ akasicdb.text_match_phrase('title', '도쿄 여행', 1) ],
must_not => ARRAY[ akasicdb.text_term('title', '광고') ]
);
| 빌더 | 용도 |
|---|---|
akasicdb.text_match(field, text) |
analyzer로 분석한 토큰 매치입니다. |
akasicdb.text_match_phrase(field, text, slop) |
구(phrase) 매치입니다. slop(기본값 0)으로 토큰 간 허용 간격을 지정합니다. |
akasicdb.text_term(field, value) |
분석하지 않은 정확한 term 매치입니다. |
akasicdb.text_prefix(field, text) |
접두사 매치입니다. |
akasicdb.text_wildcard(field, pattern) |
와일드카드 패턴 매치입니다. |
akasicdb.text_fuzzy(field, text, distance) |
편집 거리 기반 유사 매치입니다. distance는 기본값 1(최대 2)입니다. |
akasicdb.text_range(field, lower, upper, include_lower, include_upper) |
범위 매치입니다(int / float / timestamptz). 경계는 기본값 include_lower=true, include_upper=false입니다. |
akasicdb.text_phrase_prefix(field, text, max_expansions) |
search-as-you-type용 구 접두사 매치입니다. max_expansions는 기본값 50입니다. |
akasicdb.text_bool(must, should, must_not, minimum_should) |
must / should / must_not 절을 조합합니다. minimum_should로 매치되어야 하는 should 절 최소 개수를 지정합니다. |
akasicdb.text_boost(query, factor) |
하위 질의의 점수 가중치를 조정합니다. |
text_bool에 넘기는 절 배열은 texton.query[]이며, 위 빌더는 모두 texton.query를 반환하므로 그대로 중첩·조합됩니다.
BM25 점수¶
akasicdb.text_score(t)는 @@ 검색 스캔에서 현재 행의 BM25 점수를 반환합니다. 검색 스캔 밖에서 호출하면 ERROR가 발생합니다.
SELECT t.title, akasicdb.text_score(t) AS score
FROM docs t
WHERE t @@ akasicdb.text_query('여행')
ORDER BY akasicdb.text_score(t) DESC;
정렬 & 커서 페이지네이션¶
대량 결과의 안정적 정렬과 딥 페이지네이션에는 akasicdb.text_search() SRF를 사용합니다. 정렬 키(score 및/또는 fast 필드)와 after 커서(직전 페이지 마지막 행의 cursor)로 페이지를 넘깁니다. text_search()는 ctid를 돌려주므로 원본 테이블과 ctid로 조인합니다. limit 기본값은 10입니다.
SELECT d.title, s.rank, s.cursor
FROM akasicdb.text_search('docs_texton_idx', akasicdb.text_match('body', '공항'),
sort => ARRAY['score desc'], "limit" => 20) AS s
JOIN docs d ON d.ctid = s.ctid
ORDER BY s.rank;
다음 페이지는 직전 페이지 마지막 행의 cursor 값을 after로 전달합니다.
SELECT d.title, s.rank, s.cursor
FROM akasicdb.text_search('docs_texton_idx', akasicdb.text_match('body', '공항'),
sort => ARRAY['score desc'], "limit" => 20,
after => '<직전 페이지 마지막 cursor>') AS s
JOIN docs d ON d.ctid = s.ctid
ORDER BY s.rank;
정렬 키로 쓸 필드는 매핑에서 fast로 선언되어 있어야 하고, 타입도 정수·실수·bool·date 중 하나여야 합니다. text와 keyword 필드는 fast여도 정렬 키로 쓸 수 없습니다(Indexing).
하이라이트¶
akasicdb.text_highlight()는 검색 스캔 행에서 매치 스니펫 프래그먼트를 text[]로 반환합니다. field로 대상 필드를, max_fragments와 fragment_chars로 프래그먼트 개수와 길이를 조정합니다. 대상 필드는 매핑에서 stored로 선언되어 있어야 합니다(Indexing).
SELECT akasicdb.text_highlight(t, akasicdb.text_query('공항'), field => 'body',
max_fragments => 3, fragment_chars => 150)
FROM docs t
WHERE t @@ akasicdb.text_query('공항');
집계¶
akasicdb.text_aggregate()는 질의로 필터된 문서 집합에 ElasticSearch (ES) 스타일 집계를 실행합니다. 요청과 응답은 모두 jsonb입니다. 집계 대상 필드는 매핑에서 fast여야 합니다.
terms 집계는 분석하지 않은 필드를 대상으로 해야 합니다. 아래 예제는 Indexing에서 선언한 title.raw keyword 서브필드를 집계합니다. 분석된 title 필드를 대상으로 하면 제목이 아니라 형태소가 집계됩니다.