Skip to content

[Feat] 약 검색 품질 재설계 (초성·edge n-gram·오타·관련도) #92

Description

@kangcheolung

📌 Description

현재 약 검색(GET /api/search/drugs)은 DrugDocument.itemName에 기본(standard) 애널라이저 + match_phrase_prefix 쿼리 하나만 사용한다. 다음 한계가 있다.

  • 한글 형태소 분석 없음 → "타이레놀 500" vs "타이레놀500" 토큰화 불일치
  • 초성 검색 불가 (ㅌㅇㄹㄴ → 0건)
  • 오타 불가 (타이레올 → 0건)
  • match_phrase_prefix는 마지막 토큰만 prefix 취급 + 스코어링이 빈약 → 결과 순서가 사실상 무작위
  • 제품명 중간 단어로 검색 불가 ("이알서방")

전제

무중단 재색인 인프라(#90, alias + POST /api/admin/drugs/reindex)가 머지되어, DrugDocument 매핑을 바꾼 뒤 재색인 API 한 번으로 다운타임 없이 반영할 수 있다. 이 이슈는 그 매핑/쿼리를 실제로 고도화한다.

🎯 목표

지표 현재(측정 필요) 목표
검색 p95 latency ? 현재 수준 유지
정답률 (라벨링 20~30개, Recall@10) ? ≥ 0.9
초성 검색 ✅ (ㅌㅇㄹㄴ → 타이레놀 계열)
오타 1글자 허용 ✅ (타이레올 → 타이레놀 계열)
관련도 정렬 ✅ (완전일치 > 시작일치 > 부분일치)

🛠️ 작업 범위

1. 인덱스 settings/mappings 재설계 (DrugDocument)

itemName을 멀티필드로:

  • itemName — nori 형태소 분석 (정확 매칭용)
  • itemName.ngramedge_ngram (min 1, max 20) 자동완성용
  • itemName.chosung — 초성 필드 (색인 시 Java에서 자모 분해 후 주입)
  • number_of_replicas: 0 명시 (single-node → 현재 클러스터 yellow)

@Setting으로 커스텀 애널라이저 정의. DrugIndexManager.createTimestampedIndex()createSettings()/createMapping()으로 그대로 반영하므로 코드 변경 없이 재색인 API로 배포된다.

2. 초성 분해 유틸 (HangulChosungExtractor)

  • "타이레놀정" → "ㅌㅇㄹㄴㅈ"
  • 한글 유니코드 조합 분해 (0xAC00 기준 초성 인덱스)
  • 비한글(숫자/영문)은 그대로 통과
  • DrugInfoConverter.toDocument에서 chosung 필드 채움

3. 검색 쿼리 교체 (DrugSearchRepository / DrugSearchQueryService)

match_phrase_prefixbool.should 조합:

  • match itemName.ngram (자동완성 기본, boost 1)
  • match itemName + fuzziness: AUTO (정확 일치 + 오타, boost 3)
  • term itemName.chosung (입력이 전부 초성일 때만, boost 2)

입력이 "전부 초성인지" 판별해 chosung 절 on/off.

4. 관련도 정렬

  • function_score 또는 bool boost로 완전일치 > 시작일치 > 부분일치
  • DrugSearchQueryService.searchSearchHit<DrugDocument>를 받도록 변경 → _score 보존 (현재는 버려짐)
  • (선택) DrugSearchResponse에 score 필드 — 튜닝/디버깅용, 최종 노출 여부는 논의

5. (선택) 동의어

  • 성분명(아세트아미노펜) ↔ 대표 제품명 매핑 사전
  • 범위 크면 별도 이슈로 분리

6. before/after 측정

  • 라벨링 테스트셋(약명 20~30개 + 기대 결과) → Recall@10, MRR
  • p95 latency
  • 재색인 중 1초 간격 검색 → 실패 요청 0건 로그 (무중단 검증)

✅ To-do

  • 인덱스 settings/mappings JSON 정의 (nori + edge_ngram + chosung analyzer, replicas 0)
  • HangulChosungExtractor + 단위 테스트 (혼합 문자열, 자음/모음만, 빈 문자열)
  • DrugDocument 멀티필드 + @Setting 반영
  • DrugInfoConverter.toDocument — chosung 주입
  • DrugSearchRepository 쿼리 교체
  • DrugSearchQueryService — 초성 입력 판별, SearchHit 수신, score 처리
  • [Feat] DrugInfo ES 무중단 재색인 인프라 (alias + reindex API) #90 재색인 API로 신규 매핑 반영 (수동 검증)
  • 검색 품질 테스트셋 + before/after 측정 스크립트

📒 기타

  • nori 플러그인: ES 8.x 기본 번들에 analysis-nori 포함 (별도 설치 불필요) — 확인
  • 폴백(MySQL LIKE, /api/drugs/search)은 이번 범위 아님 — 그대로 둠
  • 커밋 분리: util(chosung) → document → converter → repository → service

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions