[ES] 8. Scripting (스크립팅)

mallin·2022년 4월 23일
1

ElasticSearch

목록 보기
8/9
post-thumbnail

Scripting (스크립팅)

ES 에서 스크립팅을 사용하여 사용자 지정 표현식을 사용할 수 있습니다.
EX) 계산된 값을 필드로 반환하거나 쿼리에 대한 사용자 지정 점수를 평가 가능

ES 는 기본적으로 업데이트를 허용하지 않습니다. 재색인을 통해 설정한 _id 의 문서를 삭제하고 다시 생성할 뿐입니다. _update API 도 내부적으로 스크립팅을 이용하고 있습니다.

기본 스크립팅 언어는 Painless 입니다.

🧐 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 업데이트하기

스크립트로 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']"
        }
      }
    }
  }
}

레퍼런스

Scripting

0개의 댓글