상품 검색을 개선하면서 MySQL N-Gram의 동작 방식을 다시 살펴보게 됐다. 이번 글에서는 기본 원리와 간단한 SQL 예제, 그리고 기존 상품 검색에서 아쉬웠던 점을 정리해보려고 한다.
1. N-Gram은 문자열을 어떻게 나눌까?

N-Gram은 연속된 n개의 문자를 하나의 토큰으로 나누는 방식이다. MySQL은 한글을 포함한 CJK 텍스트 검색을 위해 ngram 파서를 제공하며, FULLTEXT 인덱스에 적용할 수 있다.
예를 들어 n=2일 때 ‘운동화추천’은 ‘운동’, ‘동화’, ‘화추’, ‘추천’으로 나뉜다. 두 글자씩 끊어 버리는 것이 아니라, 한 글자씩 이동하면서 겹치는 조각을 만든다.
이때 ‘동화’나 ‘화추’가 생기는 것을 보면 알 수 있듯, 단어의 의미를 이해해 나누는 방식은 아니다.
2. 두 글자 검색만 가능한 것은 아니다
ngram_token_size의 기본값은 2다. 하지만 이것은 검색어를 반드시 두 글자로 입력해야 한다는 뜻이 아니라, 인덱스를 구성하는 토큰의 길이가 2라는 뜻이다. ‘운동화’처럼 더 긴 검색어도 여러 토큰으로 나누어 처리한다.
반대로 토큰보다 짧은 한 글자 검색은 일반적인 검색에서 제약이 있다. 검색 결과를 확인할 때는 토큰 크기와 검색 모드를 함께 봐야 한다.
3. 간단한 상품 검색 예제
아래는 운영 코드를 단순화한 것이 아니라, 검색 대상 컬럼의 차이를 설명하기 위해 만든 예제다. MySQL 8.4 문서를 기준으로 작성했으며 실제 DB에서 실행 검증한 결과는 아니다.
CREATE TABLE product_search_demo (
id BIGINT PRIMARY KEY,
name VARCHAR(200),
keywords TEXT,
FULLTEXT INDEX ft_keywords (keywords) WITH PARSER ngram
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO product_search_demo VALUES
(1, '가벼운 운동화', '운동화 러닝화'),
(2, '가벼운 운동화', '신발');
SELECT id, name
FROM product_search_demo
WHERE MATCH(keywords)
AGAINST('운동화' IN BOOLEAN MODE);
이 예제에서는 상품명에 ‘운동화’가 있어도 검색 대상은 keywords뿐이다. 따라서 2번 상품은 상품명만으로 검색에 잡히지 않는다. N-Gram이 다른 컬럼의 내용을 알아서 검색해 주는 것은 아니다.
4. 검색 모드도 확인해야 한다
자연어 모드는 검색어에서 나온 N-Gram 토큰들의 합집합을 기준으로 검색한다. Boolean 모드는 검색어를 N-Gram 구문 검색으로 변환한다. 같은 검색어라도 모드에 따라 매칭 범위가 달라질 수 있으므로, 실제 상품 데이터로 결과를 비교해보는 것이 좋다.
5. 실무에서 가장 아쉬웠던 점
기존 시스템도 검색용 키워드를 별도 컬럼에 저장하고 해당 컬럼을 검색하는 구조였다. 가장 아쉬웠던 점은 상품이 있어도 검색에 필요한 키워드가 없으면 결과에 나오지 않는다는 것이었다.
사용자가 입력할 만한 표현을 미리 등록해야 하다 보니 검색 품질이 키워드 관리에 많이 의존했다. 당시 사용하던 2글자 단위 설정의 제약도 있었지만, 키워드 누락은 토큰 크기와는 별개의 문제였다.
예를 들어 ‘러닝화’를 검색했을 때 ‘운동화’라는 키워드만 가진 상품까지 찾고 싶다면, 단순한 문자 분할 외에 두 표현을 연결하는 규칙이 필요하다. 이 예시는 기존 방식의 한계를 설명하기 위한 가상의 상황이다.
마무리
MySQL N-Gram은 DB 안에서 텍스트 검색을 구현할 수 있는 선택지다. 다만 토큰을 나누는 방식만큼 검색 대상 데이터와 검색 모드도 중요하다.
내 경우에는 키워드를 계속 추가하는 것에서 나아가, 어떤 상품 정보를 검색 대상으로 삼고 검색어를 어떻게 처리할지 다시 고민하게 됐다. 이후 OpenSearch로 전환했지만, 엔진 교체만으로 키워드 누락이 해결되는 것은 아니다. 검색에 넣을 데이터와 분석 방식을 함께 설계하는 것이 핵심이었다.
'코드 > dev' 카테고리의 다른 글
| Codex 자주 쓰는 명령어 정리: 계획부터 리뷰, 세션 재개까지 (0) | 2026.10.14 |
|---|---|
| 쿠버네티스 실습(minikube) (0) | 2026.02.22 |
| 쿠버네티스 (0) | 2025.11.21 |
| Jaeger와 Kibana로 로그통합 (1) | 2025.09.24 |
| 확장성을 고려한 CI/CD 구축 방법 -3 (0) | 2025.09.22 |













