﻿---
title: Accessing document fields and special variables
description: Depending on where a script is used, it will have access to certain special variables and document fields. A script used in the update, update-by-query,...
url: https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/5335/explore-analyze/scripting/modules-scripting-fields
products:
  - Elasticsearch
applies_to:
  - Elastic Cloud Serverless: Generally available
  - Elastic Stack: Generally available
---

# Accessing document fields and special variables
Depending on where a script is used, it will have access to certain special variables and document fields.

## Update scripts

A script used in the [update](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update), [update-by-query](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update-by-query), or [reindex](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-reindex) API will have access to the `ctx` variable which exposes:
<definitions>
  <definition term="ctx._source">
    Access to the document [`_source` field](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/mapping-source-field).
  </definition>
  <definition term="ctx.op">
    The operation that should be applied to the document: `index` or `delete`.
  </definition>
  <definition term="ctx._index etc">
    Access to [document metadata fields](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/document-metadata-fields), some of which may be read-only.
  </definition>
</definitions>

These scripts do not have access to the `doc` variable and have to use `ctx` to access the documents they operate on.

## Search and aggregation scripts

With the exception of [script fields](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/rest-apis/retrieve-selected-fields#script-fields) which are executed once per search hit, scripts used in search and aggregations will be executed once for every document which might match a query or an aggregation. Depending on how many documents you have, this could mean millions or billions of executions: these scripts need to be fast!
Field values can be accessed from a script using [doc-values](#modules-scripting-doc-vals), [the `_source` field](#modules-scripting-source), or [stored fields](#modules-scripting-stored), each of which is explained below.

### Accessing the score of a document within a script

Scripts used in the [`function_score` query](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/query-languages/query-dsl/query-dsl-function-score-query), in [script-based sorting](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/rest-apis/sort-search-results), or in [aggregations](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/5335/explore-analyze/query-filter/aggregations) have access to the `_score` variable which represents the current relevance score of a document.
Here’s an example of using a script in a [`function_score` query](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/query-languages/query-dsl/query-dsl-function-score-query) to alter the relevance `_score` of each document:
```json

{
  "text": "quick brown fox",
  "popularity": 1
}


{
  "text": "quick fox",
  "popularity": 5
}


{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "text": "quick brown fox"
        }
      },
      "script_score": {
        "script": {
          "lang": "expression",
          "source": "_score * doc['popularity']"
        }
      }
    }
  }
}
```


### Accessing term statistics of a document within a script

Scripts used in a [`script_score`](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/query-languages/query-dsl/query-dsl-script-score-query) query have access to the `_termStats` variable which provides statistical information about the terms in the child query.
In the following example, `_termStats` is used within a [`script_score`](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/query-languages/query-dsl/query-dsl-script-score-query) query to retrieve the average term frequency for the terms `quick`, `brown`, and `fox` in the `text` field:
```json

{
  "text": "quick brown fox"
}


{
  "text": "quick fox"
}


{
  "query": {
    "script_score": {
      "query": { <1>
        "match": {
          "text": "quick brown fox"
        }
      },
      "script": {
        "source": "_termStats.termFreq().getAverage()" <2>
      }
    }
  }
}
```

`_termStats` provides access to the following functions for working with term statistics:
- `uniqueTermsCount`: Returns the total number of unique terms in the query. This value is the same across all documents.
- `matchedTermsCount`: Returns the count of query terms that matched within the current document.
- `docFreq`: Provides document frequency statistics for the terms in the query, indicating how many documents contain each term. This value is consistent across all documents.
- `totalTermFreq`: Provides the total frequency of terms across all documents, representing how often each term appears in the entire corpus. This value is consistent across all documents.
- `termFreq`: Returns the frequency of query terms within the current document, showing how often each term appears in that document.

<admonition title="Functions returning aggregated statistics">
  The `docFreq`, `termFreq` and `totalTermFreq` functions return objects that represent statistics across all terms of the child query.Statistics provides support for the following methods:`getAverage()`: Returns the average value of the metric. `getMin()`: Returns the minimum value of the metric. `getMax()`: Returns the maximum value of the metric. `getSum()`: Returns the sum of the metric values. `getCount()`: Returns the count of terms included in the metric calculation.
</admonition>

<admonition title="Painless language required">
  The `_termStats` variable is only available when using the [Painless](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/5335/explore-analyze/scripting/modules-scripting-painless) scripting language.
</admonition>


### Doc values

By far the fastest most efficient way to access a field value from a script is to use the `doc['field_name']` syntax, which retrieves the field value from [doc values](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/doc-values). Doc values are a columnar field value store, enabled by default on all fields except for [analyzed `text` fields](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/text).
```json

{
  "cost_price": 100
}


{
  "script_fields": {
    "sales_price": {
      "script": {
        "lang":   "expression",
        "source": "doc['cost_price'] * markup",
        "params": {
          "markup": 0.2
        }
      }
    }
  }
}
```

Doc-values can only return "simple" field values like numbers, dates, geo- points, terms, etc, or arrays of these values if the field is multi-valued. It cannot return JSON objects.
<admonition title="Missing fields">
  The `doc['field']` will throw an error if `field` is missing from the mappings. In `painless`, a check can first be done with `doc.containsKey('field')` to guard accessing the `doc` map. Unfortunately, there is no way to check for the existence of the field in mappings in an `expression` script.
</admonition>

<admonition title="Doc values and text fields">
  The `doc['field']` syntax can also be used for [analyzed `text` fields](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/text) if [`fielddata`](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/text#fielddata-mapping-param) is enabled, but **BEWARE**: enabling fielddata on a `text` field requires loading all of the terms into the JVM heap, which can be very expensive both in terms of memory and CPU. It seldom makes sense to access `text` fields from scripts.
</admonition>


### The document `_source`

The document [`_source`](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/mapping-source-field) can be accessed using the `_source.field_name` syntax. The `_source` is loaded as a map-of-maps, so properties within object fields can be accessed as, for example, `_source.name.first`.
<admonition title="Prefer doc-values to _source">
  Accessing the `_source` field is much slower than using doc-values. The _source field is optimised for returning several fields per result, while doc values are optimised for accessing the value of a specific field in many documents.It makes sense to use `_source` when generating a [script field](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/rest-apis/retrieve-selected-fields#script-fields) for the top ten hits from a search result but, for other search and aggregation use cases, always prefer using doc values.
</admonition>

For instance:
```json

{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "text"
      },
      "last_name": {
        "type": "text"
      }
    }
  }
}


{
  "first_name": "Barry",
  "last_name": "White"
}


{
  "script_fields": {
    "full_name": {
      "script": {
        "lang": "painless",
        "source": "params._source.first_name + ' ' + params._source.last_name"
      }
    }
  }
}
```


### Stored fields

*Stored fields* — fields explicitly marked as [`"store": true`](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/mapping-store) in the mapping — can be accessed using the `_fields['field_name'].value` or `_fields['field_name']` syntax:
```json

{
  "mappings": {
    "properties": {
      "full_name": {
        "type": "text",
        "store": true
      },
      "title": {
        "type": "text",
        "store": true
      }
    }
  }
}


{
  "full_name": "Alice Ball",
  "title": "Professor"
}


{
  "script_fields": {
    "name_with_title": {
      "script": {
        "lang": "painless",
        "source": "params._fields['title'].value + ' ' + params._fields['full_name'].value"
      }
    }
  }
}
```

<admonition title="Stored vs _source">
  The `_source` field is just a special stored field, so the performance is similar to that of other stored fields. The `_source` provides access to the original document body that was indexed (including the ability to distinguish `null` values from empty fields, single-value arrays from plain scalars, etc).The only time it really makes sense to use stored fields instead of the `_source` field is when the `_source` is very large and it is less costly to access a few small stored fields instead of the entire `_source`.
</admonition>