open: keyword 단독 0건 트러블 + MeCab vs pg_trgm 근본해결 리서치
- 트러블: simple 토크나이저 한국어 구조적 한계 확정 - 리서치: MeCab-ko(근본 해결) vs pg_trgm(물리적 보완) 비교 - 근본 해결 1순위: MeCab-ko, 현실적 1단계: pg_trgm (보완 명시 필수) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
74503ab24b
commit
27ca166bcf
@ -0,0 +1,86 @@
|
||||
---
|
||||
type: research
|
||||
tags: [research, rag, korean, mecab, pg_trgm, fts, postgresql]
|
||||
status: open
|
||||
research_target: 한국어 키워드 검색의 근본 해결책 비교 — MeCab-ko 형태소 분석 vs pg_trgm 물리적 보완
|
||||
---
|
||||
|
||||
# 260323 한국어 키워드 검색 근본 해결 — MeCab vs pg_trgm 리서치
|
||||
|
||||
## 목적
|
||||
|
||||
- keyword 단독 검색 0건의 근본 원인(simple 토크나이저 한국어 한계)에 대한 해결책을 비교한다.
|
||||
- "근본 해결"과 "물리적 보완"을 명확히 구분한다.
|
||||
|
||||
## 근본 원인 (확정)
|
||||
|
||||
PostgreSQL `simple` 토크나이저는 공백 기준 토큰화만 수행. 한국어 교착어 특성(조사 결합, 복합명사)으로 lexeme이 검색어와 구조적으로 불일치.
|
||||
|
||||
이것은 검색 로직 버그가 아니라 **분석기 자체의 언어적 한계**다.
|
||||
|
||||
## 해결책 비교
|
||||
|
||||
### MeCab-ko 형태소 분석기 (근본 해결)
|
||||
|
||||
**원리**: 한국어를 의미 단위로 해체. 조사/어미를 제거하고 어간만 lexeme으로 저장.
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| 방식 | `textsearch_ko` 확장 + MeCab-ko 사전 |
|
||||
| Recall | 100% (조사/복합어 완벽 분리) |
|
||||
| Precision | 높음 (의미 단위 매칭) |
|
||||
| 설치 비용 | 높음 (23서버 OS에 MeCab + 한국어 사전 설치, PG 확장 빌드) |
|
||||
| 유지 비용 | 사전 업데이트 필요 (신조어, 고유명사) |
|
||||
| PG14 호환 | 가능하나 EOL(2026-11) 고려 |
|
||||
| 성능 | tsvector 기반이므로 GIN 인덱스 활용, FTS와 동일 속도 |
|
||||
|
||||
**적용 시 변경**:
|
||||
- tsvector 트리거: `to_tsvector('simple', ...)` → `to_tsvector('korean', ...)`
|
||||
- tsquery: `to_tsquery('simple', ...)` → `to_tsquery('korean', ...)`
|
||||
- 기존 tsvector 전수 재생성 필요
|
||||
|
||||
### pg_trgm (물리적 보완)
|
||||
|
||||
**원리**: 텍스트를 3글자 단위로 기계적으로 쪼개 인덱싱. 언어 구조를 모름.
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| 방식 | `CREATE EXTENSION pg_trgm` + `GIN(gin_trgm_ops)` |
|
||||
| Recall | 높음 (글자 조각 매칭, 0건 방지) |
|
||||
| Precision | 낮음 (짧은 검색어에서 노이즈. "차" 검색 시 "자동차", "차차차" 모두 히트) |
|
||||
| 설치 비용 | 낮음 (`CREATE EXTENSION` 1줄) |
|
||||
| 유지 비용 | 인덱스 크기 증가, INSERT 시 인덱스 업데이트 부하 |
|
||||
| PG14 호환 | 기본 내장 |
|
||||
| 성능 | similarity 계산 시 FTS보다 느림. ILIKE 인덱싱은 빠름 |
|
||||
|
||||
**적용 시 변경**:
|
||||
- `chunk_text` 컬럼에 `GIN(gin_trgm_ops)` 인덱스 추가
|
||||
- 검색 쿼리에 `similarity(chunk_text, :query)` 또는 `chunk_text ILIKE '%keyword%'` 추가
|
||||
- 기존 tsvector 경로는 그대로 유지, 병렬 축으로 추가
|
||||
|
||||
## 판단
|
||||
|
||||
| 기준 | MeCab-ko | pg_trgm |
|
||||
|------|----------|---------|
|
||||
| 근본 해결 여부 | **근본 해결** | 물리적 보완 |
|
||||
| 0건 방지 | ✅ | ✅ |
|
||||
| 정확도 | 높음 | 낮음 |
|
||||
| 설치 난이도 | 높음 | 낮음 |
|
||||
| 장기 유지 | 사전 관리 필요 | 인덱스 크기 관리 |
|
||||
|
||||
**최종 목표**: MeCab-ko + pg_trgm 하이브리드
|
||||
**현실적 1단계**: pg_trgm 먼저 적용 (0건 즉시 방지) → MeCab-ko 후속 도입
|
||||
|
||||
단, pg_trgm 적용 시 "이것은 근본 해결이 아니라 물리적 보완이다"를 문서와 코드에 명시한다.
|
||||
|
||||
## Unresolved
|
||||
|
||||
- MeCab-ko의 PG14 EOL(2026-11) 이후 PG16 마이그레이션과 동시 도입이 합리적인지
|
||||
- pg_trgm 인덱스 크기가 3,474 청크 → 5만 청크 확장 시 어느 수준인지
|
||||
- MeCab 사전에 Company X 고유명사(투자조합명, 기업명) 추가 가능 여부
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- [260323 keyword 단독 검색 0건 트러블](../../troubleshooting/260323_companyx_rag_keyword_단독검색_전질의_0건.md)
|
||||
- [260323 PostgreSQL simple FTS 한국어 한계 요약](./260323_PostgreSQL_simple_FTS_한국어_키워드검색_한계_및_대안_요약.md)
|
||||
- [PostgreSQL pg_trgm 공식 문서](https://www.postgresql.org/docs/current/pgtrgm.html)
|
||||
@ -0,0 +1,62 @@
|
||||
---
|
||||
type: troubleshooting
|
||||
tags: [companyx, rag, keyword, tsvector, simple, korean, skill-rag-file]
|
||||
status: open
|
||||
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)
|
||||
Loading…
x
Reference in New Issue
Block a user