Elasticsearch 검색 2편 - 고급 검색 기법과 성능 튜닝
[ELK Stack]Elasticsearch 검색 2편 - 고급 검색 기법과 성능 튜닝
Kibana 콘솔에서 실습했던 고급 검색 쿼리들에 대해 하나도 빠짐없이 정리함. 분석기, 스코어 계산, 페이징, 정렬, 와일드카드, 정규식 등 검색 최적화와 표현력을 위한 기능들을 나열함. 서적 중심으로 자주 마주치는 조건들에 대해 직접 테스트하며 기록한 내용을 기반으로 정리함.
1. 스코어(_score)의 정체와 조작 기법
스코어는 어떻게 계산되는가?
Elasticsearch는 기본적으로 BM25 알고리즘을 통해 _score를 계산함. 이는 단순히 키워드 포함 여부만 따지는 게 아니라, 문서 내에서의 등장 빈도와 해당 단어의 희귀도까지 고려한 계산임.
핵심 구성 요소:
- tf (term frequency): 해당 문서에서 키워드가 얼마나 자주 등장했는지
- idf (inverse document frequency): 전체 문서 중 해당 키워드를 포함한 문서가 얼마나 드문지
- 문서 길이 보정: 짧은 문서일수록 높은 점수를 받도록 보정
- boost: 필드나 쿼리에서 직접 주는 가중치 값
최종 공식 (단순화):
_score = boost × tf × idf / 문서 길이 조정값
이 알고리즘을 이해하면 왜 특정 문서가 상위에 노출되는지 판단할 수 있고, 우리가 원하는 순서를 맞추기 위한 튜닝도 가능함.
🔹 _score 분석: explain
GET kibana_sample_data_ecommerce/_search
{
"query": {
"match": {
"products.product_name": "Pants"
}
},
"explain": true
}
explain: true를 통해 각 문서가 어떤 기준으로 점수를 받았는지 자세히 확인 가능함.- 실무에서는 특정 문서가 왜 높은 순위에 있는지 또는 왜 안 보이는지 디버깅할 때 유용함.
🔹 minimum_should_match
{
"bool": {
"should": [
{ "match": {"title": "Elastic"} },
{ "match": {"title": "Search"} },
{ "match": {"title": "Query"} }
],
"minimum_should_match": 2
}
}
should조건 중 몇 개 이상 일치해야 문서를 반환할지를 지정할 수 있음.- 단순 OR 조합보다 더 정밀한 조건을 구성할 수 있음.
🔹 function_score 쿼리
{
"function_score": {
"query": {
"match": {"category": "clothing"}
},
"field_value_factor": {
"field": "products.base_price",
"factor": 1.2,
"modifier": "sqrt",
"missing": 1
}
}
}
- 쿼리 점수를 수학적으로 조정할 수 있음.
- 예:
base_price값이 클수록 높은 점수를 부여하고 싶은 경우. - 실무 예시: 리뷰 개수, 평점, 판매량 등 다양한 수치를 기반으로 랭킹을 조정하는 데 활용 가능.
기타 사용 가능한 스코어 함수:
random_score: 랜덤하게 결과 섞기script_score: 스크립트를 이용해 점수 계산
2. 정렬과 페이징 전략
🔹 기본 정렬
"sort": [
{ "products.base_price": "desc" },
"_score"
]
- 여러 필드 조합 가능 (가격, 등록일자 등)
_score정렬도 가능하므로 relevance 우선 정렬도 가능
🔹 페이징: from / size 방식
"from": 10,
"size": 10
from: 몇 번째 문서부터 가져올지size: 몇 개 가져올지- 문제점: 10,000 이상 넘어가면 성능 급격히 저하됨 (Lucene 구조 때문)
🔹 페이징: search_after 방식
"sort": ["timestamp", "_id"],
"search_after": ["2023-01-01T00:00:00", "abc123"]
- 이전 쿼리의 마지막 정렬값을 기준으로 다음 페이지 탐색
search_after는 무한 스크롤 구현 시 성능상 유리함- 주의:
_id필드 반드시 포함되어야 함 (정렬 기준 안정성)
3. 고급 검색 - 패턴 기반 쿼리
🔹 와일드카드 쿼리
{
"wildcard": {
"customer_full_name.keyword": {
"value": "M?r*"
}
}
}
?: 임의의 문자 한 개*: 0개 이상의 문자- 성능이 매우 낮기 때문에 접두어가 반드시 고정된 형태로 시작되어야 함 (예:
Mar*은 OK,*ar은 매우 비효율적) - 대소문자 구분 있음 (
keyword필드로만 사용 가능)
🔹 정규식 쿼리
{
"regexp": {
"customer_full_name.keyword": {
"value": "M[a-z]+(y|i)"
}
}
}
- Java 정규식 문법과 동일함
- 활용 예:
.*: 임의의 문자열a[bcd]e: a로 시작해서 b/c/d 중 하나가 가운데, 마지막은 ea.*b: a로 시작해서 b로 끝나는 모든 문자열
- 굉장히 유연하지만 역시 성능상 위험이 있으므로 실무에서는 사전 필터링과 조합 필수
끄읕
댓글남기기