---
type: troubleshooting
tags: [companyx, rag, keyword, tsvector, simple, korean, skill-rag-file]
status: closed
closed_date: 2026-03-23
closed_reason: pg_trgm 확장 설치 + GIN 인덱스 + keyword_search에 trgm similarity 보완 추가. 이전 0건 질문 전부 결과 반환 확인.
opened_date: 2026-03-23
severity: high
root_cause: PostgreSQL simple 토크나이저가 한국어 교착어를 처리 못 함. 공백 기준 토큰화로 조사 결합·복합명사가 하나의 lexeme이 되어 검색어와 불일치. prefix(:*)로 부분 완화했으나 전 질의 커버 불가.
---

# 260323 Company X RAG keyword 단독 검색 전 질의 0건

## 현상

- `search_mode: keyword` 단독 경로에서 대부분의 질문이 0건 반환
- hybrid 모드에서는 벡터 검색이 보완하여 17/17 통과하지만, keyword 축이 죽어 있음
- prefix(`:*`) + threshold 0.001 적용 후에도 특정 고유명사만 히트, 일반 질문은 0건

## 근본 원인

PostgreSQL `simple` 토크나이저는 공백 기준으로만 토큰을 분리한다. 한국어는 교착어로 어간에 조사/어미가 항상 붙기 때문에:

- `투자를` → lexeme `'투자를'` (검색어 `'투자'`와 불일치)
- `개인투자조합을` → lexeme `'개인투자조합을'` (검색어 `'개인투자조합'`와 불일치)
- `아크로셀의` → lexeme `'아크로셀의'` (검색어 `'아크로셀'`와 불일치)

prefix(`:*`)는 lexeme **접두**만 매칭하므로 `'투자를'`에서 `'투자:*'`는 히트하지만, `'개인투자조합을'`에서 `'투자:*'`는 히트하지 않는다 (투자가 중간에 있음).

이것은 검색 로직의 버그가 아니라 **토크나이저 자체의 한국어 구조적 한계**다.

## 근본 해결책

### 1순위: MeCab-ko 형태소 분석기 도입

- 한국어를 의미 단위로 해체하여 조사를 완벽히 제거
- `아크로셀의` → `[아크로셀]`, `투자를` → `[투자]`
- PostgreSQL용 `textsearch_ko` 확장 설치 후 tsvector 생성 시 `korean` 분석기 지정
- 23서버(PostgreSQL 14)에 확장 설치 필요. PG14 EOL(2026-11) 고려 사항 있음
- **정확도(Precision)와 재현율(Recall) 모두 근본 해결**

### 2순위: pg_trgm + GIN 인덱스

- 텍스트를 3글자 단위로 쪼개 인덱싱 (형태소 분석 없이 부분 문자열 매칭)
- `CREATE EXTENSION pg_trgm` + `GIN(gin_trgm_ops)` 인덱스
- 조사/복합어 무관하게 글자 조각으로 매칭 → 0건 방지
- Recall은 해결되지만 Precision이 하락할 수 있음 (짧은 검색어에서 노이즈)
- MeCab 대비 설치 비용 낮음
- **이것은 근본 해결이 아니라 물리적 보완이다**

### 하이브리드 조합 (최종 목표)

```
Total_Score = ts_rank(MeCab) × 0.8 + similarity(pg_trgm) × 0.2
```

- MeCab으로 정확한 의미 매칭 (고득점)
- pg_trgm으로 복합어/특수명사 보완 (저득점 보완)
- 현재 RRF 합산 구조에 자연스럽게 편입 가능

## 관련 문서

- [260321 하이브리드 검색 keyword recall=0 리서치 (닫힘)](../research/rag/260321_하이브리드검색_keyword_recall0_및_grounding_실패_원인확정_리서치.md)
- [260323 PostgreSQL simple FTS 한국어 한계 리서치](../research/rag/260323_PostgreSQL_simple_FTS_한국어_키워드검색_한계_및_대안_요약.md)
