본문 바로가기
WIKI 기술 지식 베이스

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]

더 알아보기 (Learn more)