🧩 문제 상황: 형용사 키워드 검색 실패
- 현상: description = "아늑한" 검색 시, 결과가 빈 배열로 반환됨
- 원인 분석:
- korean_nori 분석기는 텍스트를 형태소 단위로 분해
- "아늑한" → "아늑", "하", "ㄴ"으로 과도하게 분해됨
- Criteria.contains()는 내부적으로 아늑한* 형식의 wildcard 쿼리를 생성하지만, 이 쿼리는 분해된 토큰과 매칭되지 않음 → 검색 실패
🧪 토큰화 예시 (curl 테스트 결과)
POST _analyze
{
"analyzer": "korean_nori",
"text": "아늑한 분위기의 카페입니다."
}
결과 토큰들:
- "아늑", "하", "ᆫ", "분위기", "의", "카페", "이", "ᄇ니다"
→ "아늑한"이라는 전체 단어는 인덱스에 존재하지 않음
📌 필드별 영향도
필드명 | 내용 예시 | 영향도 |
name | "가 카페" | 낮음 |
address | "서울시 강남구" | 낮음 |
description | "맛있는 커피가 있는 아늑한 카페" | 높음 |
- name, address: 명사 위주의 짧은 문자열 → korean_nori와 호환성 양호
- description: 문장형 텍스트 → 세밀한 토큰화로 인해 형용사 검색에서 문제 발생
💡 해결 방안
1. Criteria.contains() → Criteria.matches() 변경
- contains()는 wildcard 쿼리 생성 → 토큰화된 텍스트와 매칭 어려움
- matches()는 match 쿼리 사용 → 형태소 기반 토큰과 유연한 매칭 가능
✅ 조치 후 "아늑한" 검색 시, 적절한 결과 반환됨
2. 추가로 고려한 사항들: 사용자 정의 사전, 동의어 사전, nGram 분석기 도입 고려
도입은 보류, 아래 이유로 필요성 낮음
장점
- 부분 문자열 검색 유연성 확보 가능
- "아늑한" 같은 단어를 분리 없이 유지
- "포근한", "따뜻한" 등 동의어 매핑 → 검색 포괄성 증가
- 도메인 키워드("맛있는", "분위기 좋은") 포함 가능
- LIKE 검색과 유사한 유연성 제공
단점
- 사전 변경 시 인덱스 재생성 필요
- 사전 관리에 지속적인 리소스 요구
- 과도한 통합 시, 다른 키워드 검색 정확도 저하 가능
- 동의어 매핑은 검색 시 추가 연산 → 성능 이슈
⚖️ 최종 판단
- 실사용 시나리오에서, "아늑한"처럼 형용사보다는 "카페", "고깃집" 등 명사 기반 검색이 주를 이룸
- 현재 상태에서 명사 키워드 검색 정확도는 높음
- matches()로 변경한 후 형용사 검색도 보완됨
- 관련성 높은 검색 결과만 노출하려면 min_score 설정을 추가해도 좋을듯
- ex)
Query query = new CriteriaQuery(criteria) .setPageable(pageable) .addSort(Sort.by(Sort.Order.desc("_score"))) .setMinScore(1.0f);
-> 따라서 사용자 정의 사전 도입은 보류하고, 상황에 따라 선택적으로 도입하는 방향으로 결정
✅ 결론
- korean_nori 분석기와 형용사 검색 문제는 Criteria.matches()로 전환하여 해결
- 현재 사용 흐름에서는 명사 위주 검색 패턴이 주를 이루기 때문에, 현상 유지로도 실용성 충분
- 사용자 정의 사전 도입은 향후 필요 시 고려