5.5 검색 설계 - 한국어 전문 검색과 인덱싱 파이프라인
MAM 검색 요구사항, DB와 검색 엔진의 동기화, 한국어 검색에서 기본 토크나이저가 실패하는 이유와 n-gram 인덱스의 한계를 SQLite FTS5 실험으로 설명하고, 형태소 분석과 구간 검색 설계를 다룹니다.
#MAM 검색의 요구사항
"검색창에 단어를 넣으면 결과가 나온다"는 수준을 넘어 MAM 검색에는 다음이 요구됩니다.
| 요구 | 설명 |
|---|---|
| 전문(Full-text) 검색 | 제목, 줄거리, 자막, 음성 인식 텍스트까지 |
| 필터·패싯 | 기간, 프로그램, 종류, 포맷, 보관 상태 |
| 정렬 | 관련도, 방송일, 등록일 |
| 자동완성·오타 허용 | 입력 중 추천 |
| 구간 검색 | "이 단어가 나오는 지점"까지 찾아가기 |
| 권한 반영 | 볼 수 없는 소재는 결과에서 제외 |
| 속도 | 수십만~수백만 건에서 1초 이내 |
#검색 아키텍처
관계형 DB에서 LIKE '%단어%'로 검색하면 데이터가 늘수록 느려지고 정렬·형태소 분석·동의어 처리를 하기 어렵습니다. 그래서 검색 전용 인덱스를 둡니다.
메타데이터 DB (원본) ──변경 이벤트/주기 동기화──→ 검색 엔진 인덱스 (사본)
↑ │
상세 조회·수정 검색 결과(소재 ID 목록)
└────────── 검색 결과의 ID로 DB에서 상세를 다시 조회 ───┘
- DB가 원본, 검색 인덱스는 사본입니다. 인덱스가 깨져도 DB에서 다시 만들 수 있어야 합니다.
- 소재가 수정되면 인덱스에 반영(색인)하는데, 이 과정은 비동기이므로 수 초의 지연을 허용합니다.
- 전체 재색인(reindex)이 가능한 경로를 항상 확보해 두세요. 검색 설정(분석기)을 바꿀 때 필요합니다.
검색 엔진으로는 Elasticsearch/OpenSearch 계열이 널리 쓰이며, 규모가 작으면 DB 내장 전문 검색(SQLite FTS5, PostgreSQL 전문 검색)으로도 시작할 수 있습니다.
#한국어 검색의 어려움
영어는 공백으로 단어를 나누면 대부분 검색이 됩니다. 한국어는 조사와 어미가 단어에 붙어서(교착어) 같은 단어가 여러 형태로 나타납니다.
"광화문" / "광화문에서" / "광화문의" / "광화문까지"
검색어가 "광화문"일 때 이 모든 문서를 찾아야 합니다.
#실험 1: 공백 기준 토크나이저
SQLite FTS5의 기본 토크나이저(unicode61)는 공백과 구두점을 기준으로 단어를 나눕니다. "서울 광화문에서 인터뷰한 홍길동"을 색인하고 검색해 보았습니다.
| 검색어 | 결과 |
|---|---|
광화문에서 |
찾음 |
인터뷰한 |
찾음 |
홍길동 |
찾음 |
광화문 |
못 찾음 |
문서에는 "광화문에서"라는 단어가 있을 뿐 "광화문"이라는 독립된 단어가 없기 때문입니다. 사용자는 "광화문"을 검색할 것이므로 기본 설정으로는 한국어 검색이 제대로 되지 않습니다.
#실험 2: 문자 n-gram(trigram) 토크나이저
n-gram은 텍스트를 연속된 N글자 조각으로 쪼개서 색인합니다. FTS5의 trigram 토크나이저는 3글자 조각을 쓰므로 부분 문자열 검색이 가능합니다.
CREATE VIRTUAL TABLE search USING fts5(title, body, tokenize='trigram');
INSERT INTO search(rowid, title, body)
VALUES (1, '서울 시청 앞 집회 현장', '서울 광화문 인터뷰 홍길동 집회 참가자 발언');
SELECT rowid, snippet(search, 1, '[', ']', '…', 6) FROM search WHERE search MATCH '"광화문"';
| 검색어(글자 수) | 결과 |
|---|---|
광화문 (3) |
찾음 |
인터뷰 (3) |
찾음 |
홍길동 (3) |
찾음 |
시청 앞 (4) |
찾음 |
집회 (2) |
못 찾음 |
홍길 (2) |
못 찾음 |
3글자 이상은 잘 찾지만, 2글자 검색어는 결과가 없습니다. trigram 조각은 3글자 단위이기 때문입니다. 한국어는 "서울", "집회", "화재", "선거"처럼 2글자 핵심 단어가 매우 많아서 치명적인 한계입니다. 같은 데이터에서 LIKE '%서울%'은 결과를 찾았으므로, 2글자 검색어에 한해 LIKE로 대체하는 우회가 가능합니다. 그러나 데이터가 커지면 LIKE는 느립니다.
#정리: 한국어 검색 방식 비교
| 방식 | 장점 | 단점 |
|---|---|---|
| 공백 토크나이저 | 단순, 빠름 | 조사가 붙은 단어를 못 찾음 |
| n-gram(2-gram 등) | 부분 일치, 사전 불필요 | 색인 크기 증가, 노이즈 많음(우연히 겹치는 글자 쌍이 결과에 섞임) |
| 형태소 분석기 | 조사·어미 제거, 정확도 높음 | 사전 관리 필요, 신조어·고유명사 누락 |
| 혼합(형태소 + n-gram 보조) | 재현율과 정확도 균형 | 복잡 |
Elasticsearch 계열에서는 한국어 형태소 분석 플러그인(예: nori)을 사용해 명사 중심으로 색인하고, 사용자 사전에 인물명·프로그램명·지명 같은 고유명사를 등록하는 것이 일반적인 구성입니다. 방송 소재는 프로그램명, 출연자, 지명이 중요하므로 사용자 사전 관리 체계(누가, 어떻게 단어를 추가하는가)를 함께 설계해야 합니다.
#검색 대상 텍스트를 풍부하게
검색은 색인된 텍스트의 품질이 전부입니다. 메타데이터 입력이 부족한 MAM에서는 다음 소스를 자동으로 텍스트화해서 색인에 추가합니다(6장 AI 메타데이터).
| 소스 | 방법 |
|---|---|
| 음성 | 음성 인식(STT) 결과 |
| 화면 속 글자 | OCR(자막, 뉴스 자막띠, 간판) |
| 자막·클로즈드 캡션 | 자막 파일/데이터 트랙 |
| 파일명, 폴더명 | 인제스트 시 수집 |
| 외부 시스템 | 편성표, 기사(CMS) 연계 |
자동 생성 텍스트는 틀릴 수 있으므로, 소스(사람 입력 vs 자동) 를 구분해 저장하고 가중치를 다르게 줍니다(제목 > 사람 입력 키워드 > 자동 인식 텍스트).
#구간 검색 설계
"이 인물이 처음 나오는 장면"을 찾으려면 검색 결과가 소재 단위가 아니라 구간 단위여야 합니다.
인덱스 문서 단위: (소재 ID, 구간 시작 TC, 구간 끝 TC, 텍스트, 출처)
검색 결과: 소재별로 묶어 보여 주되, 각 소재의 매칭 구간 목록과 대표 썸네일 제공
클릭: 프록시 플레이어가 해당 타임코드로 바로 이동
- 구간 단위 문서를 색인하고, 결과는 소재별로 그룹화(collapse) 해서 보여 줍니다.
- 구간의 시간은 프록시의 타임코드와 일치해야 클릭 시 정확한 위치로 이동합니다(1장 타임코드, 2장 프록시).
#정리
- 검색은 DB 원본 + 검색 엔진 사본 구조로 설계하고, 재색인 경로를 확보합니다.
- 한국어는 기본 토크나이저로는 조사가 붙은 단어를 못 찾고, 3-gram은 2글자 검색어를 못 찾습니다. 형태소 분석기 + 사용자 사전이 일반적 해법이고, 어떤 방식이든 테스트 세트로 검증해야 합니다.
- 음성·OCR 같은 자동 텍스트로 검색 대상을 풍부하게 하되, 출처를 구분합니다.
- 구간 단위 색인으로 "정확한 지점"까지 찾아가게 합니다.
#참고 자료
링크는 2026-10-28에 열람이 되는 것을 확인했습니다. 규격과 도구 문서는 개정될 수 있으므로 적용하기 전에 최신 판을 확인하세요.