Loading

Painless syntax-context bridge

Serverless Stack

One of the most distinctive aspects of Painless scripting is how data access methods (doc, ctx, and _source) are directly tied to the context of use. Unlike other scripting languages where data access patterns remain consistent, Painless provides different access mechanisms that are optimized for specific use cases and contexts within Elasticsearch.
Understanding when and why to use each access method is crucial for writing efficient Painless scripts.

Tip

If you're new to Painless contexts, refer to Painless contexts in the Reference section for comprehensive context documentation. For hands-on examples of field access, refer to our set of Painless script tutorials.

  • doc values are a columnar field value store, enabled by default on all the fields except analyzed text fields. They can only return simple field values such as numbers, dates, geo-points, and terms.
  • ctx access provides structured access to document content during modification contexts, with fields accessible as map and list structures for existing document fields.
  • _source access loads the complete document as a map-of-maps, optimized for returning several fields per result but slower than doc values for single field access.

Check the decision matrix to decide between these.

  • You should always start with doc values as your first option for field access. This is the fastest and most efficient way to access field values in Painless scripts. Refer to Doc values to learn more.
  • Painless context examples:
  • Syntax pattern: doc[‘field_name’].value

The following example calculates the average price per item across all orders by dividing taxful_total_price by total_quantity for each document. The avg aggregation then computes the average of these calculated values.

GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "avg_price_per_item": {
      "avg": {
        "script": {
          "source": "doc['taxful_total_price'].value / doc['total_quantity'].value"
        }
      }
    }
  }
}
		
  • Use ctx for document modification and pipeline processing where you need access to document metadata, content, and operational control.
  • Painless context examples:
  • Syntax pattern: ctx.field_name, ctx._source.field_name, and `ctx[‘field_name’]`

The following example creates an ingest pipeline named create_summary with a script processor. This script assigns a text value to the field order_summary by combining the customer name and the price.

PUT _ingest/pipeline/create_summary
{
  "processors": [
    {
      "script": {
        "source": """
          ctx.order_summary = ctx.customer_full_name + ' - $' + ctx.taxful_total_price;
        """
      }
    }
  ]
}
		
  • Use _source for document updates and transformations where you need full JSON document access.
  • Painless context examples:
  • Syntax patterns: ctx._source.field_name

Let’s use _update_by_query to calculate loyalty points from the order’s total price multiplied by a parameter rate for high-value orders.

POST /kibana_sample_data_ecommerce/_update_by_query
{
  "query": {
    "range": {
      "taxful_total_price": {"gte": 1000}
    }
  },
  "script": {
    "source": """
      ctx._source.loyalty_points = Math.round(ctx._source.taxful_total_price * params.points_rate);
    """,
    "params": {
      "points_rate": 2.0
    }
  }
}
		
Scenario Required Access Method Reason
Aggregation calculations doc Columnar storage provides fastest performance
Document scoring doc Optimized for search-time calculations
Script fields (top results) _source Optimized for returning several fields per result
Adding fields during ingest ctx Direct field access during pipeline processing
Updating existing documents ctx._source Full document modification capabilities
Document transformation during reindex ctx._source Complete document restructuring with metadata access
Sort operations doc Single-field performance optimization for sorting
Runtime field with simple values doc Performance advantage for repeated calculations
Runtime field with complex logic params[‘_source’] Access to complete document structure with emit