한 줄 정의

전문 검색(Full-text) 인덱스는 문서의 단어들을 토큰 단위로 분해 해 역색인을 만들어, 긴 텍스트에서도 키워드 검색을 빠르게 수행하게 해주는 인덱스입니다.

쉽게 말하면

일반 B-Tree 인덱스가 “이름 전체” 를 색인한다면, 전문 검색 인덱스는 “문장을 구성하는 각 단어” 를 따로 색인합니다.

“MySQL은 빠릅니다”라는 문장은 B-Tree에서는 하나의 값이지만, 전문 검색에서는 MySQL, 빠릅니다 두 개의 단어로 쪼개 색인됩니다. 덕분에 빠릅니다만으로도 이 문장을 찾을 수 있습니다.

왜 필요한가?

일반 인덱스는 문서 내 단어 검색에 전혀 도움이 되지 않습니다.

-- 인덱스: (content)
SELECT * FROM articles WHERE content LIKE '%MySQL%';

이 쿼리는 앞에 와일드카드(%) 가 있어서 B-Tree 인덱스를 탈 수 없습니다. 결국 풀 스캔이 되고, 수백만 건의 문서에서는 사용 불가 수준으로 느려집니다. 전문 검색 인덱스는 이 문제를 해결합니다.

핵심 내용

토큰화 방식

전문 검색 인덱스는 문서를 어떻게 단어로 쪼갤 것인가 가 핵심입니다. MySQL InnoDB는 두 가지 파서를 지원합니다.

1. 기본 파서 (Built-in Parser)

공백과 특수문자 를 기준으로 단어를 분리합니다.

"MySQL is fast" → ["MySQL", "is", "fast"]
  • 영어처럼 공백으로 단어가 구분되는 언어에 적합
  • 한국어에는 부적합 (조사가 붙어있어 “MySQL은”과 “MySQL”을 다른 단어로 취급)

2. n-gram 파서

n글자씩 연속으로 잘라 토큰을 만듭니다.

"검색엔진" (n=2) → ["검색", "색엔", "엔진"]
  • 공백이 없는 언어(한국어/일본어/중국어)에 적합
  • n=2(bigram)가 기본이며 권장값
인덱스 생성 예
CREATE TABLE articles (
    id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(200),
    content TEXT,
    FULLTEXT INDEX ft_content (content) WITH PARSER ngram
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

전문 검색 쿼리

전문 검색 인덱스는 일반 WHERE가 아니라 MATCH ... AGAINST 구문으로 사용합니다.

-- 자연어 검색 (기본)
SELECT * FROM articles
WHERE MATCH(content) AGAINST('MySQL 인덱스' IN NATURAL LANGUAGE MODE);
 
-- 불리언 검색 (+포함, -제외, * 와일드카드)
SELECT * FROM articles
WHERE MATCH(content) AGAINST('+MySQL -Oracle' IN BOOLEAN MODE);
검색 모드
모드설명
NATURAL LANGUAGE MODE (기본)자연어 질의, 연관도 점수 기반 정렬
BOOLEAN MODE+, -, * 등 연산자 사용 가능
QUERY EXPANSION1차 결과에서 키워드 확장 재검색

불용어 (Stopword)

“the”, “is”, “a” 같은 자주 등장하지만 검색에 의미 없는 단어 는 인덱스에서 제외됩니다.

  • 기본 불용어 목록이 내장되어 있으며 커스터마이징 가능
  • innodb_ft_enable_stopword 설정으로 켜고 끌 수 있음
  • 한국어에서는 조사/어미가 불용어 역할을 할 수 있지만, n-gram 파서에서는 개념이 다름

최소 토큰 길이

기본적으로 3글자 미만의 단어는 인덱싱하지 않습니다.

  • InnoDB: innodb_ft_min_token_size (기본 3)
  • MyISAM: ft_min_word_len (기본 4)

한국어처럼 2글자 단어도 의미 있는 경우, 이 값을 조정해야 합니다. bigram 기반이면 2로 맞추는 것이 일반적 입니다.

검색 결과의 연관도 (Relevance)

MATCH ... AGAINST는 boolean 값이 아니라 연관도 점수 를 반환합니다.

SELECT id,
       MATCH(content) AGAINST('MySQL') AS score
FROM articles
ORDER BY score DESC
LIMIT 10;

점수가 0이면 매치되지 않은 것이고, 양수면 관련된 문서입니다.

내 생각

  • 실무에서 대규모 검색이 필요하다면 MySQL의 전문 검색 인덱스는 Elasticsearch의 대체재가 되기 어렵습니다. 형태소 분석, 동의어 처리, 점수 커스터마이징, 실시간 색인 업데이트 같은 기능이 훨씬 제한적입니다.

  • 그럼에도 불구하고 “이미 MySQL에 있는 데이터에 대해 가볍게 검색 기능을 추가 해야 할 때”는 전문 검색 인덱스가 훌륭한 선택입니다. 별도 검색 엔진을 운영하는 비용을 생각하면, 중소 규모에서는 충분한 솔루션입니다.

  • 한국어 환경에서는 반드시 WITH PARSER ngram 을 사용해야 하며, innodb_ft_min_token_size = 2 로 설정해야 2글자 단어도 검색됩니다. 기본값으로 사용하면 한국어 검색이 거의 동작하지 않습니다.

관련 개념

출처

  • Real MySQL 8.0 (1권), 8.5 전문 검색 인덱스