스크립트 쿼리
- Elasticsearch에서 제공하는 스크립트 언어를 활용해서 검색 쿼리 생성
- 필터 기반의 검색 쿼리
- 여러 필드를 동시에 다루거나 검색 조건이 달라지는 경우 활용
스크립트 사용 방법
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"script": { | |
"lang": "...", // 디폴트 언어는 painless | |
"source" | "id": "...", // 스크립트 정보 | |
"params": { ... } // 스크립트에 변수로 넣어줄 매개변수 | |
} |
스크립트 언어 종류
- painless: Elasticsearch에서 자체적으로 만든 스크립트 언어
- expression: 랭킹과 정렬에 사용하기 위한 js를 바이트 코드로 컴파일하는 언어
- mustache: 템플릿에서 변수 매칭을 위해서 사용되는 표현식으로 {{ variable }}로 표현
- java
1. painless
- 빠르고 안전
- 자바의 데이터 타입을 지원하며 def와 같은 동적인 타입도 지원
- 조건문의 경우 switch를 제외한 일반적인 자바 문법 지원
1.1 painless 스크립트 사용 케이스
- 문서에 접근하는 용도
- 업데이트, 삭제, 필드에 대한 계산
- 커스텀한 score 처리
- aggregation과 함께 사용
- Ingest 파이프라인에서 스크립트 활용 가능
- reindex
1.2 painless 문법
필드 접근 케이스 | 방법 |
ingest node | ctx.필드명 |
업데이트 시 | ctx._source.필드명 |
검색과 집계 시 | doc[필드명].value doc[배열 타입 필드명] |
* 주의: 필드 접근 시 필드가 없거나, null 값인 경우 런타임 에러 발생
- 색인할 때 필드가 null인 경우 대체값을 지정하거나 (필드에 대해 null_value 설정)
- 스크립트를 작성할 때 필드의 존재 여부를 확인하고 필드가 존재하지 않는 경우에 대한 처리 로직 추가
1.3 painless 사용 예시 - 검색
- condition이 excellent이고 transmission이 automatic인 중고차 리스트
- 혹여나 해당 필드가 존재하지 않을 것을 대비하여 필드 존재여부부터 체크
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
GET test-used-car/_search | |
{ | |
"query": { | |
"bool": { | |
"must": [ | |
{ | |
"script": { | |
"script": { | |
"source": """ | |
doc['condition'].size() > 0 && | |
doc['condition'].value== params.condition && | |
doc['transmission'].size() > 0 && | |
doc['transmission'].value == params.transmission | |
""", | |
"lang": "painless", | |
"params": { | |
"condition": "excellent", | |
"transmission": "automatic" | |
} | |
} | |
} | |
} | |
] | |
} | |
} | |
} |
1.4 painless 사용 예시 - 정렬
- 타입이 pickup인 차량을 posting_date 기준 내림차순 정렬
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
GET test-used-car/_search | |
{ | |
"query": { | |
"bool": { | |
"must": [ | |
{ | |
"term": { | |
"type": { | |
"value": "pickup" | |
} | |
} | |
} | |
] | |
} | |
}, | |
"sort": [ | |
{ | |
"_script": { | |
"type": "number", | |
"script": { | |
"source": "(doc['posting_date'].value).toInstant().toEpochMilli()" | |
}, | |
"order": "desc" | |
} | |
} | |
] | |
} |
1.5 painless 사용 예시 - document 변경 (업데이트)
- total_view 필드 값을 view_count 파라미터 값만큼 증감
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
POST test-script/_update/1 | |
{ | |
"script": { | |
"lang": "painless", | |
"source": "ctx._source.total_view += params.view_count", | |
"params": { | |
"view_count": 1 | |
} | |
} | |
} |
1.6 painless 사용 예시 - 필드 추가 및 삭제
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 필드 추가 | |
POST test-script/_update/1 | |
{ | |
"script": "ctx._source.user_name = 'kibana'" | |
} | |
GET test-script/_search | |
# 필드 삭제 | |
POST test-script/_update/1 | |
{ | |
"script": "ctx._source.remove('user_name')" | |
} |
1.7 painless 디버깅 방법
- _explain API를 통해 Debug.explain을 호출하면 강제로 에러를 발생시켜 디버깅 가능
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PUT test-painless-debug/_doc/1 | |
{ | |
"my_value": 5, | |
"my_array": [1, 2, 3, 4] | |
} | |
POST test-painless-debug/_explain/1 | |
{ | |
"query": { | |
"script": { | |
"script": "Debug.explain(doc.my_array)" | |
} | |
} | |
} |

