Override field values at query time
editOverride field values at query time
editIf you create a runtime field with the same name as a field that already exists in the mapping, the runtime field shadows the mapped field. At query time, Elasticsearch evaluates the runtime field, calculates a value based on the script, and returns the value as part of the query. Because the runtime field shadows the mapped field, you can override the value returned in search without modifying the mapped field.
For example, let’s say you indexed the following documents into my-index-000001
:
resp = client.bulk( index="my-index-000001", refresh=True, operations=[ { "index": {} }, { "@timestamp": 1516729294000, "model_number": "QVKC92Q", "measures": { "voltage": 5.2 } }, { "index": {} }, { "@timestamp": 1516642894000, "model_number": "QVKC92Q", "measures": { "voltage": 5.8 } }, { "index": {} }, { "@timestamp": 1516556494000, "model_number": "QVKC92Q", "measures": { "voltage": 5.1 } }, { "index": {} }, { "@timestamp": 1516470094000, "model_number": "QVKC92Q", "measures": { "voltage": 5.6 } }, { "index": {} }, { "@timestamp": 1516383694000, "model_number": "HG537PU", "measures": { "voltage": 4.2 } }, { "index": {} }, { "@timestamp": 1516297294000, "model_number": "HG537PU", "measures": { "voltage": 4 } } ], ) print(resp)
response = client.bulk( index: 'my-index-000001', refresh: true, body: [ { index: {} }, { "@timestamp": 1_516_729_294_000, model_number: 'QVKC92Q', measures: { voltage: 5.2 } }, { index: {} }, { "@timestamp": 1_516_642_894_000, model_number: 'QVKC92Q', measures: { voltage: 5.8 } }, { index: {} }, { "@timestamp": 1_516_556_494_000, model_number: 'QVKC92Q', measures: { voltage: 5.1 } }, { index: {} }, { "@timestamp": 1_516_470_094_000, model_number: 'QVKC92Q', measures: { voltage: 5.6 } }, { index: {} }, { "@timestamp": 1_516_383_694_000, model_number: 'HG537PU', measures: { voltage: 4.2 } }, { index: {} }, { "@timestamp": 1_516_297_294_000, model_number: 'HG537PU', measures: { voltage: 4 } } ] ) puts response
const response = await client.bulk({ index: "my-index-000001", refresh: "true", operations: [ { index: {}, }, { "@timestamp": 1516729294000, model_number: "QVKC92Q", measures: { voltage: 5.2, }, }, { index: {}, }, { "@timestamp": 1516642894000, model_number: "QVKC92Q", measures: { voltage: 5.8, }, }, { index: {}, }, { "@timestamp": 1516556494000, model_number: "QVKC92Q", measures: { voltage: 5.1, }, }, { index: {}, }, { "@timestamp": 1516470094000, model_number: "QVKC92Q", measures: { voltage: 5.6, }, }, { index: {}, }, { "@timestamp": 1516383694000, model_number: "HG537PU", measures: { voltage: 4.2, }, }, { index: {}, }, { "@timestamp": 1516297294000, model_number: "HG537PU", measures: { voltage: 4, }, }, ], }); console.log(response);
POST my-index-000001/_bulk?refresh=true {"index":{}} {"@timestamp":1516729294000,"model_number":"QVKC92Q","measures":{"voltage":5.2}} {"index":{}} {"@timestamp":1516642894000,"model_number":"QVKC92Q","measures":{"voltage":5.8}} {"index":{}} {"@timestamp":1516556494000,"model_number":"QVKC92Q","measures":{"voltage":5.1}} {"index":{}} {"@timestamp":1516470094000,"model_number":"QVKC92Q","measures":{"voltage":5.6}} {"index":{}} {"@timestamp":1516383694000,"model_number":"HG537PU","measures":{"voltage":4.2}} {"index":{}} {"@timestamp":1516297294000,"model_number":"HG537PU","measures":{"voltage":4.0}}
You later realize that the HG537PU
sensors aren’t reporting their true
voltage. The indexed values are supposed to be 1.7 times higher than
the reported values! Instead of reindexing your data, you can define a script in
the runtime_mappings
section of the _search
request to shadow the voltage
field and calculate a new value at query time.
If you search for documents where the model number matches HG537PU
:
resp = client.search( index="my-index-000001", query={ "match": { "model_number": "HG537PU" } }, ) print(resp)
response = client.search( index: 'my-index-000001', body: { query: { match: { model_number: 'HG537PU' } } } ) puts response
const response = await client.search({ index: "my-index-000001", query: { match: { model_number: "HG537PU", }, }, }); console.log(response);
GET my-index-000001/_search { "query": { "match": { "model_number": "HG537PU" } } }
The response includes indexed values for documents matching model number
HG537PU
:
{ ... "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 1.0296195, "hits" : [ { "_index" : "my-index-000001", "_id" : "F1BeSXYBg_szTodcYCmk", "_score" : 1.0296195, "_source" : { "@timestamp" : 1516383694000, "model_number" : "HG537PU", "measures" : { "voltage" : 4.2 } } }, { "_index" : "my-index-000001", "_id" : "l02aSXYBkpNf6QRDO62Q", "_score" : 1.0296195, "_source" : { "@timestamp" : 1516297294000, "model_number" : "HG537PU", "measures" : { "voltage" : 4.0 } } } ] } }
The following request defines a runtime field where the script evaluates the
model_number
field where the value is HG537PU
. For each match, the script
multiplies the value for the voltage
field by 1.7
.
Using the fields
parameter on the _search
API, you can
retrieve the value that the script calculates for the measures.voltage
field
for documents matching the search request:
resp = client.search( index="my-index-000001", runtime_mappings={ "measures.voltage": { "type": "double", "script": { "source": "if (doc['model_number.keyword'].value.equals('HG537PU'))\n {emit(1.7 * params._source['measures']['voltage']);}\n else{emit(params._source['measures']['voltage']);}" } } }, query={ "match": { "model_number": "HG537PU" } }, fields=[ "measures.voltage" ], ) print(resp)
response = client.search( index: 'my-index-000001', body: { runtime_mappings: { 'measures.voltage' => { type: 'double', script: { source: "if (doc['model_number.keyword'].value.equals('HG537PU'))\n {emit(1.7 * params._source['measures']['voltage']);}\n else{emit(params._source['measures']['voltage']);}" } } }, query: { match: { model_number: 'HG537PU' } }, fields: [ 'measures.voltage' ] } ) puts response
const response = await client.search({ index: "my-index-000001", runtime_mappings: { "measures.voltage": { type: "double", script: { source: "if (doc['model_number.keyword'].value.equals('HG537PU'))\n {emit(1.7 * params._source['measures']['voltage']);}\n else{emit(params._source['measures']['voltage']);}", }, }, }, query: { match: { model_number: "HG537PU", }, }, fields: ["measures.voltage"], }); console.log(response);
POST my-index-000001/_search { "runtime_mappings": { "measures.voltage": { "type": "double", "script": { "source": """if (doc['model_number.keyword'].value.equals('HG537PU')) {emit(1.7 * params._source['measures']['voltage']);} else{emit(params._source['measures']['voltage']);}""" } } }, "query": { "match": { "model_number": "HG537PU" } }, "fields": ["measures.voltage"] }
Looking at the response, the calculated values for measures.voltage
on each
result are 7.14
and 6.8
. That’s more like it! The runtime field calculated
this value as part of the search request without modifying the mapped value,
which still returns in the response:
{ ... "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 1.0296195, "hits" : [ { "_index" : "my-index-000001", "_id" : "F1BeSXYBg_szTodcYCmk", "_score" : 1.0296195, "_source" : { "@timestamp" : 1516383694000, "model_number" : "HG537PU", "measures" : { "voltage" : 4.2 } }, "fields" : { "measures.voltage" : [ 7.14 ] } }, { "_index" : "my-index-000001", "_id" : "l02aSXYBkpNf6QRDO62Q", "_score" : 1.0296195, "_source" : { "@timestamp" : 1516297294000, "model_number" : "HG537PU", "measures" : { "voltage" : 4.0 } }, "fields" : { "measures.voltage" : [ 6.8 ] } } ] } }