How to use scripts
출처: 문서
본문
스크립트 사용 방법
스크립트를 받아들이는 모든 OpenSearch API는 동일한 요청 문법을 사용해요. 그래서 script 객체의 형태만 한 번 익혀 두면 검색, 애그리게이션, 업데이트, 인제스트 파이프라인, 인덱스 매핑 어디에든 똑같이 적용할 수 있어요:
"script": {
"lang": "painless",
"source": "doc['price'].value * multiplier",
"params": {
"multiplier": 0.8
}
}
다음 표는 script 객체의 필드를 정리한 거예요.
| 필드 | 데이터 타입 | 설명 |
|---|---|---|
lang |
String | 스크립트가 작성된 언어예요. 기본값은 painless예요. |
source |
String | 스크립트 본문이에요. 인라인 스크립트에는 이 필드를 사용해요. source 또는 id 중 하나는 필수예요. |
id |
String | Create or Update Stored Script API로 저장한 스크립트의 식별자예요. 저장된 스크립트를 실행할 때는 source 대신 이 필드를 사용해요. source 또는 id 중 하나는 필수예요. |
params |
Object | OpenSearch가 스크립트에 변수로 전달하는 이름이 지정된 값이에요. 선택 사항이에요. |
테스트 환경 준비
이 페이지와 스크립팅 문서 전반의 예제는 제품 레코드 인덱스를 사용해요. 다음 매핑으로 인덱스를 생성하세요:
PUT scripting-products
{
"mappings": {
"properties": {
"name": { "type": "text" },
"sku": { "type": "keyword", "store": true },
"brand": { "type": "keyword", "store": true },
"category": { "type": "keyword" },
"price": { "type": "double" },
"quantity": { "type": "integer" },
"ratings": { "type": "integer" },
"on_sale": { "type": "boolean" },
"release_date": { "type": "date" },
"warehouse": { "type": "geo_point" }
}
}
}
{% include copy-curl.html %}
그다음 제품 네 개를 색인하세요:
POST scripting-products/_bulk?refresh=true
{"index":{"_id":"1"}}
{"name":"Wireless noise cancelling headphones","sku":"AUD-1001","brand":"Aurora","category":"audio","price":249.99,"quantity":42,"ratings":[5,4,5,3],"on_sale":true,"release_date":"2024-03-15","warehouse":{"lat":47.6062,"lon":-122.3321}}
{"index":{"_id":"2"}}
{"name":"Wireless earbuds","sku":"AUD-1002","brand":"Aurora","category":"audio","price":129.5,"quantity":8,"ratings":[4,4],"on_sale":false,"release_date":"2025-01-20","warehouse":{"lat":37.7749,"lon":-122.4194}}
{"index":{"_id":"3"}}
{"name":"Mechanical keyboard","sku":"ACC-2001","brand":"Northwind","category":"accessories","price":89.0,"quantity":120,"ratings":[5,5,5],"on_sale":true,"release_date":"2023-11-02","warehouse":{"lat":41.8781,"lon":-87.6298}}
{"index":{"_id":"4"}}
{"name":"Ultrawide monitor","sku":"DSP-3001","brand":"Northwind","category":"displays","price":599.0,"quantity":0,"on_sale":false,"release_date":"2025-06-10","warehouse":{"lat":30.2672,"lon":-97.7431}}
{% include copy-curl.html %}
인라인 스크립트 실행하기
인라인 스크립트는 요청 본문의 source 필드에 지정해요. 다음 검색은 한 제품의 가격에 할인을 적용하고 그 결과를 스크립트 필드로 반환하는데, 저장된 문서는 그대로 유지돼요:
GET scripting-products/_search
{
"_source": false,
"query": { "term": { "sku": "AUD-1001" } },
"script_fields": {
"sale_price": {
"script": {
"lang": "expression",
"source": "doc['price'] * discount",
"params": { "discount": 0.8 }
}
}
}
}
{% include copy-curl.html %}
sale_price 필드는 요청 시점에 계산돼요:
응답
{
"took": 372,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "scripting-products",
"_id": "1",
"_score": 1.0,
"fields": {
"sale_price": [
199.99200000000002
]
}
}
]
}
}
값을 파라미터로 전달하기
요청마다 달라지는 값은 스크립트 본문에 직접 쓰지 말고 params로 전달하세요. 그래야 스크립트가 한 번만 컴파일되고, 이후 모든 요청이 컴파일된 결과를 재사용해요. OpenSearch는 각 고유 스크립트를 처음 사용할 때 컴파일해서 캐시하는데, 컴파일은 컴파일된 스크립트를 실행하는 것에 비해 상대적으로 느려요.
예를 들어 다음 스크립트는 할인율을 하드코딩하기 때문에, 할인 값마다 별도로 컴파일되는 고유한 스크립트가 생겨요:
"source": "doc['price'] * 0.8"
파라미터로 뽑아낸 버전은 한 번만 컴파일되고 모든 할인 값에 재사용돼요:
"source": "doc['price'] * discount",
"params": { "discount": 0.8 }
짧은 시간 안에 너무 많은 고유 스크립트를 컴파일하면 OpenSearch가 circuit_breaking_exception으로 이후 컴파일을 거부해요. 컴파일 한도를 올리는 것은 증상을 치료하는 것이고, 스크립트를 파라미터화하면 원인을 제거하는 거예요. 이 한도를 제어하는 설정은 컴파일 한도와 캐싱을 참고하세요.
{: .note}
짧은 스크립트 형식 사용하기
스크립트에 lang도 params도 필요 없다면, script 객체 대신 스크립트 본문을 일반 문자열로 넣을 수 있어요. 다음 업데이트는 짧은 형식을 사용해 한 제품의 재고 수량을 늘려요:
POST scripting-products/_update/3
{
"script": "ctx._source.quantity++"
}
{% include copy-curl.html %}
짧은 형식은 다음 객체 형식과 동일해요:
"script": {
"source": "ctx._source.quantity++"
}
문서가 업데이트되고 버전이 1 증가해요:
응답
{
"_index": "scripting-products",
"_id": "3",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 4,
"_primary_term": 1
}
저장된 스크립트 다루기
저장된 스크립트는 클러스터 상태에 식별자를 붙여 저장되고, source 대신 id로 참조해요. 스크립트를 저장해 두면 정의가 한 곳에만 유지되므로, 호출부가 스크립트 본문을 반복해서 작성할 필요가 없고, 스크립트를 호출하는 애플리케이션을 재배포하지 않고도 로직을 바꿀 수 있어요.
매칭된 문서의 관련성 점수를 재고 수량에 따라 조정하는 stock-boosted-score 스크립트를 생성하세요:
POST _scripts/stock-boosted-score
{
"script": {
"lang": "painless",
"source": "_score * (1 + Math.log(1 + params.stock_weight * doc['quantity'].value))"
}
}
{% include copy-curl.html %}
처음 사용할 때가 아니라 저장 시점에 특정 컨텍스트를 기준으로 스크립트를 컴파일하게 하려면, 경로에 _scripts/<id>/<context> 형태로 컨텍스트를 덧붙이세요:
POST _scripts/stock-boosted-score/score
{
"script": {
"lang": "painless",
"source": "_score * (1 + Math.log(1 + params.stock_weight * doc['quantity'].value))"
}
}
{% include copy-curl.html %}
스크립트가 지정된 컨텍스트에 유효하지 않으면, 미리 컴파일했을 때 오류가 스크립트를 사용하는 첫 번째 검색이 아니라 이 요청에서 반환돼요. 클러스터가 지원하는 컨텍스트 목록은 [Get Script Contexts API]