전문 검색
요약 Apache Doris 전문 검색은 역색인을 사용해 텍스트 컬럼을 검색 가능한 검색어로 변환하고, SQL에서 여섯 가지
MATCH_*연산자로 검색할 수 있게 합니다. 이 연산자는MATCH_ANY,MATCH_ALL,MATCH_PHRASE,MATCH_PHRASE_PREFIX,MATCH_PHRASE_EDGE,MATCH_REGEXP입니다. 인덱스를 생성할 때 토크나이저를 선택한 뒤 일반적인 SQL 쿼리를 작성하면 됩니다. Apache Doris 플래너가 조건식을 인덱스로 푸시다운하므로 별도의 검색 클러스터가 필요하지 않습니다.

Apache Doris에서 전문 검색을 사용하는 이유는 무엇인가요?
Apache Doris 전문 검색은 본격적인 텍스트 검색과 데이터 웨어하우스 분석을 하나의 엔진으로 통합하며, 토큰을 인식하는 연산자를 통해 LIKE 부분 문자열 매칭보다 훨씬 다양한 검색을 지원합니다. 대부분의 데이터 웨어하우스는 LIKE '%foo%'를 제공하면서 이를 텍스트 검색이라고 부릅니다. 만 개의 행 중 한 행을 찾는 정도라면 충분합니다. 하지만 "battery" 또는 "batteries"를 언급하는 모든 주문 메모, "connection refused"라는 구문이 포함된 모든 로그 줄, 설명이 "wireless"로 시작하는 모든 제품을 찾아야 하는 순간 한계가 드러납니다.
LIKE는 각 값을 처음부터 끝까지 바이트 단위로 읽습니다. 이 연산자는 "Running"과 "running"이 같은 단어라는 사실도, "search engine optimization"이 단순한 부분 문자열이 아니라 순서대로 나열된 세 검색어라는 사실도 알지 못합니다. 일반적인 우회 방법은 Elasticsearch를 별도로 붙이고, 두 번째 클러스터의 비용을 부담하며, 오류가 발생하기 쉬운 동기화 파이프라인을 작성하는 것입니다.
Apache Doris는 이 모든 작업을 하나의 엔진으로 통합합니다. 집계를 처리하는 바로 그 테이블이 텍스트 쿼리도 처리하며, 연산자 이름도 SQL에 자연스럽게 어울립니다.
- 부분 문자열을 찾는
LIKE는 전체 스캔으로 처리됩니다. 역색인은 텍스트 조건식을 포스팅 리스트 조회로 바꿉니다. - 입력 중 검색, 구문 검색, 토큰에 대한 정규식 검색에는
LIKE로 표현할 수 없는 매칭 의미 체계가 필요합니다. - 구조화된 조건식과 텍스트 조건식을 혼합한 쿼리(
category = 'A' AND content MATCH_ANY 'doris')도 하나의 쿼리로 계획하고 실행합니다.
Apache Doris 전문 검색이란 무엇인가요?
Apache Doris 전문 검색은 역색인을 기반으로 구축된 쿼리 기능입니다. INVERTED 인덱스를 STRING, TEXT, VARCHAR 또는 ARRAY<STRING> 컬럼에 선언하고 분석기를 선택하면, MATCH_* 연산자가 포함된 WHERE 절의 조건이 인덱스로 푸시다운됩니다. 기본 테이블은 대시보드에서 이미 쿼리하고 있는 일반 Apache Doris 테이블 그대로입니다.
주요 용어
- 분석기(파서): 원시 텍스트를 검색 가능한 검색어로 변환하는 파이프라인입니다. 기본 제공 옵션으로는
none(정확한 매칭),english,chinese,unicode,standard,icu가 있습니다. 사용자 정의 분석기는char_filter,tokenizer, 하나 이상의token_filter단계를 연결할 수 있습니다. - 검색어 쿼리: 개별 토큰을 매칭합니다.
MATCH_ANY는 검색어 간 OR 연산이고,MATCH_ALL은 검색어 간 AND 연산입니다. - 구문 쿼리: 토큰이 순서대로 인접해 있는 경우를 매칭합니다. 토큰화를 수행하지 않는 파서를 사용할 때는 인덱스에
"support_phrase" = "true"를 설정해야 합니다. score(): BM25 관련도 점수입니다. 토큰화된 인덱스,MATCH_*조건식,ORDER BY score() LIMIT N이 있을 때 사용할 수 있습니다.
Apache Doris 전문 검색은 어떻게 작동하나요?
Apache Doris 전문 검색은 쓰기 시점에 텍스트를 토큰화하고, Nereids 옵티마이저에서 각 MATCH_* 조건식을 인식한 뒤 역색인으로 푸시다운합니다. 따라서 일치하지 않는 행은 디코딩하지 않습니다. 아래 다섯 단계는 파싱, 푸시다운, 점수 계산, 구조화된 조건식과의 결합 과정을 보여 줍니다.
- 쓰기 시점에 토큰화합니다. 행이 태블릿에 저장되면 분석기가 각 텍스트 값을 검색어로 분리합니다. 역색인은 각 검색어를 포함하는 행과 해당 검색어의 위치를 기록합니다.
- 쿼리를 파싱합니다. Nereids는
MATCH_*연산자를Match,MatchAny,MatchAll,MatchPhrase,MatchPhrasePrefix,MatchPhraseEdge,MatchRegexp중 하나로 인식합니다. 각 연산자에는 쿼리 문자열 자체의 토큰화 방식을 제어하는 분석기 힌트가 포함됩니다. - 인덱스로 푸시다운합니다. BE가 일치하는 포스팅 리스트를 조회하고, 연산자에 따라 교집합이나 합집합을 구한 뒤 행 비트맵을 반환합니다. 일치하지 않는 행은 디코딩하지 않습니다.
- 요청 시 점수를 계산합니다. 쿼리에
SELECT score() ... ORDER BY score() DESC LIMIT N이 있으면 Doris가 BM25(검색어 빈도, 역문서 빈도, 길이 정규화)를 계산하고 상위 N개를 반환합니다. 이 세 요소가 없으면 조건식은 일반 필터로 동작합니다. - 자유롭게 결합합니다. 하나의 쿼리에서
MATCH_*를=,IN, 범위 필터, 조인, 집계와 함께 사용할 수 있습니다. 옵티마이저는 텍스트 조건식도 다른 조건식처럼 푸시다운 대상으로 처리합니다.
빠른 시작
CREATE TABLE articles (
id INT,
title STRING,
body STRING,
INDEX idx_body (body) USING INVERTED
PROPERTIES("parser" = "english", "support_phrase" = "true")
) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1;
INSERT INTO articles VALUES
(1, 'Doris 4.0 release', 'Apache Doris adds BM25 scoring for full-text search'),
(2, 'Storage notes', 'Inverted indexes accelerate text and structured filters'),
(3, 'Vector primer', 'Approximate nearest neighbor search complements text search');
SELECT id, title, score() AS rel
FROM articles
WHERE body MATCH_ANY 'text search'
ORDER BY rel DESC LIMIT 3;
예상 결과
+------+-------------------+-----------+
| id | title | rel |
+------+-------------------+-----------+
| 3 | Vector primer | 0.8009131 |
| 1 | Doris 4.0 release | 0.5634479 |
| 2 | Storage notes | 0.1384567 |
+------+-------------------+-----------+
MATCH_ANY 'text search'는 쿼리를 text와 search로 토큰화하고, 두 포스팅 리스트를 조회한 뒤 어느 한 검색어라도 포함하는 행을 반환합니다. score()는 BM25를 기준으로 순위를 매기며, ORDER BY rel LIMIT 3이 있으면 옵티마이저가 이를 Top-N 쿼리로 처리합니다. 행 3에는 두 검색어가 모두 포함되어 있고(search는 두 번), 행 1에는 두 검색어가 각각 한 번씩 포함되어 있으며, 행 2에는 text만 포함되어 있습니다.
연산자 종류 한눈에 보기
| 연산자 | 용도 |
|---|---|
MATCH / MATCH_ANY | 주어진 키워드 중 하나라도 포함하는 검색(OR) |
MATCH_ALL | 모든 키워드가 반드시 포함되어야 하는 검색(AND) |
MATCH_PHRASE 'a b' | 검색어가 순서대로 인접해 있는 경우 검색. ~slop과 엄격한 순서를 적용하는 ~slop+ 지원 |
MATCH_PHRASE_PREFIX 'a b' | 마지막 검색어를 접두사로 매칭하는 구문 검색. 입력 중 자동 완성에 활용 |
MATCH_PHRASE_EDGE 'a b c' | 첫 검색어는 접미사 매칭, 중간 검색어는 정확한 매칭, 마지막 검색어는 접두사 매칭 |
MATCH_REGEXP '^abc.*' | 원시 바이트가 아닌 토큰을 대상으로 정규식 평가 |
하나의 컬럼에 서로 다른 분석기를 사용하는 역색인이 여러 개 있으면, 쿼리 시점에 USING ANALYZER <name>을 덧붙여 사용할 분석기를 선택할 수 있습니다.
Apache Doris 전문 검색은 언제 사용해야 하나요?
Apache Doris 전문 검색은 로그/트레이스 검색, 전자상거래 Catalog 검색, CJK와 라틴 문자가 혼합된 콘텐츠, 입력 중 검색, 텍스트 매칭과 벡터 유사도를 결합하는 RAG 파이프라인에 사용하세요. 토큰 내부의 부분 문자열 검색, 편집 거리에 기반한 퍼지 매칭, 검색 결과 하이라이트가 필요하다면 LIKE 또는 n-gram 인덱스를 검토하세요.
적합한 용도
- 사용자가 자유 텍스트와 구조화된 필터를 혼합하는 로그 및 트레이스 검색(
level = 'ERROR' AND message MATCH_ANY 'timeout disconnect'). - 같은 행에 가격, 카테고리, 설명이 있는 전자상거래 및 Catalog 검색.
- CJK와 라틴 문자가 혼합된 콘텐츠.
chinese,unicode,icu파서는 하나의 컬럼에서 두 유형을 모두 처리합니다. - 별도의 자동 완성 서비스 없이
MATCH_PHRASE_PREFIX로 완성 후보를 반환하는 입력 중 검색. - 텍스트 매칭과 임베딩 유사도를 결합하는 RAG 파이프라인. 하이브리드 검색에서
MATCH_*와 벡터 거리를 하나의 SQL로 결합하는 방법을 확인하세요.
적합하지 않은 용도
- 단일 토큰 내부의 부분 문자열 검색(컬럼에서 "ear"가 "year"의 일부로 포함된 모든 행 찾기). 토큰화하면 데이터를 이런 방식으로 볼 수 없게 됩니다.
LIKE, N-Gram BloomFilter 인덱스 또는 토큰화하지 않는 역색인을 사용하세요. - 퍼지/편집 거리 매칭("이 단어를 찾으셨나요..."). Doris는 현재 내장 퍼지 연산자를 제공하지 않습니다. 쓰기 시점에 발음 기반 또는 n-gram 분석기로 전처리하거나, 애플리케이션에서 쿼리에 퍼지 처리를 적용하세요.
- 검색 결과 하이라이트(일치하는 부분을 마크업과 함께 반환). Doris는 점수를 계산하지만 현재 하이라이트 조각은 반환하지 않습니다. 일치한 검색어를 바탕으로 애플리케이션에서 하이라이트를 렌더링하세요.
- Elasticsearch의
dis_max와 같은 여러 필드에 걸친 관련도 순위 산정.score()는 조건식별로 계산됩니다. 더 정교한 점수 계산 전략이 필요하면SEARCH('title:foo OR body:foo')를 사용하고 애플리케이션 계층에서 조정하세요.
토크나이저 선택하기
분석기 선택은 가장 큰 영향을 미치는 결정입니다. 어떤 쿼리가 매칭될 수 있는지를 결정하며, 인덱싱되는 검색어는 쓰기 시점에 확정됩니다.
none: 토큰화하지 않습니다. 전체 값이 하나의 검색어가 됩니다. ID, 태그, 상태 열거형, 정확한 매칭 필터에 적합합니다.english: 가벼운 정규화를 적용한 ASCII 단어 분리입니다. 영어 텍스트에 적합합니다.chinese:parser_mode를fine_grained또는coarse_grained로 설정하는 중국어 단어 분할입니다. CJK 콘텐츠에 적합합니다.unicode: CJK와 문장 부호를 언어에 의존하지 않고 단어 단위로 분리합니다. 혼합 콘텐츠의 기본값으로 무난합니다.standard: Unicode 텍스트 분할 토크나이저입니다. 대부분의 언어에서 작동합니다.icu: 완전한 Unicode 분할 규칙이 필요한 언어를 위한 ICU 기반 토크나이저입니다(태국어, 크메르어, 여러 문자 체계가 혼합된 텍스트).- 사용자 정의 분석기(3.1+): 접두사 자동 완성을 위한
edge_ngram, 카멜 표기법과 하이픈으로 연결된 검색어 처리를 위한word_delimiter, 대소문자와 악센트를 구분하지 않는 검색을 위한lowercase와asciifolding등을 연결합니다.
분석기를 변경하려면 BUILD INDEX로 인덱스를 다시 빌드해야 합니다.
더 알아보기
- 역색인: 이 연산자들의 기반이 되는 인덱스 구조와 저장 레이아웃, 빌드 및 컴팩션 동작을 설명합니다.
- BM25 관련도 점수 계산:
score()의 계산 방식, 활성화 조건,k1과b를 조정하는 방법을 설명합니다. - 하이브리드 검색: 사전 필터링 및 폴백 의미 체계를 적용해 하나의 SQL에서
MATCH_*와 벡터 ANN 거리를 결합하는 방법을 설명합니다. - 검색 연산자 레퍼런스: slop 구문, 접두사 규칙,
USING ANALYZER를 포함한 전체 연산자 Catalog입니다. - 사용자 정의 분석기 가이드: 문자 필터, 토크나이저, 토큰 필터를 자세히 설명합니다.
- SEARCH 함수: 여러 컬럼에 걸쳐 여러 연산자를 결합하는 단일 문자열 DSL입니다.
- 상호 순위 융합(Reciprocal Rank Fusion): 하나의 점수 계산기만으로 충분하지 않을 때 BM25 순위와 벡터 순위를 융합하는 SQL 패턴입니다.