1.8 스크립트 관리
- inline으로 직접 다 작성할 수도 있고
- 스크립트를 별도로 저장해서 사용할 수도 있음
- 이렇게 사용할 경우 컴파일 시간이 줄어들게 되고 검색 속도를 향상할 수 있음
1.8.1 inline으로 전부 작성
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
GET test-script/_search | |
{ | |
"query": { | |
"script_score": { | |
"query": { | |
"match": { | |
"message": "스타벅스" | |
} | |
}, | |
"script": { | |
"source": "_source * 2 * params['my_param']", | |
"params": { | |
"my_param": 2 | |
} | |
} | |
} | |
} | |
} |
1.8.2 스크립트 별도 저장해서 관리
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
POST _scripts/my-calculate-score | |
{ | |
"script": { | |
"lang": "painless", | |
"source": "_score * 2 * params['my_param']" | |
} | |
} | |
GET test-script/_search | |
{ | |
"query": { | |
"script_score": { | |
"query": { | |
"match": { | |
"message": "스타벅스" | |
} | |
}, | |
"script": { | |
"id": "my-calculate-score", | |
"params": { | |
"my_param": 2 | |
} | |
} | |
} | |
} | |
} |
* 주의: 별도로 스크립트 저장할 경우 리소스를 잡아먹으므로 리소스 관리 측면에서 사용하지 않는 스크립트는 제거하는 것을 권장
DELETE _scripts/my-calculate-score
1.8.3 스크립트 캐싱
- 새로운 스크립트가 들어오면 컴파일해서 캐시에 저장하는데 캐시의 기본 사이즈는 100개
- 이 때문에 1.8.2에서 사용하지 않는 스크립트를 제거하도록 권장
- 기본적으로 만료시간은 없으나 script.cache.expire 설정을 통해 만료 시간 설정 가능
- script.cache.max_size를 통해 캐시 사이즈 변경 가능
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PUT _cluster/settings | |
{ | |
"persistent": { | |
"script.cache.max_size": 200 | |
} | |
} |
- 캐싱된 스크립트 목록은 /_nodes/stats?filter_path=*.*.script_cache API를 통해 확인 가능
GET /_nodes/stats?filter_path=*.*.script_cache

2. Expression
- 기본적인 수학 연산자를 사용하여 필드 값을 계산할 수 있으며 문서의 점수나 필드 값을 동적으로 계산 가능
- 로그, 제곱근 등의 수학 함수를 사용할 수 있음
- Expression 스크립트는 안전하고 빠른 평가를 위해 설계됨
- 주요 사용 사례는 사용자 정의 점수 계산 및 복잡한 정렬 조건 설정
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
POST /products/_search | |
{ | |
"query": { | |
"function_score": { | |
"query": { | |
"match_all": {} | |
}, | |
"script_score": { | |
"script": { | |
"source": "0.5 * log(sales + 1) + 0.5 * rating", | |
"lang": "expression" | |
} | |
} | |
} | |
} | |
} |
부연 설명
- 판매량의 로그 값과 평가 점수를 결합하여 문서를 정렬
- 로그 함수를 사용해서 판매량이 클수록 점수가 더 높아지도록 설정했고 각 부분의 가중치는 0.5로 설정
3. Mustache
- 검색 쿼리를 템플릿 기반으로 만들고자 할 때 사용
- Mustache 템플릿 언어를 사용하여 동적 쿼리 생성
- 이를 통해 복잡한 쿼리를 간단하고 유연하게 구성 가능
- Mustache는 논리 연산을 제공하지 않지만, 변수를 바인딩하고 반복 및 조건부 구문을 사용할 수 있어 유용
3.1 Mustache 사용 예시 - 템플릿 저장
- _scripts 엔드포인트 사용
- 해당 템플릿에서 title 변수는 필수지만 author 변수는 optional
- {{#author}}와 {{/author}}는 author 변수가 제공될 때만 해당 블록을 포함
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PUT _scripts/my_search_template | |
{ | |
"script": { | |
"lang": "mustache", | |
"source": """ | |
{ | |
"query": { | |
"bool": { | |
"must": [ | |
{ | |
"match": { | |
"title": "{{title}}" | |
} | |
}, | |
{{#author}} | |
{ | |
"match": { | |
"author": "{{author}}" | |
} | |
} | |
{{/author}} | |
] | |
} | |
} | |
} | |
""" | |
} | |
} |
3.2 Mustache 사용 예시 - 저장한 템플릿을 사용하여 쿼리 실행
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
POST _search/template | |
{ | |
"id": "my_search_template", | |
"params": { | |
"title": "Elasticsearch", | |
"author": "jaimemin" | |
} | |
} |
스크립트 쿼리 참고 사항
- 스크립트 쿼리는 일반적으로 비싼 쿼리에 속함
- 미리 데이터를 색인할 수 없기 때문에 검색 시 계산되는 비용이 많음
- 성능 향상을 위해 필터와 같이 캐시를 사용할 수 있음
- 단, 이를 위해서는 쿼리가 변하지 않아야 하며, 변하는 부분은 params에 저장하는 것을 권장
- 검색의 성능을 위해 불필요한 스크립트 쿼리는 안하는 것이 좋음
- 앞서 언급한 캐시 사이즈 때문에 스크립트가 많이 생성되는 것보다 적게 생성되는 것이 좋음
참고
- 패스트 캠퍼스 - 고성능 검색 엔진 구축으로 한 번에 끝내는 Elasticsearch
반응형
'Elastic Search' 카테고리의 다른 글
[Elasticsearch] 검색 정확도와 랭킹 (0) | 2024.06.19 |
---|---|
[Elasticsearch] Fuzzy 쿼리 (0) | 2024.06.19 |
[Elasticsearch] 자동완성 (0) | 2024.06.12 |
[Elasticsearch] 집계 (3) | 2024.06.09 |
[Elasticsearch] 검색 (0) | 2024.06.07 |