runtime.asciidoc 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707
  1. [[runtime]]
  2. == Runtime fields
  3. A _runtime field_ is a field that is evaluated at query time. Runtime fields
  4. enable you to:
  5. * Add fields to existing documents without reindexing your data
  6. * Start working with your data without understanding how it’s structured
  7. * Override the value returned from an indexed field at query time
  8. * Define fields for a specific use without modifying the underlying schema
  9. You access runtime fields from the search API like any other field, and {es}
  10. sees runtime fields no differently. You can define runtime fields in the
  11. <<runtime-mapping-fields,index mapping>> or in the
  12. <<runtime-search-request,search request>>. Your choice, which is part of the
  13. inherent flexibility of runtime fields.
  14. Use the <<search-fields,`fields`>> parameter on the `_search` API to
  15. <<runtime-retrieving-fields,retrieve the values of runtime fields>>. Runtime
  16. fields won't display in `_source`, but the `fields` API works for all fields,
  17. even those that were not sent as part of the original `_source`.
  18. Runtime fields are useful when working with log data
  19. (see <<runtime-examples,examples>>), especially when you're unsure about the
  20. data structure. Your search speed decreases, but your index size is much
  21. smaller and you can more quickly process logs without having to index them.
  22. [discrete]
  23. [[runtime-benefits]]
  24. === Benefits
  25. Because runtime fields aren't indexed, adding a runtime field doesn't increase
  26. the index size. You define runtime fields directly in the index mapping, saving
  27. storage costs and increasing ingestion speed. You can more quickly ingest
  28. data into the Elastic Stack and access it right away. When you define a runtime
  29. field, you can immediately use it in search requests, aggregations, filtering,
  30. and sorting.
  31. If you change a runtime field into an indexed field, you don't need to modify
  32. any queries that refer to the runtime field. Better yet, you can refer to some
  33. indices where the field is a runtime field, and other indices where the field
  34. is an indexed field. You have the flexibility to choose which fields to index
  35. and which ones to keep as runtime fields.
  36. At its core, the most important benefit of runtime fields is the ability to
  37. add fields to documents after you've ingested them. This capability simplifies
  38. mapping decisions because you don't have to decide how to parse your data up
  39. front, and can use runtime fields to amend the mapping at any time. Using
  40. runtime fields allows for a smaller index and faster ingest time, which
  41. combined use less resources and reduce your operating costs.
  42. [discrete]
  43. [[runtime-incentives]]
  44. === Incentives
  45. Runtime fields can replace many of the ways you can use scripting with the
  46. `_search` API. How you use a runtime field is impacted by the number of
  47. documents that the included script runs against. For example, if you're using
  48. the `fields` parameter on the `_search` API to
  49. <<runtime-retrieving-fields,retrieve the values of a runtime field>>, the script
  50. runs only against the top hits just like script fields do.
  51. You can use <<script-fields,script fields>> to access values in `_source` and
  52. return calculated values based on a script valuation. Runtime fields have the
  53. same capabilities, but provide greater flexibility because you can query and
  54. aggregate on runtime fields in a search request. Script fields can only fetch
  55. values.
  56. Similarly, you could write a <<query-dsl-script-query,script query>> that
  57. filters documents in a search request based on a script. Runtime fields provide
  58. a very similar feature that is more flexible. You write a script to create
  59. field values and they are available everywhere, such as
  60. <<search-fields,`fields`>>, <<query-dsl, all queries>>, and
  61. <<search-aggregations, aggregations>>.
  62. You can also use scripts to <<script-based-sorting,sort search results>>, but
  63. that same script works exactly the same in a runtime field.
  64. If you move a script from any of these sections in a search request to a
  65. runtime field that is computing values from the same number of documents, the
  66. performance should be about the same. The performance for these features is
  67. largely dependent upon the calculations that the included script is running and
  68. how many documents the script runs against.
  69. [discrete]
  70. [[runtime-compromises]]
  71. === Compromises
  72. Runtime fields use less disk space and provide flexibility in how you access
  73. your data, but can impact search performance based on the computation defined in
  74. the runtime script.
  75. To balance search performance and flexibility, index fields that you'll
  76. frequently search for and filter on, such as a timestamp. {es} automatically
  77. uses these indexed fields first when running a query, resulting in a fast
  78. response time. You can then use runtime fields to limit the number of fields
  79. that {es} needs to calculate values for. Using indexed fields in tandem with
  80. runtime fields provides flexibility in the data that you index and how you
  81. define queries for other fields.
  82. Use the <<async-search,asynchronous search API>> to run searches that include
  83. runtime fields. This method of search helps to offset the performance impacts
  84. of computing values for runtime fields in each document containing that field.
  85. If the query can't return the result set synchronously, you'll get results
  86. asynchronously as they become available.
  87. IMPORTANT: Queries against runtime fields are considered expensive. If
  88. <<query-dsl-allow-expensive-queries,`search.allow_expensive_queries`>> is set
  89. to `false`, expensive queries are not allowed and {es} will reject any queries
  90. against runtime fields.
  91. [[runtime-mapping-fields]]
  92. === Map a runtime field
  93. You map runtime fields by adding a `runtime` section under the mapping
  94. definition and defining
  95. <<modules-scripting-using,a Painless script>>. This script has access to the
  96. entire context of a document, including the original `_source` via `params._source`
  97. and any mapped fields plus their values. At query time, the script runs and
  98. generates values for each scripted field that is required for the query.
  99. .Emitting runtime field values
  100. ****
  101. When defining a Painless script to use with runtime fields, you must include
  102. the {painless}/painless-runtime-fields-context.html[`emit` method] to emit
  103. calculated values.
  104. ****
  105. For example, the script in the following request calculates the day of the week
  106. from the `@timestamp` field, which is defined as a `date` type. The script
  107. calculates the day of the week based on the value of `timestamp`, and uses
  108. `emit` to return the calculated value.
  109. [source,console]
  110. ----
  111. PUT my-index-000001/
  112. {
  113. "mappings": {
  114. "runtime": {
  115. "day_of_week": {
  116. "type": "keyword",
  117. "script": {
  118. "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH))"
  119. }
  120. }
  121. },
  122. "properties": {
  123. "@timestamp": {"type": "date"}
  124. }
  125. }
  126. }
  127. ----
  128. The `runtime` section can be any of these data types:
  129. // tag::runtime-data-types[]
  130. * `boolean`
  131. * `composite`
  132. * `date`
  133. * `double`
  134. * `geo_point`
  135. * `ip`
  136. * `keyword`
  137. * `long`
  138. * <<lookup-runtime-fields, `lookup`>>
  139. // end::runtime-data-types[]
  140. Runtime fields with a `type` of `date` can accept the
  141. <<mapping-date-format,`format`>> parameter exactly as the `date` field type.
  142. Runtime fields with a `type` of `lookup` allow retrieving fields from
  143. related indices. See <<lookup-runtime-fields, `retrieve fields from related indices`>>.
  144. If <<dynamic-field-mapping,dynamic field mapping>> is enabled where the
  145. `dynamic` parameter is set to `runtime`, new fields are automatically added to
  146. the index mapping as runtime fields:
  147. [source,console]
  148. ----
  149. PUT my-index-000001
  150. {
  151. "mappings": {
  152. "dynamic": "runtime",
  153. "properties": {
  154. "@timestamp": {
  155. "type": "date"
  156. }
  157. }
  158. }
  159. }
  160. ----
  161. [[runtime-fields-scriptless]]
  162. ==== Define runtime fields without a script
  163. Runtime fields typically include a Painless script that manipulates data in some
  164. way. However, there are instances where you might define a runtime field
  165. _without_ a script. For example, if you want to retrieve a single field from `_source` without making changes, you don't need a script. You can just create
  166. a runtime field without a script, such as `day_of_week`:
  167. [source,console]
  168. ----
  169. PUT my-index-000001/
  170. {
  171. "mappings": {
  172. "runtime": {
  173. "day_of_week": {
  174. "type": "keyword"
  175. }
  176. }
  177. }
  178. }
  179. ----
  180. When no script is provided, {es} implicitly looks in `_source` at query time
  181. for a field with the same name as the runtime field, and returns a value if one
  182. exists. If a field with the same name doesn’t exist, the response doesn't
  183. include any values for that runtime field.
  184. In most cases, retrieve field values through
  185. <<doc-values,`doc_values`>> whenever possible. Accessing `doc_values` with a
  186. runtime field is faster than retrieving values from `_source` because of how
  187. data is loaded from Lucene.
  188. However, there are cases where retrieving fields from `_source` is necessary.
  189. For example, `text` fields do not have `doc_values` available by default, so you
  190. have to retrieve values from `_source`. In other instances, you might choose to
  191. disable `doc_values` on a specific field.
  192. NOTE: You can alternatively prefix the field you want to retrieve values for
  193. with `params._source` (such as `params._source.day_of_week`). For simplicity,
  194. defining a runtime field in the mapping definition without a script is the
  195. recommended option, whenever possible.
  196. [[runtime-errorhandling]]
  197. ==== Ignoring script errors on runtime fields
  198. Scripts can throw errors at runtime, e.g. on accessing missing or invalid values
  199. in documents or because of performing invalid operations. The `on_script_error`
  200. parameter can be used to control error behaviour when this happens. Setting this
  201. parameter to `continue` will have the effect of silently ignoring all errors on
  202. this runtime field. The default `fail` value will cause a shard failure which
  203. gets reported in the search response.
  204. [[runtime-updating-scripts]]
  205. ==== Updating and removing runtime fields
  206. You can update or remove runtime fields at any time. To replace an existing
  207. runtime field, add a new runtime field to the mappings with the same name. To
  208. remove a runtime field from the mappings, set the value of the runtime field to
  209. `null`:
  210. [source,console]
  211. ----
  212. PUT my-index-000001/_mapping
  213. {
  214. "runtime": {
  215. "day_of_week": null
  216. }
  217. }
  218. ----
  219. //TEST[continued]
  220. .Downstream impacts
  221. ****
  222. Updating or removing a runtime field while a dependent query is running can return
  223. inconsistent results. Each shard might have access to different versions of the
  224. script, depending on when the mapping change takes effect.
  225. WARNING: Existing queries or visualizations in {kib} that rely on runtime fields can
  226. fail if you remove or update the field. For example, a bar chart visualization
  227. that uses a runtime field of type `ip` will fail if the type is changed
  228. to `boolean`, or if the runtime field is removed.
  229. ****
  230. [[runtime-search-request]]
  231. === Define runtime fields in a search request
  232. You can specify a `runtime_mappings` section in a search request to create
  233. runtime fields that exist only as part of the query. You specify a script
  234. as part of the `runtime_mappings` section, just as you would if
  235. <<runtime-mapping-fields,adding a runtime field to the mappings>>.
  236. Defining a runtime field in a search request uses the same format as defining
  237. a runtime field in the index mapping. Just copy the field definition from
  238. the `runtime` in the index mapping to the `runtime_mappings` section of the search request.
  239. The following search request adds a `day_of_week` field to the
  240. `runtime_mappings` section. The field values will be calculated dynamically,
  241. and only within the context of this search request:
  242. [source,console]
  243. ----
  244. GET my-index-000001/_search
  245. {
  246. "runtime_mappings": {
  247. "day_of_week": {
  248. "type": "keyword",
  249. "script": {
  250. "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH))"
  251. }
  252. }
  253. },
  254. "aggs": {
  255. "day_of_week": {
  256. "terms": {
  257. "field": "day_of_week"
  258. }
  259. }
  260. }
  261. }
  262. ----
  263. //TEST[continued]
  264. [[runtime-search-request-examples]]
  265. [discrete]
  266. === Create runtime fields that use other runtime fields
  267. You can even define runtime fields in a search request that return values from
  268. other runtime fields. For example, let's say you bulk index some sensor data:
  269. [source,console]
  270. ----
  271. POST my-index-000001/_bulk?refresh=true
  272. {"index":{}}
  273. {"@timestamp":1516729294000,"model_number":"QVKC92Q","measures":{"voltage":"5.2","start": "300","end":"8675309"}}
  274. {"index":{}}
  275. {"@timestamp":1516642894000,"model_number":"QVKC92Q","measures":{"voltage":"5.8","start": "300","end":"8675309"}}
  276. {"index":{}}
  277. {"@timestamp":1516556494000,"model_number":"QVKC92Q","measures":{"voltage":"5.1","start": "300","end":"8675309"}}
  278. {"index":{}}
  279. {"@timestamp":1516470094000,"model_number":"QVKC92Q","measures":{"voltage":"5.6","start": "300","end":"8675309"}}
  280. {"index":{}}
  281. {"@timestamp":1516383694000,"model_number":"HG537PU","measures":{"voltage":"4.2","start": "400","end":"8625309"}}
  282. {"index":{}}
  283. {"@timestamp":1516297294000,"model_number":"HG537PU","measures":{"voltage":"4.0","start": "400","end":"8625309"}}
  284. ----
  285. You realize after indexing that your numeric data was mapped as type `text`.
  286. You want to aggregate on the `measures.start` and `measures.end` fields, but
  287. the aggregation fails because you can't aggregate on fields of type `text`.
  288. Runtime fields to the rescue! You can add runtime fields with the same name as
  289. your indexed fields and modify the data type:
  290. [source,console]
  291. ----
  292. PUT my-index-000001/_mapping
  293. {
  294. "runtime": {
  295. "measures.start": {
  296. "type": "long"
  297. },
  298. "measures.end": {
  299. "type": "long"
  300. }
  301. }
  302. }
  303. ----
  304. // TEST[continued]
  305. Runtime fields take precedence over fields defined with the same name in the
  306. index mappings. This flexibility allows you to shadow existing fields and
  307. calculate a different value, without modifying the field itself. If you made a
  308. mistake in your index mapping, you can use runtime fields to calculate values
  309. that <<runtime-override-values,override values>> in the mapping during the
  310. search request.
  311. Now, you can easily run an
  312. <<search-aggregations-metrics-avg-aggregation,average aggregation>> on the
  313. `measures.start` and `measures.end` fields:
  314. [source,console]
  315. ----
  316. GET my-index-000001/_search
  317. {
  318. "aggs": {
  319. "avg_start": {
  320. "avg": {
  321. "field": "measures.start"
  322. }
  323. },
  324. "avg_end": {
  325. "avg": {
  326. "field": "measures.end"
  327. }
  328. }
  329. }
  330. }
  331. ----
  332. // TEST[continued]
  333. // TEST[s/_search/_search\?filter_path=aggregations/]
  334. The response includes the aggregation results without changing the values for
  335. the underlying data:
  336. [source,console-result]
  337. ----
  338. {
  339. "aggregations" : {
  340. "avg_start" : {
  341. "value" : 333.3333333333333
  342. },
  343. "avg_end" : {
  344. "value" : 8658642.333333334
  345. }
  346. }
  347. }
  348. ----
  349. Further, you can define a runtime field as part of a search query that
  350. calculates a value, and then run a
  351. <<search-aggregations-metrics-stats-aggregation,stats aggregation>> on that
  352. field _in the same query_.
  353. The `duration` runtime field doesn't exist in the index mapping, but we can
  354. still search and aggregate on that field. The following query returns the
  355. calculated value for the `duration` field and runs a stats aggregation to
  356. compute statistics over numeric values extracted from the aggregated documents.
  357. [source,console]
  358. ----
  359. GET my-index-000001/_search
  360. {
  361. "runtime_mappings": {
  362. "duration": {
  363. "type": "long",
  364. "script": {
  365. "source": """
  366. emit(doc['measures.end'].value - doc['measures.start'].value);
  367. """
  368. }
  369. }
  370. },
  371. "aggs": {
  372. "duration_stats": {
  373. "stats": {
  374. "field": "duration"
  375. }
  376. }
  377. }
  378. }
  379. ----
  380. // TEST[continued]
  381. // TEST[s/_search/_search\?filter_path=aggregations/]
  382. Even though the `duration` runtime field only exists in the context of a search
  383. query, you can search and aggregate on that field. This flexibility is
  384. incredibly powerful, enabling you to rectify mistakes in your index mappings
  385. and dynamically complete calculations all within a single search request.
  386. [source,console-result]
  387. ----
  388. {
  389. "aggregations" : {
  390. "duration_stats" : {
  391. "count" : 6,
  392. "min" : 8624909.0,
  393. "max" : 8675009.0,
  394. "avg" : 8658309.0,
  395. "sum" : 5.1949854E7
  396. }
  397. }
  398. }
  399. ----
  400. [[runtime-override-values]]
  401. === Override field values at query time
  402. If you create a runtime field with the same name as a field that
  403. already exists in the mapping, the runtime field shadows the mapped field. At
  404. query time, {es} evaluates the runtime field, calculates a value based on the
  405. script, and returns the value as part of the query. Because the runtime field
  406. shadows the mapped field, you can override the value returned in search without
  407. modifying the mapped field.
  408. For example, let's say you indexed the following documents into `my-index-000001`:
  409. [source,console]
  410. ----
  411. POST my-index-000001/_bulk?refresh=true
  412. {"index":{}}
  413. {"@timestamp":1516729294000,"model_number":"QVKC92Q","measures":{"voltage":5.2}}
  414. {"index":{}}
  415. {"@timestamp":1516642894000,"model_number":"QVKC92Q","measures":{"voltage":5.8}}
  416. {"index":{}}
  417. {"@timestamp":1516556494000,"model_number":"QVKC92Q","measures":{"voltage":5.1}}
  418. {"index":{}}
  419. {"@timestamp":1516470094000,"model_number":"QVKC92Q","measures":{"voltage":5.6}}
  420. {"index":{}}
  421. {"@timestamp":1516383694000,"model_number":"HG537PU","measures":{"voltage":4.2}}
  422. {"index":{}}
  423. {"@timestamp":1516297294000,"model_number":"HG537PU","measures":{"voltage":4.0}}
  424. ----
  425. You later realize that the `HG537PU` sensors aren't reporting their true
  426. voltage. The indexed values are supposed to be 1.7 times higher than
  427. the reported values! Instead of reindexing your data, you can define a script in
  428. the `runtime_mappings` section of the `_search` request to shadow the `voltage`
  429. field and calculate a new value at query time.
  430. If you search for documents where the model number matches `HG537PU`:
  431. [source,console]
  432. ----
  433. GET my-index-000001/_search
  434. {
  435. "query": {
  436. "match": {
  437. "model_number": "HG537PU"
  438. }
  439. }
  440. }
  441. ----
  442. //TEST[continued]
  443. The response includes indexed values for documents matching model number
  444. `HG537PU`:
  445. [source,console-result]
  446. ----
  447. {
  448. ...
  449. "hits" : {
  450. "total" : {
  451. "value" : 2,
  452. "relation" : "eq"
  453. },
  454. "max_score" : 1.0296195,
  455. "hits" : [
  456. {
  457. "_index" : "my-index-000001",
  458. "_id" : "F1BeSXYBg_szTodcYCmk",
  459. "_score" : 1.0296195,
  460. "_source" : {
  461. "@timestamp" : 1516383694000,
  462. "model_number" : "HG537PU",
  463. "measures" : {
  464. "voltage" : 4.2
  465. }
  466. }
  467. },
  468. {
  469. "_index" : "my-index-000001",
  470. "_id" : "l02aSXYBkpNf6QRDO62Q",
  471. "_score" : 1.0296195,
  472. "_source" : {
  473. "@timestamp" : 1516297294000,
  474. "model_number" : "HG537PU",
  475. "measures" : {
  476. "voltage" : 4.0
  477. }
  478. }
  479. }
  480. ]
  481. }
  482. }
  483. ----
  484. // TESTRESPONSE[s/\.\.\./"took" : $body.took,"timed_out" : $body.timed_out,"_shards" : $body._shards,/]
  485. // TESTRESPONSE[s/"_id" : "F1BeSXYBg_szTodcYCmk"/"_id": $body.hits.hits.0._id/]
  486. // TESTRESPONSE[s/"_id" : "l02aSXYBkpNf6QRDO62Q"/"_id": $body.hits.hits.1._id/]
  487. The following request defines a runtime field where the script evaluates the
  488. `model_number` field where the value is `HG537PU`. For each match, the script
  489. multiplies the value for the `voltage` field by `1.7`.
  490. Using the <<search-fields,`fields`>> parameter on the `_search` API, you can
  491. retrieve the value that the script calculates for the `measures.voltage` field
  492. for documents matching the search request:
  493. [source,console]
  494. ----
  495. POST my-index-000001/_search
  496. {
  497. "runtime_mappings": {
  498. "measures.voltage": {
  499. "type": "double",
  500. "script": {
  501. "source":
  502. """if (doc['model_number.keyword'].value.equals('HG537PU'))
  503. {emit(1.7 * params._source['measures']['voltage']);}
  504. else{emit(params._source['measures']['voltage']);}"""
  505. }
  506. }
  507. },
  508. "query": {
  509. "match": {
  510. "model_number": "HG537PU"
  511. }
  512. },
  513. "fields": ["measures.voltage"]
  514. }
  515. ----
  516. //TEST[continued]
  517. Looking at the response, the calculated values for `measures.voltage` on each
  518. result are `7.14` and `6.8`. That's more like it! The runtime field calculated
  519. this value as part of the search request without modifying the mapped value,
  520. which still returns in the response:
  521. [source,console-result]
  522. ----
  523. {
  524. ...
  525. "hits" : {
  526. "total" : {
  527. "value" : 2,
  528. "relation" : "eq"
  529. },
  530. "max_score" : 1.0296195,
  531. "hits" : [
  532. {
  533. "_index" : "my-index-000001",
  534. "_id" : "F1BeSXYBg_szTodcYCmk",
  535. "_score" : 1.0296195,
  536. "_source" : {
  537. "@timestamp" : 1516383694000,
  538. "model_number" : "HG537PU",
  539. "measures" : {
  540. "voltage" : 4.2
  541. }
  542. },
  543. "fields" : {
  544. "measures.voltage" : [
  545. 7.14
  546. ]
  547. }
  548. },
  549. {
  550. "_index" : "my-index-000001",
  551. "_id" : "l02aSXYBkpNf6QRDO62Q",
  552. "_score" : 1.0296195,
  553. "_source" : {
  554. "@timestamp" : 1516297294000,
  555. "model_number" : "HG537PU",
  556. "measures" : {
  557. "voltage" : 4.0
  558. }
  559. },
  560. "fields" : {
  561. "measures.voltage" : [
  562. 6.8
  563. ]
  564. }
  565. }
  566. ]
  567. }
  568. }
  569. ----
  570. // TESTRESPONSE[s/\.\.\./"took" : $body.took,"timed_out" : $body.timed_out,"_shards" : $body._shards,/]
  571. // TESTRESPONSE[s/"_id" : "F1BeSXYBg_szTodcYCmk"/"_id": $body.hits.hits.0._id/]
  572. // TESTRESPONSE[s/"_id" : "l02aSXYBkpNf6QRDO62Q"/"_id": $body.hits.hits.1._id/]
  573. [[runtime-retrieving-fields]]
  574. === Retrieve a runtime field
  575. Use the <<search-fields,`fields`>> parameter on the `_search` API to retrieve
  576. the values of runtime fields. Runtime fields won't display in `_source`, but
  577. the `fields` API works for all fields, even those that were not sent as part of
  578. the original `_source`.
  579. [[runtime-define-field-dayofweek]]
  580. ==== Define a runtime field to calculate the day of week
  581. For example, the following request adds a runtime field called `day_of_week`.
  582. The runtime field includes a script that calculates the day of the week based
  583. on the value of the `@timestamp` field. We'll include `"dynamic":"runtime"` in
  584. the request so that new fields are added to the mapping as runtime fields.
  585. [source,console]
  586. ----
  587. PUT my-index-000001/
  588. {
  589. "mappings": {
  590. "dynamic": "runtime",
  591. "runtime": {
  592. "day_of_week": {
  593. "type": "keyword",
  594. "script": {
  595. "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH))"
  596. }
  597. }
  598. },
  599. "properties": {
  600. "@timestamp": {"type": "date"}
  601. }
  602. }
  603. }
  604. ----
  605. [[runtime-ingest-data]]
  606. ==== Ingest some data
  607. Let's ingest some sample data, which will result in two indexed fields:
  608. `@timestamp` and `message`.
  609. [source,console]
  610. ----
  611. POST /my-index-000001/_bulk?refresh
  612. { "index": {}}
  613. { "@timestamp": "2020-06-21T15:00:01-05:00", "message" : "211.11.9.0 - - [2020-06-21T15:00:01-05:00] \"GET /english/index.html HTTP/1.0\" 304 0"}
  614. { "index": {}}
  615. { "@timestamp": "2020-06-21T15:00:01-05:00", "message" : "211.11.9.0 - - [2020-06-21T15:00:01-05:00] \"GET /english/index.html HTTP/1.0\" 304 0"}
  616. { "index": {}}
  617. { "@timestamp": "2020-04-30T14:30:17-05:00", "message" : "40.135.0.0 - - [2020-04-30T14:30:17-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  618. { "index": {}}
  619. { "@timestamp": "2020-04-30T14:30:53-05:00", "message" : "232.0.0.0 - - [2020-04-30T14:30:53-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  620. { "index": {}}
  621. { "@timestamp": "2020-04-30T14:31:12-05:00", "message" : "26.1.0.0 - - [2020-04-30T14:31:12-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  622. { "index": {}}
  623. { "@timestamp": "2020-04-30T14:31:19-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:19-05:00] \"GET /french/splash_inet.html HTTP/1.0\" 200 3781"}
  624. { "index": {}}
  625. { "@timestamp": "2020-04-30T14:31:27-05:00", "message" : "252.0.0.0 - - [2020-04-30T14:31:27-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  626. { "index": {}}
  627. { "@timestamp": "2020-04-30T14:31:29-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:29-05:00] \"GET /images/hm_brdl.gif HTTP/1.0\" 304 0"}
  628. { "index": {}}
  629. { "@timestamp": "2020-04-30T14:31:29-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:29-05:00] \"GET /images/hm_arw.gif HTTP/1.0\" 304 0"}
  630. { "index": {}}
  631. { "@timestamp": "2020-04-30T14:31:32-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:32-05:00] \"GET /images/nav_bg_top.gif HTTP/1.0\" 200 929"}
  632. { "index": {}}
  633. { "@timestamp": "2020-04-30T14:31:43-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:43-05:00] \"GET /french/images/nav_venue_off.gif HTTP/1.0\" 304 0"}
  634. ----
  635. //TEST[continued]
  636. [[runtime-search-dayofweek]]
  637. ==== Search for the calculated day of week
  638. The following request uses the search API to retrieve the `day_of_week` field
  639. that the original request defined as a runtime field in the mapping. The value
  640. for this field is calculated dynamically at query time without reindexing
  641. documents or indexing the `day_of_week` field. This flexibility allows you to
  642. modify the mapping without changing any field values.
  643. [source,console]
  644. ----
  645. GET my-index-000001/_search
  646. {
  647. "fields": [
  648. "@timestamp",
  649. "day_of_week"
  650. ],
  651. "_source": false
  652. }
  653. ----
  654. // TEST[continued]
  655. The previous request returns the `day_of_week` field for all matching documents.
  656. We can define another runtime field called `client_ip` that also operates on
  657. the `message` field and will further refine the query:
  658. [source,console]
  659. ----
  660. PUT /my-index-000001/_mapping
  661. {
  662. "runtime": {
  663. "client_ip": {
  664. "type": "ip",
  665. "script" : {
  666. "source" : "String m = doc[\"message\"].value; int end = m.indexOf(\" \"); emit(m.substring(0, end));"
  667. }
  668. }
  669. }
  670. }
  671. ----
  672. //TEST[continued]
  673. Run another query, but search for a specific IP address using the `client_ip`
  674. runtime field:
  675. [source,console]
  676. ----
  677. GET my-index-000001/_search
  678. {
  679. "size": 1,
  680. "query": {
  681. "match": {
  682. "client_ip": "211.11.9.0"
  683. }
  684. },
  685. "fields" : ["*"]
  686. }
  687. ----
  688. //TEST[continued]
  689. This time, the response includes only two hits. The value for `day_of_week`
  690. (`Sunday`) was calculated at query time using the runtime script defined in the
  691. mapping, and the result includes only documents matching the `211.11.9.0` IP
  692. address.
  693. [source,console-result]
  694. ----
  695. {
  696. ...
  697. "hits" : {
  698. "total" : {
  699. "value" : 2,
  700. "relation" : "eq"
  701. },
  702. "max_score" : 1.0,
  703. "hits" : [
  704. {
  705. "_index" : "my-index-000001",
  706. "_id" : "oWs5KXYB-XyJbifr9mrz",
  707. "_score" : 1.0,
  708. "_source" : {
  709. "@timestamp" : "2020-06-21T15:00:01-05:00",
  710. "message" : "211.11.9.0 - - [2020-06-21T15:00:01-05:00] \"GET /english/index.html HTTP/1.0\" 304 0"
  711. },
  712. "fields" : {
  713. "@timestamp" : [
  714. "2020-06-21T20:00:01.000Z"
  715. ],
  716. "client_ip" : [
  717. "211.11.9.0"
  718. ],
  719. "message" : [
  720. "211.11.9.0 - - [2020-06-21T15:00:01-05:00] \"GET /english/index.html HTTP/1.0\" 304 0"
  721. ],
  722. "day_of_week" : [
  723. "Sunday"
  724. ]
  725. }
  726. }
  727. ]
  728. }
  729. }
  730. ----
  731. // TESTRESPONSE[s/\.\.\./"took" : $body.took,"timed_out" : $body.timed_out,"_shards" : $body._shards,/]
  732. // TESTRESPONSE[s/"_id" : "oWs5KXYB-XyJbifr9mrz"/"_id": $body.hits.hits.0._id/]
  733. // TESTRESPONSE[s/"day_of_week" : \[\n\s+"Sunday"\n\s\]/"day_of_week": $body.hits.hits.0.fields.day_of_week/]
  734. [[lookup-runtime-fields]]
  735. ==== Retrieve fields from related indices
  736. The <<search-fields,`fields`>> parameter on the `_search` API can also be used to retrieve fields from
  737. the related indices via runtime fields with a type of `lookup`.
  738. NOTE: Fields that are retrieved by runtime fields of type `lookup` can be used
  739. to enrich the hits in a search response. It's not possible to query or aggregate
  740. on these fields.
  741. [source,console]
  742. ----
  743. POST ip_location/_doc?refresh
  744. {
  745. "ip": "192.168.1.1",
  746. "country": "Canada",
  747. "city": "Montreal"
  748. }
  749. PUT logs/_doc/1?refresh
  750. {
  751. "host": "192.168.1.1",
  752. "message": "the first message"
  753. }
  754. PUT logs/_doc/2?refresh
  755. {
  756. "host": "192.168.1.2",
  757. "message": "the second message"
  758. }
  759. POST logs/_search
  760. {
  761. "runtime_mappings": {
  762. "location": {
  763. "type": "lookup", <1>
  764. "target_index": "ip_location", <2>
  765. "input_field": "host", <3>
  766. "target_field": "ip", <4>
  767. "fetch_fields": ["country", "city"] <5>
  768. }
  769. },
  770. "fields": [
  771. "host",
  772. "message",
  773. "location"
  774. ],
  775. "_source": false
  776. }
  777. ----
  778. <1> Define a runtime field in the main search request with a type of `lookup` that retrieves fields from the target index using the <<query-dsl-term-query, `term`>> queries.
  779. <2> The target index where the lookup query executes against
  780. <3> A field on the main index whose values are used as the input values of the lookup term query
  781. <4> A field on the lookup index which the lookup query searches against
  782. <5> A list of fields to retrieve from the lookup index. See the <<search-fields, `fields`>> parameter of a search request.
  783. The above search returns the country and city from the `ip_location` index
  784. for each ip address of the returned search hits.
  785. [source,console-result]
  786. ----
  787. {
  788. "took": 3,
  789. "timed_out": false,
  790. "_shards": {
  791. "total": 1,
  792. "successful": 1,
  793. "skipped": 0,
  794. "failed": 0
  795. },
  796. "hits": {
  797. "total": {
  798. "value": 2,
  799. "relation": "eq"
  800. },
  801. "max_score": 1.0,
  802. "hits": [
  803. {
  804. "_index": "logs",
  805. "_id": "1",
  806. "_score": 1.0,
  807. "fields": {
  808. "host": [ "192.168.1.1" ],
  809. "location": [
  810. {
  811. "city": [ "Montreal" ],
  812. "country": [ "Canada" ]
  813. }
  814. ],
  815. "message": [ "the first message" ]
  816. }
  817. },
  818. {
  819. "_index": "logs",
  820. "_id": "2",
  821. "_score": 1.0,
  822. "fields": {
  823. "host": [ "192.168.1.2" ],
  824. "message": [ "the second message" ]
  825. }
  826. }
  827. ]
  828. }
  829. }
  830. ----
  831. // TESTRESPONSE[s/"took": 3/"took": $body.took/]
  832. The response of lookup fields are grouped to maintain the independence
  833. of each document from the lookup index. The lookup query for each input
  834. value is expected to match at most one document on the lookup index.
  835. If the lookup query matches more than one documents, then a random document
  836. will be selected.
  837. [[runtime-indexed]]
  838. === Index a runtime field
  839. Runtime fields are defined by the context where they run. For example, you
  840. can define runtime fields in the
  841. <<runtime-search-request,context of a search query>> or within the
  842. <<runtime-mapping-fields,`runtime` section>> of an index mapping. If you
  843. decide to index a runtime field for greater performance, just move the full
  844. runtime field definition (including the script) to the context of an index
  845. mapping. {es} automatically uses these indexed fields to drive queries,
  846. resulting in a fast response time. This capability means you can write a
  847. script only once, and apply it to any context that supports runtime fields.
  848. NOTE: Indexing a `composite` runtime field is currently not supported.
  849. You can then use runtime fields to limit the number of fields that {es} needs
  850. to calculate values for. Using indexed fields in tandem with runtime fields
  851. provides flexibility in the data that you index and how you define queries for
  852. other fields.
  853. IMPORTANT: After indexing a runtime field, you cannot update the included
  854. script. If you need to change the script, create a new field with the updated
  855. script.
  856. For example, let's say your company wants to replace some old pressure
  857. valves. The connected sensors are only capable of reporting a fraction of
  858. the true readings. Rather than outfit the pressure valves with new sensors,
  859. you decide to calculate the values based on reported readings. Based on the
  860. reported data, you define the following fields in your mapping for
  861. `my-index-000001`:
  862. [source,console]
  863. ----
  864. PUT my-index-000001/
  865. {
  866. "mappings": {
  867. "properties": {
  868. "timestamp": {
  869. "type": "date"
  870. },
  871. "temperature": {
  872. "type": "long"
  873. },
  874. "voltage": {
  875. "type": "double"
  876. },
  877. "node": {
  878. "type": "keyword"
  879. }
  880. }
  881. }
  882. }
  883. ----
  884. You then bulk index some sample data from your sensors. This data includes
  885. `voltage` readings for each sensor:
  886. [source,console]
  887. ----
  888. POST my-index-000001/_bulk?refresh=true
  889. {"index":{}}
  890. {"timestamp": 1516729294000, "temperature": 200, "voltage": 5.2, "node": "a"}
  891. {"index":{}}
  892. {"timestamp": 1516642894000, "temperature": 201, "voltage": 5.8, "node": "b"}
  893. {"index":{}}
  894. {"timestamp": 1516556494000, "temperature": 202, "voltage": 5.1, "node": "a"}
  895. {"index":{}}
  896. {"timestamp": 1516470094000, "temperature": 198, "voltage": 5.6, "node": "b"}
  897. {"index":{}}
  898. {"timestamp": 1516383694000, "temperature": 200, "voltage": 4.2, "node": "c"}
  899. {"index":{}}
  900. {"timestamp": 1516297294000, "temperature": 202, "voltage": 4.0, "node": "c"}
  901. ----
  902. // TEST[continued]
  903. After talking to a few site engineers, you realize that the sensors should
  904. be reporting at least _double_ the current values, but potentially higher.
  905. You create a runtime field named `voltage_corrected` that retrieves the current
  906. voltage and multiplies it by `2`:
  907. [source,console]
  908. ----
  909. PUT my-index-000001/_mapping
  910. {
  911. "runtime": {
  912. "voltage_corrected": {
  913. "type": "double",
  914. "script": {
  915. "source": """
  916. emit(doc['voltage'].value * params['multiplier'])
  917. """,
  918. "params": {
  919. "multiplier": 2
  920. }
  921. }
  922. }
  923. }
  924. }
  925. ----
  926. // TEST[continued]
  927. You retrieve the calculated values using the <<search-fields,`fields`>>
  928. parameter on the `_search` API:
  929. [source,console]
  930. ----
  931. GET my-index-000001/_search
  932. {
  933. "fields": [
  934. "voltage_corrected",
  935. "node"
  936. ],
  937. "size": 2
  938. }
  939. ----
  940. // TEST[continued]
  941. // TEST[s/_search/_search\?filter_path=hits/]
  942. //
  943. ////
  944. [source,console-result]
  945. ----
  946. {
  947. "hits" : {
  948. "total" : {
  949. "value" : 6,
  950. "relation" : "eq"
  951. },
  952. "max_score" : 1.0,
  953. "hits" : [
  954. {
  955. "_index" : "my-index-000001",
  956. "_id" : "z4TCrHgBdg9xpPrU6z9k",
  957. "_score" : 1.0,
  958. "_source" : {
  959. "timestamp" : 1516729294000,
  960. "temperature" : 200,
  961. "voltage" : 5.2,
  962. "node" : "a"
  963. },
  964. "fields" : {
  965. "voltage_corrected" : [
  966. 10.4
  967. ],
  968. "node" : [
  969. "a"
  970. ]
  971. }
  972. },
  973. {
  974. "_index" : "my-index-000001",
  975. "_id" : "0ITCrHgBdg9xpPrU6z9k",
  976. "_score" : 1.0,
  977. "_source" : {
  978. "timestamp" : 1516642894000,
  979. "temperature" : 201,
  980. "voltage" : 5.8,
  981. "node" : "b"
  982. },
  983. "fields" : {
  984. "voltage_corrected" : [
  985. 11.6
  986. ],
  987. "node" : [
  988. "b"
  989. ]
  990. }
  991. }
  992. ]
  993. }
  994. }
  995. ----
  996. // TESTRESPONSE[s/"_id" : "z4TCrHgBdg9xpPrU6z9k"/"_id": $body.hits.hits.0._id/]
  997. // TESTRESPONSE[s/"_id" : "0ITCrHgBdg9xpPrU6z9k"/"_id": $body.hits.hits.1._id/]
  998. ////
  999. //
  1000. After reviewing the sensor data and running some tests, you determine that the
  1001. multiplier for reported sensor data should be `4`. To gain greater performance,
  1002. you decide to index the `voltage_corrected` runtime field with the new
  1003. `multiplier` parameter.
  1004. In a new index named `my-index-000001`, copy the `voltage_corrected` runtime
  1005. field definition into the mappings of the new index. It's that simple! You can
  1006. add an optional parameter named `on_script_error` that determines whether to
  1007. reject the entire document if the script throws an error at index time
  1008. (default).
  1009. [source,console]
  1010. ----
  1011. PUT my-index-000001/
  1012. {
  1013. "mappings": {
  1014. "properties": {
  1015. "timestamp": {
  1016. "type": "date"
  1017. },
  1018. "temperature": {
  1019. "type": "long"
  1020. },
  1021. "voltage": {
  1022. "type": "double"
  1023. },
  1024. "node": {
  1025. "type": "keyword"
  1026. },
  1027. "voltage_corrected": {
  1028. "type": "double",
  1029. "on_script_error": "fail", <1>
  1030. "script": {
  1031. "source": """
  1032. emit(doc['voltage'].value * params['multiplier'])
  1033. """,
  1034. "params": {
  1035. "multiplier": 4
  1036. }
  1037. }
  1038. }
  1039. }
  1040. }
  1041. }
  1042. ----
  1043. <1> Causes the entire document to be rejected if the script throws an error at
  1044. index time. Setting the value to `ignore` will register the field in the
  1045. document’s `_ignored` metadata field and continue indexing.
  1046. Bulk index some sample data from your sensors into the `my-index-000001` index:
  1047. [source,console]
  1048. ----
  1049. POST my-index-000001/_bulk?refresh=true
  1050. { "index": {}}
  1051. { "timestamp": 1516729294000, "temperature": 200, "voltage": 5.2, "node": "a"}
  1052. { "index": {}}
  1053. { "timestamp": 1516642894000, "temperature": 201, "voltage": 5.8, "node": "b"}
  1054. { "index": {}}
  1055. { "timestamp": 1516556494000, "temperature": 202, "voltage": 5.1, "node": "a"}
  1056. { "index": {}}
  1057. { "timestamp": 1516470094000, "temperature": 198, "voltage": 5.6, "node": "b"}
  1058. { "index": {}}
  1059. { "timestamp": 1516383694000, "temperature": 200, "voltage": 4.2, "node": "c"}
  1060. { "index": {}}
  1061. { "timestamp": 1516297294000, "temperature": 202, "voltage": 4.0, "node": "c"}
  1062. ----
  1063. // TEST[continued]
  1064. You can now retrieve calculated values in a search query, and find documents
  1065. based on precise values. The following range query returns all documents where
  1066. the calculated `voltage_corrected` is greater than or equal to `16`, but less
  1067. than or equal to `20`. Again, use the <<search-fields,`fields`>> parameter on
  1068. the `_search` API to retrieve the fields you want:
  1069. [source,console]
  1070. ----
  1071. POST my-index-000001/_search
  1072. {
  1073. "query": {
  1074. "range": {
  1075. "voltage_corrected": {
  1076. "gte": 16,
  1077. "lte": 20,
  1078. "boost": 1.0
  1079. }
  1080. }
  1081. },
  1082. "fields": ["voltage_corrected", "node"]
  1083. }
  1084. ----
  1085. // TEST[continued]
  1086. // TEST[s/_search/_search\?filter_path=hits/]
  1087. The response includes the `voltage_corrected` field for the documents that
  1088. match the range query, based on the calculated value of the included script:
  1089. [source,console-result]
  1090. ----
  1091. {
  1092. "hits" : {
  1093. "total" : {
  1094. "value" : 2,
  1095. "relation" : "eq"
  1096. },
  1097. "max_score" : 1.0,
  1098. "hits" : [
  1099. {
  1100. "_index" : "my-index-000001",
  1101. "_id" : "yoSLrHgBdg9xpPrUZz_P",
  1102. "_score" : 1.0,
  1103. "_source" : {
  1104. "timestamp" : 1516383694000,
  1105. "temperature" : 200,
  1106. "voltage" : 4.2,
  1107. "node" : "c"
  1108. },
  1109. "fields" : {
  1110. "voltage_corrected" : [
  1111. 16.8
  1112. ],
  1113. "node" : [
  1114. "c"
  1115. ]
  1116. }
  1117. },
  1118. {
  1119. "_index" : "my-index-000001",
  1120. "_id" : "y4SLrHgBdg9xpPrUZz_P",
  1121. "_score" : 1.0,
  1122. "_source" : {
  1123. "timestamp" : 1516297294000,
  1124. "temperature" : 202,
  1125. "voltage" : 4.0,
  1126. "node" : "c"
  1127. },
  1128. "fields" : {
  1129. "voltage_corrected" : [
  1130. 16.0
  1131. ],
  1132. "node" : [
  1133. "c"
  1134. ]
  1135. }
  1136. }
  1137. ]
  1138. }
  1139. }
  1140. ----
  1141. // TESTRESPONSE[s/"_id" : "yoSLrHgBdg9xpPrUZz_P"/"_id": $body.hits.hits.0._id/]
  1142. // TESTRESPONSE[s/"_id" : "y4SLrHgBdg9xpPrUZz_P"/"_id": $body.hits.hits.1._id/]
  1143. [[runtime-examples]]
  1144. === Explore your data with runtime fields
  1145. Consider a large set of log data that you want to extract fields from.
  1146. Indexing the data is time consuming and uses a lot of disk space, and you just
  1147. want to explore the data structure without committing to a schema up front.
  1148. You know that your log data contains specific fields that you want to extract.
  1149. In this case, we want to focus on the `@timestamp` and `message` fields. By
  1150. using runtime fields, you can define scripts to calculate values at search
  1151. time for these fields.
  1152. [[runtime-examples-define-fields]]
  1153. ==== Define indexed fields as a starting point
  1154. You can start with a simple example by adding the `@timestamp` and `message`
  1155. fields to the `my-index-000001` mapping as indexed fields. To remain flexible, use
  1156. `wildcard` as the field type for `message`:
  1157. [source,console]
  1158. ----
  1159. PUT /my-index-000001/
  1160. {
  1161. "mappings": {
  1162. "properties": {
  1163. "@timestamp": {
  1164. "format": "strict_date_optional_time||epoch_second",
  1165. "type": "date"
  1166. },
  1167. "message": {
  1168. "type": "wildcard"
  1169. }
  1170. }
  1171. }
  1172. }
  1173. ----
  1174. [[runtime-examples-ingest-data]]
  1175. ==== Ingest some data
  1176. After mapping the fields you want to retrieve, index a few records from
  1177. your log data into {es}. The following request uses the <<docs-bulk,bulk API>>
  1178. to index raw log data into `my-index-000001`. Instead of indexing all of your log
  1179. data, you can use a small sample to experiment with runtime fields.
  1180. The final document is not a valid Apache log format, but we can account for
  1181. that scenario in our script.
  1182. [source,console]
  1183. ----
  1184. POST /my-index-000001/_bulk?refresh
  1185. {"index":{}}
  1186. {"timestamp":"2020-04-30T14:30:17-05:00","message":"40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  1187. {"index":{}}
  1188. {"timestamp":"2020-04-30T14:30:53-05:00","message":"232.0.0.0 - - [30/Apr/2020:14:30:53 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  1189. {"index":{}}
  1190. {"timestamp":"2020-04-30T14:31:12-05:00","message":"26.1.0.0 - - [30/Apr/2020:14:31:12 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  1191. {"index":{}}
  1192. {"timestamp":"2020-04-30T14:31:19-05:00","message":"247.37.0.0 - - [30/Apr/2020:14:31:19 -0500] \"GET /french/splash_inet.html HTTP/1.0\" 200 3781"}
  1193. {"index":{}}
  1194. {"timestamp":"2020-04-30T14:31:22-05:00","message":"247.37.0.0 - - [30/Apr/2020:14:31:22 -0500] \"GET /images/hm_nbg.jpg HTTP/1.0\" 304 0"}
  1195. {"index":{}}
  1196. {"timestamp":"2020-04-30T14:31:27-05:00","message":"252.0.0.0 - - [30/Apr/2020:14:31:27 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  1197. {"index":{}}
  1198. {"timestamp":"2020-04-30T14:31:28-05:00","message":"not a valid apache log"}
  1199. ----
  1200. // TEST[continued]
  1201. At this point, you can view how {es} stores your raw data.
  1202. [source,console]
  1203. ----
  1204. GET /my-index-000001
  1205. ----
  1206. // TEST[continued]
  1207. The mapping contains two fields: `@timestamp` and `message`.
  1208. [source,console-result]
  1209. ----
  1210. {
  1211. "my-index-000001" : {
  1212. "aliases" : { },
  1213. "mappings" : {
  1214. "properties" : {
  1215. "@timestamp" : {
  1216. "type" : "date",
  1217. "format" : "strict_date_optional_time||epoch_second"
  1218. },
  1219. "message" : {
  1220. "type" : "wildcard"
  1221. },
  1222. "timestamp" : {
  1223. "type" : "date"
  1224. }
  1225. }
  1226. },
  1227. ...
  1228. }
  1229. }
  1230. ----
  1231. // TESTRESPONSE[s/\.\.\./"settings": $body.my-index-000001.settings/]
  1232. [[runtime-examples-grok]]
  1233. ==== Define a runtime field with a grok pattern
  1234. If you want to retrieve results that include `clientip`, you can add that
  1235. field as a runtime field in the mapping. The following runtime script defines a
  1236. <<grok,grok pattern>> that extracts structured fields out of a single text
  1237. field within a document. A grok pattern is like a regular expression that
  1238. supports aliased expressions that you can reuse.
  1239. The script matches on the `%{COMMONAPACHELOG}` log pattern, which understands
  1240. the structure of Apache logs. If the pattern matches (`clientip != null`),
  1241. the script emits the value of the matching IP address. If the pattern doesn't
  1242. match, the script just returns the field value without crashing.
  1243. [source,console]
  1244. ----
  1245. PUT my-index-000001/_mappings
  1246. {
  1247. "runtime": {
  1248. "http.client_ip": {
  1249. "type": "ip",
  1250. "script": """
  1251. String clientip=grok('%{COMMONAPACHELOG}').extract(doc["message"].value)?.clientip;
  1252. if (clientip != null) emit(clientip); <1>
  1253. """
  1254. }
  1255. }
  1256. }
  1257. ----
  1258. // TEST[continued]
  1259. <1> This condition ensures that the script doesn't crash even if the pattern of
  1260. the message doesn't match.
  1261. Alternatively, you can define the same runtime field but in the context of a
  1262. search request. The runtime definition and the script are exactly the same as
  1263. the one defined previously in the index mapping. Just copy that definition into
  1264. the search request under the `runtime_mappings` section and include a query
  1265. that matches on the runtime field. This query returns the same results as if
  1266. you defined a search query for the `http.clientip` runtime field in your index
  1267. mappings, but only in the context of this specific search:
  1268. [source,console]
  1269. ----
  1270. GET my-index-000001/_search
  1271. {
  1272. "runtime_mappings": {
  1273. "http.clientip": {
  1274. "type": "ip",
  1275. "script": """
  1276. String clientip=grok('%{COMMONAPACHELOG}').extract(doc["message"].value)?.clientip;
  1277. if (clientip != null) emit(clientip);
  1278. """
  1279. }
  1280. },
  1281. "query": {
  1282. "match": {
  1283. "http.clientip": "40.135.0.0"
  1284. }
  1285. },
  1286. "fields" : ["http.clientip"]
  1287. }
  1288. ----
  1289. // TEST[continued]
  1290. [[runtime-examples-grok-composite]]
  1291. ==== Define a composite runtime field
  1292. You can also define a _composite_ runtime field to emit multiple fields from a
  1293. single script. You can define a set of typed subfields and emit a map of
  1294. values. At search time, each subfield retrieves the value associated with
  1295. their name in the map. This means that you only need to specify your grok
  1296. pattern one time and can return multiple values:
  1297. [source,console]
  1298. ----
  1299. PUT my-index-000001/_mappings
  1300. {
  1301. "runtime": {
  1302. "http": {
  1303. "type": "composite",
  1304. "script": "emit(grok(\"%{COMMONAPACHELOG}\").extract(doc[\"message\"].value))",
  1305. "fields": {
  1306. "clientip": {
  1307. "type": "ip"
  1308. },
  1309. "verb": {
  1310. "type": "keyword"
  1311. },
  1312. "response": {
  1313. "type": "long"
  1314. }
  1315. }
  1316. }
  1317. }
  1318. }
  1319. ----
  1320. // TEST[continued]
  1321. [[runtime-examples-grok-ip]]
  1322. ===== Search for a specific IP address
  1323. Using the `http.clientip` runtime field, you can define a simple query to run a
  1324. search for a specific IP address and return all related fields.
  1325. [source,console]
  1326. ----
  1327. GET my-index-000001/_search
  1328. {
  1329. "query": {
  1330. "match": {
  1331. "http.clientip": "40.135.0.0"
  1332. }
  1333. },
  1334. "fields" : ["*"]
  1335. }
  1336. ----
  1337. // TEST[continued]
  1338. The API returns the following result. Because `http` is a `composite` runtime
  1339. field, the response includes each of the sub-fields under `fields`, including
  1340. any associated values that match the query. Without building your data structure
  1341. in advance, you can search and explore your data in meaningful ways to
  1342. experiment and determine which fields to index.
  1343. [source,console-result]
  1344. ----
  1345. {
  1346. ...
  1347. "hits" : {
  1348. "total" : {
  1349. "value" : 1,
  1350. "relation" : "eq"
  1351. },
  1352. "max_score" : 1.0,
  1353. "hits" : [
  1354. {
  1355. "_index" : "my-index-000001",
  1356. "_id" : "sRVHBnwBB-qjgFni7h_O",
  1357. "_score" : 1.0,
  1358. "_source" : {
  1359. "timestamp" : "2020-04-30T14:30:17-05:00",
  1360. "message" : "40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  1361. },
  1362. "fields" : {
  1363. "http.verb" : [
  1364. "GET"
  1365. ],
  1366. "http.clientip" : [
  1367. "40.135.0.0"
  1368. ],
  1369. "http.response" : [
  1370. 200
  1371. ],
  1372. "message" : [
  1373. "40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  1374. ],
  1375. "http.client_ip" : [
  1376. "40.135.0.0"
  1377. ],
  1378. "timestamp" : [
  1379. "2020-04-30T19:30:17.000Z"
  1380. ]
  1381. }
  1382. }
  1383. ]
  1384. }
  1385. }
  1386. ----
  1387. // TESTRESPONSE[s/\.\.\./"took" : $body.took,"timed_out" : $body.timed_out,"_shards" : $body._shards,/]
  1388. // TESTRESPONSE[s/"_id" : "sRVHBnwBB-qjgFni7h_O"/"_id": $body.hits.hits.0._id/]
  1389. Also, remember that `if` statement in the script?
  1390. [source,painless]
  1391. ----
  1392. if (clientip != null) emit(clientip);
  1393. ----
  1394. If the script didn't include this condition, the query would fail on any shard
  1395. that doesn't match the pattern. By including this condition, the query skips
  1396. data that doesn't match the grok pattern.
  1397. [[runtime-examples-grok-range]]
  1398. ===== Search for documents in a specific range
  1399. You can also run a <<query-dsl-range-query,range query>> that operates on the
  1400. `timestamp` field. The following query returns any documents where the
  1401. `timestamp` is greater than or equal to `2020-04-30T14:31:27-05:00`:
  1402. [source,console]
  1403. ----
  1404. GET my-index-000001/_search
  1405. {
  1406. "query": {
  1407. "range": {
  1408. "timestamp": {
  1409. "gte": "2020-04-30T14:31:27-05:00"
  1410. }
  1411. }
  1412. }
  1413. }
  1414. ----
  1415. // TEST[continued]
  1416. The response includes the document where the log format doesn't match, but the
  1417. timestamp falls within the defined range.
  1418. [source,console-result]
  1419. ----
  1420. {
  1421. ...
  1422. "hits" : {
  1423. "total" : {
  1424. "value" : 2,
  1425. "relation" : "eq"
  1426. },
  1427. "max_score" : 1.0,
  1428. "hits" : [
  1429. {
  1430. "_index" : "my-index-000001",
  1431. "_id" : "hdEhyncBRSB6iD-PoBqe",
  1432. "_score" : 1.0,
  1433. "_source" : {
  1434. "timestamp" : "2020-04-30T14:31:27-05:00",
  1435. "message" : "252.0.0.0 - - [30/Apr/2020:14:31:27 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  1436. }
  1437. },
  1438. {
  1439. "_index" : "my-index-000001",
  1440. "_id" : "htEhyncBRSB6iD-PoBqe",
  1441. "_score" : 1.0,
  1442. "_source" : {
  1443. "timestamp" : "2020-04-30T14:31:28-05:00",
  1444. "message" : "not a valid apache log"
  1445. }
  1446. }
  1447. ]
  1448. }
  1449. }
  1450. ----
  1451. // TESTRESPONSE[s/\.\.\./"took" : $body.took,"timed_out" : $body.timed_out,"_shards" : $body._shards,/]
  1452. // TESTRESPONSE[s/"_id" : "hdEhyncBRSB6iD-PoBqe"/"_id": $body.hits.hits.0._id/]
  1453. // TESTRESPONSE[s/"_id" : "htEhyncBRSB6iD-PoBqe"/"_id": $body.hits.hits.1._id/]
  1454. [[runtime-examples-dissect]]
  1455. ==== Define a runtime field with a dissect pattern
  1456. If you don't need the power of regular expressions, you can use
  1457. <<dissect-processor,dissect patterns>> instead of grok patterns. Dissect
  1458. patterns match on fixed delimiters but are typically faster than grok.
  1459. You can use dissect to achieve the same results as parsing the Apache logs with
  1460. a <<runtime-examples-grok,grok pattern>>. Instead of matching on a log
  1461. pattern, you include the parts of the string that you want to discard. Paying
  1462. special attention to the parts of the string you want to discard will help build
  1463. successful dissect patterns.
  1464. [source,console]
  1465. ----
  1466. PUT my-index-000001/_mappings
  1467. {
  1468. "runtime": {
  1469. "http.client.ip": {
  1470. "type": "ip",
  1471. "script": """
  1472. String clientip=dissect('%{clientip} %{ident} %{auth} [%{@timestamp}] "%{verb} %{request} HTTP/%{httpversion}" %{status} %{size}').extract(doc["message"].value)?.clientip;
  1473. if (clientip != null) emit(clientip);
  1474. """
  1475. }
  1476. }
  1477. }
  1478. ----
  1479. // TEST[continued]
  1480. Similarly, you can define a dissect pattern to extract the https://developer.mozilla.org/en-US/docs/Web/HTTP/Status[HTTP response code]:
  1481. [source,console]
  1482. ----
  1483. PUT my-index-000001/_mappings
  1484. {
  1485. "runtime": {
  1486. "http.responses": {
  1487. "type": "long",
  1488. "script": """
  1489. String response=dissect('%{clientip} %{ident} %{auth} [%{@timestamp}] "%{verb} %{request} HTTP/%{httpversion}" %{response} %{size}').extract(doc["message"].value)?.response;
  1490. if (response != null) emit(Integer.parseInt(response));
  1491. """
  1492. }
  1493. }
  1494. }
  1495. ----
  1496. // TEST[continued]
  1497. You can then run a query to retrieve a specific HTTP response using the
  1498. `http.responses` runtime field. Use the `fields` parameter of the `_search`
  1499. request to indicate which fields you want to retrieve:
  1500. [source,console]
  1501. ----
  1502. GET my-index-000001/_search
  1503. {
  1504. "query": {
  1505. "match": {
  1506. "http.responses": "304"
  1507. }
  1508. },
  1509. "fields" : ["http.client_ip","timestamp","http.verb"]
  1510. }
  1511. ----
  1512. // TEST[continued]
  1513. The response includes a single document where the HTTP response is `304`:
  1514. [source,console-result]
  1515. ----
  1516. {
  1517. ...
  1518. "hits" : {
  1519. "total" : {
  1520. "value" : 1,
  1521. "relation" : "eq"
  1522. },
  1523. "max_score" : 1.0,
  1524. "hits" : [
  1525. {
  1526. "_index" : "my-index-000001",
  1527. "_id" : "A2qDy3cBWRMvVAuI7F8M",
  1528. "_score" : 1.0,
  1529. "_source" : {
  1530. "timestamp" : "2020-04-30T14:31:22-05:00",
  1531. "message" : "247.37.0.0 - - [30/Apr/2020:14:31:22 -0500] \"GET /images/hm_nbg.jpg HTTP/1.0\" 304 0"
  1532. },
  1533. "fields" : {
  1534. "http.verb" : [
  1535. "GET"
  1536. ],
  1537. "http.client_ip" : [
  1538. "247.37.0.0"
  1539. ],
  1540. "timestamp" : [
  1541. "2020-04-30T19:31:22.000Z"
  1542. ]
  1543. }
  1544. }
  1545. ]
  1546. }
  1547. }
  1548. ----
  1549. // TESTRESPONSE[s/\.\.\./"took" : $body.took,"timed_out" : $body.timed_out,"_shards" : $body._shards,/]
  1550. // TESTRESPONSE[s/"_id" : "A2qDy3cBWRMvVAuI7F8M"/"_id": $body.hits.hits.0._id/]