ES 에서 스크립팅을 사용하여 사용자 지정 표현식을 사용할 수 있습니다.
EX) 계산된 값을 필드로 반환하거나 쿼리에 대한 사용자 지정 점수를 평가 가능
ES 는 기본적으로 업데이트를 허용하지 않습니다. 재색인을 통해 설정한 _id 의 문서를 삭제하고 다시 생성할 뿐입니다. _update API 도 내부적으로 스크립팅을 이용하고 있습니다.
기본 스크립팅 언어는 Painless 입니다.
Painless 는 Elasticsearch를 위해 특별히 설계된 고성능의 안전한 스크립팅 언어입니다.
Painless를 사용하여 Elasticsearch에서 스크립트가 지원되는 모든 곳에서 inline script 및 stored script 를 안전하게 작성할 수 있습니다.
특징
① 안전성
: Painless는 클래스 구성원까지 세분화된 세분화된 허용 목록을 사용
: 허용 목록에 포함되지 않은 모든 항목은 컴파일 오류가 발생
② 성능
: JVM이 제공하는 가능한 모든 최적화를 활용하기 위해 JVM 바이트코드로 직접 컴파일
: Painless는 일반적으로 런타임 시 추가로 느린 검사가 필요한 기능을 피함
③ 단순성
: 기본적인 코딩 경험이 있는 사람이라면 누구나 자연스럽게 친숙한 구문을 구현
: 가독성을 높이고 상용구를 제거하기 위해 몇 가지 추가 개선 사항과 함께 Java 구문의 하위 집합을 사용
사용방법
"script": {
"lang": "...",
"source" | "id": "...",
"params": { ... }
}
이름 | 설명 |
---|---|
lang | 스크립트가 작성된 언어를 지정, 기본 값은 painless |
source, id | 스크립트 |
params | 스크립트에 변수로 전달되는 명명된 매개변수를 지정 |
학생들의 점수를 0.5 배씩 올려주는 스크립트 코드를 작성하겠습니다.
GET /students/_search
{
"_source": ["score"],
"script_fields": {
"test_script": {
"script": {
"source": "doc['score'].value * params['multiplier']",
"params": {"multiplier": 1.5 }
}
}
}
}
도큐먼트에 있는 값을 접근할 때에는 doc['필드'].value
파라미터로 넘어온 값을 접근할 때에는 params['필드']
로 사용하면 됩니다.
해당 querydsl 을 실행했을 때 우리가 의도한 것처럼 원래 점수 50 점에서 50 + 25 (0.5배) 가 올라간 걸 확인 할 수 있습니다.
클러스터 상태에서 스크립트를 저장하고 사용할 수 있습니다.
스크립트를 저장해서 사용하면 컴파일 시간을 줄이고 검색을 더 빠르게 만듭니다.
그냥 스크립트를 사용할 때에는 lang 을 지정해주지 않아도 되지만, 스크립트를 저장하는 경우엔는 lang 매개변수로 반드시 스크립트 언어를 지정해야 합니다.
스크립트 생성
POST _scripts/calculate-score2
{
"script": {
"lang": "painless",
"source": "Math.log(_score * 2) + params['multiplier']"
}
}
calculate-score 라는 스크립트를 생성합니다.
해당 스크립트는 도큐먼트의 score 값에 파라미터 값을 더해줍니다.
스크립트 가져오기
GET _scripts/calculate-score2
정상적으로 스크립트가 만들어진 걸 확인할 수 있습니다.
스크립트로 검색하기
GET students/_search
{
"query": {
"script_score": {
"query": {
"match": {
"score": "90"
}
},
"script": {
"id": "calculate-score2",
"params": {
"multiplier": 1.5
}
}
}
}
}
스크립트 삭제
DELETE _scripts/calculate-score
스크립트로 document 업데이트도 할 수 있습니다.
1번 학생의 나이가 실제 21살인데 1살로 잘못 들어가 있어서 21살로 업데이트 해보겠습니다.
스크립트로 document 업데이트 하기
POST students/_update/1
{
"script": {
"source": "ctx._source.age = params.age",
"lang": "painless",
"params": {
"age": 21
}
}
}
필드 및 값 추가하기
POST students/_update/2
{
"script" : "ctx._source.company = '회사1'"
}
필드 삭제하기
POST students/_update/2
{
"script" : "ctx._source.remove('company')"
}
if 쿼리 쓰기
POST students/_update/2
{
"script": {
"source": "if (ctx._source.name.equals('학생23')) { ctx._source.name = '학생22' }",
"lang": "painless"
}
}
_score는 문서의 현재 관련성 점수를 나타내는 변수에 액세스할 수 있습니다.
GET my-index-000001/_search
{
"query": {
"function_score": {
"query": {
"match": {
"text": "quick brown fox"
}
},
"script_score": {
"script": {
"lang": "expression",
"source": "_score * doc['popularity']"
}
}
}
}
}