painless-execute-script.asciidoc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. [[painless-execute-api]]
  2. === Painless execute API
  3. experimental::[]
  4. The Painless execute API runs a script and returns a result.
  5. [[painless-execute-api-request]]
  6. ==== {api-request-title}
  7. `POST /_scripts/painless/_execute`
  8. [[painless-execute-api-desc]]
  9. ==== {api-description-title}
  10. Use this API to build and test scripts, such as when defining a script for a
  11. {ref}/runtime.html[runtime field]. This API requires very few dependencies, and is
  12. especially useful if you don't have permissions to write documents on a cluster.
  13. The API uses several _contexts_, which control how scripts are executed, what
  14. variables are available at runtime, and what the return type is.
  15. Each context requires a script, but additional parameters depend on the context
  16. you're using for that script.
  17. [[painless-execute-api-request-body]]
  18. ==== {api-request-body-title}
  19. `script`:: (Required, object)
  20. The Painless script to execute.
  21. +
  22. .Properties of `script`
  23. --
  24. include::../painless-contexts/painless-runtime-fields-context.asciidoc[tag=runtime-field-emit]
  25. --
  26. [[_contexts]]
  27. `context`:: (Optional, string)
  28. The context that the script should run in. Defaults to `painless_test` if no
  29. context is specified.
  30. +
  31. .Properties of `context`
  32. [%collapsible%open]
  33. ====
  34. `painless_test`::
  35. The default context if no other context is specified. See
  36. <<painless-execute-test,test context>>.
  37. `filter`::
  38. Treats scripts as if they were run inside a `script` query. See
  39. <<painless-execute-filter-context,filter context>>.
  40. `score`::
  41. Treats scripts as if they were run inside a `script_score` function in a
  42. `function_score` query. See <<painless-execute-core-context,score context>>.
  43. [[painless-execute-runtime-context]]
  44. .Field contexts
  45. [%collapsible%open]
  46. =====
  47. --
  48. The following options are specific to the field contexts.
  49. NOTE: Result ordering in the field contexts is not guaranteed.
  50. --
  51. ****
  52. `boolean_field`::
  53. The context for {ref}/boolean.html[`boolean` fields]. The script returns a `true`
  54. or `false` response. See
  55. <<painless-runtime-boolean,boolean_field context>>.
  56. `date_field`::
  57. The context for {ref}/date.html[`date` fields]. `emit` takes a `long` value and
  58. the script returns a sorted list of dates. See
  59. <<painless-runtime-datetime,date_time context>>.
  60. `double_field`::
  61. The context for `double` {ref}/number.html[numeric fields]. The script returns a
  62. sorted list of `double` values. See
  63. <<painless-runtime-double,double_field context>>.
  64. `geo_point_field`::
  65. The context for {ref}/geo-point.html[`geo-point` fields]. `emit` takes two double
  66. parameters, the latitude and longitude values, and the script returns an object in
  67. GeoJSON format containing the coordinates for the geo point. See
  68. <<painless-runtime-geo,geo_point_field context>>.
  69. `ip_field`::
  70. The context for {ref}/ip.html[`ip` fields]. The script returns a sorted list of IP
  71. addresses. See
  72. <<painless-runtime-ip,ip_field context>>.
  73. `keyword_field`::
  74. The context for {ref}/keyword.html[`keyword` fields]. The script returns a sorted
  75. list of `string` values. See
  76. <<painless-runtime-keyword,keyword_field context>>.
  77. `long_field`::
  78. The context for `long` {ref}/number.html[numeric fields]. The script returns a
  79. sorted list of `long` values. See <<painless-runtime-long,long_field context>>.
  80. `composite_field`::
  81. The context for `composite` {ref}/runtime.html[runtime fields]. The script returns a
  82. map of values. See <<painless-runtime-composite,composite_field context>>.
  83. ****
  84. =====
  85. ====
  86. `context_setup`:: (Required, object)
  87. Additional parameters for the `context`.
  88. +
  89. NOTE: This parameter is required for all contexts except `painless_test`,
  90. which is the default if no value is provided for `context`.
  91. +
  92. .Properties of `context_setup`
  93. [%collapsible%open]
  94. ====
  95. `document`:: (Required, string)
  96. Document that's temporarily indexed in-memory and accessible from the script.
  97. `index`:: (Required, string)
  98. Index containing a mapping that's compatible with the indexed document.
  99. ====
  100. `params`:: (`Map`, read-only)
  101. Specifies any named parameters that are passed into the script as variables.
  102. `query`:: (Optional, object)
  103. NOTE: This parameter only applies when `score` is specified as the script
  104. `context`.
  105. +
  106. Use this parameter to specify a query for computing a score. Besides deciding
  107. whether or not the document matches, the
  108. {ref}/query-filter-context.html#query-context[query clause] also calculates a
  109. relevance score in the `_score` metadata field.
  110. [[painless-execute-test]]
  111. ==== Test context
  112. The `painless_test` context runs scripts without additional parameters. The only
  113. variable that is available is `params`, which can be used to access user defined
  114. values. The result of the script is always converted to a string.
  115. Because the default context is `painless_test`, you don't need to specify the
  116. `context` or `context_setup`.
  117. ===== Request
  118. [source,console]
  119. ----
  120. POST /_scripts/painless/_execute
  121. {
  122. "script": {
  123. "source": "params.count / params.total",
  124. "params": {
  125. "count": 100.0,
  126. "total": 1000.0
  127. }
  128. }
  129. }
  130. ----
  131. ===== Response
  132. [source,console-result]
  133. ----
  134. {
  135. "result": "0.1"
  136. }
  137. ----
  138. [[painless-execute-filter-context]]
  139. ==== Filter context
  140. The `filter` context treats scripts as if they were run inside a `script` query.
  141. For testing purposes, a document must be provided so that it will be temporarily
  142. indexed in-memory and is accessible from the script. More precisely, the
  143. `_source`, stored fields and doc values of such a document are available to the
  144. script being tested.
  145. ===== Request
  146. [source,console]
  147. ----
  148. PUT /my-index-000001
  149. {
  150. "mappings": {
  151. "properties": {
  152. "field": {
  153. "type": "keyword"
  154. }
  155. }
  156. }
  157. }
  158. ----
  159. [source,console]
  160. ----
  161. POST /_scripts/painless/_execute
  162. {
  163. "script": {
  164. "source": "doc['field'].value.length() <= params.max_length",
  165. "params": {
  166. "max_length": 4
  167. }
  168. },
  169. "context": "filter",
  170. "context_setup": {
  171. "index": "my-index-000001",
  172. "document": {
  173. "field": "four"
  174. }
  175. }
  176. }
  177. ----
  178. // TEST[continued]
  179. ===== Response
  180. [source,console-result]
  181. ----
  182. {
  183. "result": true
  184. }
  185. ----
  186. [[painless-execute-core-context]]
  187. ==== Score context
  188. The `score` context treats scripts as if they were run inside a `script_score`
  189. function in a `function_score` query.
  190. ===== Request
  191. [source,console]
  192. ----
  193. PUT /my-index-000001
  194. {
  195. "mappings": {
  196. "properties": {
  197. "field": {
  198. "type": "keyword"
  199. },
  200. "rank": {
  201. "type": "long"
  202. }
  203. }
  204. }
  205. }
  206. ----
  207. [source,console]
  208. ----
  209. POST /_scripts/painless/_execute
  210. {
  211. "script": {
  212. "source": "doc['rank'].value / params.max_rank",
  213. "params": {
  214. "max_rank": 5.0
  215. }
  216. },
  217. "context": "score",
  218. "context_setup": {
  219. "index": "my-index-000001",
  220. "document": {
  221. "rank": 4
  222. }
  223. }
  224. }
  225. ----
  226. // TEST[continued]
  227. ===== Response
  228. [source,console-result]
  229. ----
  230. {
  231. "result": 0.8
  232. }
  233. ----
  234. [[painless-execute-runtime-field-context]]
  235. ==== Field contexts
  236. The field contexts treat scripts as if they were run inside the
  237. {ref}/runtime-search-request.html[`runtime_mappings` section] of a search query.
  238. You can use field contexts to test scripts for different field types, and then
  239. include those scripts anywhere that they're supported, such as <<painless-runtime-fields,runtime fields>>.
  240. Choose a field context based on the data type you want to return.
  241. [[painless-runtime-boolean]]
  242. ===== `boolean_field`
  243. Use the `boolean_field` field context when you want to return a `true`
  244. or `false` value from a script valuation. {ref}/boolean.html[Boolean fields]
  245. accept `true` and `false` values, but can also accept strings that are
  246. interpreted as either true or false.
  247. Let's say you have data for the top 100 science fiction books of all time. You
  248. want to write scripts that return a boolean response such as whether books
  249. exceed a certain page count, or if a book was published after a specific year.
  250. Consider that your data is structured like this:
  251. [source,console]
  252. ----
  253. PUT /my-index-000001
  254. {
  255. "mappings": {
  256. "properties": {
  257. "name": {
  258. "type": "keyword"
  259. },
  260. "author": {
  261. "type": "keyword"
  262. },
  263. "release_date": {
  264. "type": "date"
  265. },
  266. "page_count": {
  267. "type": "double"
  268. }
  269. }
  270. }
  271. }
  272. ----
  273. You can then write a script in the `boolean_field` context that indicates
  274. whether a book was published before the year 1972:
  275. [source,console]
  276. ----
  277. POST /_scripts/painless/_execute
  278. {
  279. "script": {
  280. "source": """
  281. emit(doc['release_date'].value.year < 1972);
  282. """
  283. },
  284. "context": "boolean_field",
  285. "context_setup": {
  286. "index": "my-index-000001",
  287. "document": {
  288. "name": "Dune",
  289. "author": "Frank Herbert",
  290. "release_date": "1965-06-01",
  291. "page_count": 604
  292. }
  293. }
  294. }
  295. ----
  296. // TEST[continued]
  297. Because _Dune_ was published in 1965, the result returns as `true`:
  298. [source,console-result]
  299. ----
  300. {
  301. "result" : [
  302. true
  303. ]
  304. }
  305. ----
  306. Similarly, you could write a script that determines whether the first name of
  307. an author exceeds a certain number of characters. The following script operates
  308. on the `author` field to determine whether the author's first name contains at
  309. least one character, but is less than five characters:
  310. [source,console]
  311. ----
  312. POST /_scripts/painless/_execute
  313. {
  314. "script": {
  315. "source": """
  316. int space = doc['author'].value.indexOf(' ');
  317. emit(space > 0 && space < 5);
  318. """
  319. },
  320. "context": "boolean_field",
  321. "context_setup": {
  322. "index": "my-index-000001",
  323. "document": {
  324. "name": "Dune",
  325. "author": "Frank Herbert",
  326. "release_date": "1965-06-01",
  327. "page_count": 604
  328. }
  329. }
  330. }
  331. ----
  332. // TEST[continued]
  333. Because `Frank` is five characters, the response returns `false` for the script
  334. valuation:
  335. [source,console-result]
  336. ----
  337. {
  338. "result" : [
  339. false
  340. ]
  341. }
  342. ----
  343. [[painless-runtime-datetime]]
  344. ===== `date_time`
  345. Several options are available for using
  346. <<painless-datetime,using datetime in Painless>>. In this example, you'll
  347. estimate when a particular author starting writing a book based on its release
  348. date and the writing speed of that author. The example makes some assumptions,
  349. but shows to write a script that operates on a date while incorporating
  350. additional information.
  351. Add the following fields to your index mapping to get started:
  352. [source,console]
  353. ----
  354. PUT /my-index-000001
  355. {
  356. "mappings": {
  357. "properties": {
  358. "name": {
  359. "type": "keyword"
  360. },
  361. "author": {
  362. "type": "keyword"
  363. },
  364. "release_date": {
  365. "type": "date"
  366. },
  367. "page_count": {
  368. "type": "long"
  369. }
  370. }
  371. }
  372. }
  373. ----
  374. The following script makes the incredible assumption that when writing a book,
  375. authors just write each page and don't do research or revisions. Further, the
  376. script assumes that the average time it takes to write a page is eight hours.
  377. The script retrieves the `author` and makes another fantastic assumption to
  378. either divide or multiply the `pageTime` value based on the author's perceived
  379. writing speed (yet another wild assumption).
  380. The script subtracts the release date value (in milliseconds) from the
  381. calculation of `pageTime` times the `page_count` to determine approximately
  382. (based on numerous assumptions) when the author began writing the book.
  383. [source,console]
  384. ----
  385. POST /_scripts/painless/_execute
  386. {
  387. "script": {
  388. "source": """
  389. String author = doc['author'].value;
  390. long pageTime = 28800000; <1>
  391. if (author == 'Robert A. Heinlein') {
  392. pageTime /= 2; <2>
  393. } else if (author == 'Alastair Reynolds') {
  394. pageTime *= 2; <3>
  395. }
  396. emit(doc['release_date'].value.toInstant().toEpochMilli() - pageTime * doc['page_count'].value);
  397. """
  398. },
  399. "context": "date_field",
  400. "context_setup": {
  401. "index": "my-index-000001",
  402. "document": {
  403. "name": "Revelation Space",
  404. "author": "Alastair Reynolds",
  405. "release_date": "2000-03-15",
  406. "page_count": 585
  407. }
  408. }
  409. }
  410. ----
  411. //TEST[continued]
  412. <1> Eight hours, represented in milliseconds
  413. <2> Incredibly fast writing from Robert A. Heinlein
  414. <3> Alastair Reynolds writes space operas at a much slower speed
  415. In this case, the author is Alastair Reynolds. Based on a release date of
  416. `2000-03-15`, the script calculates that the author started writing
  417. `Revelation Space` on 19 February 1999. Writing a 585 page book in just over one
  418. year is pretty impressive!
  419. [source,console-result]
  420. ----
  421. {
  422. "result" : [
  423. "1999-02-19T00:00:00.000Z"
  424. ]
  425. }
  426. ----
  427. [[painless-runtime-double]]
  428. ===== `double_field`
  429. Use the `double_field` context for {ref}/number.html[numeric data] of type
  430. `double`. For example, let's say you have sensor data that includes a `voltage`
  431. field with values like 5.6. After indexing millions of documents, you discover
  432. that the sensor with model number `QVKC92Q` is under reporting its voltage by a
  433. factor of 1.7. Rather than reindex your data, you can fix it with a
  434. runtime field.
  435. You need to multiply this value, but only for
  436. sensors that match a specific model number.
  437. Add the following fields to your index mapping. The `voltage` field is a
  438. sub-field of the `measures` object.
  439. [source,console]
  440. ----
  441. PUT my-index-000001
  442. {
  443. "mappings": {
  444. "properties": {
  445. "@timestamp": {
  446. "type": "date"
  447. },
  448. "model_number": {
  449. "type": "keyword"
  450. },
  451. "measures": {
  452. "properties": {
  453. "voltage": {
  454. "type": "double"
  455. }
  456. }
  457. }
  458. }
  459. }
  460. }
  461. ----
  462. The following script matches on any documents where the `model_number` equals
  463. `QVKC92Q`, and then multiplies the `voltage` value by `1.7`. This script is
  464. useful when you want to select specific documents and only operate on values
  465. that match the specified criteria.
  466. [source,console]
  467. ----
  468. POST /_scripts/painless/_execute
  469. {
  470. "script": {
  471. "source": """
  472. if (doc['model_number'].value.equals('QVKC92Q'))
  473. {emit(1.7 * params._source['measures']['voltage']);}
  474. else{emit(params._source['measures']['voltage']);}
  475. """
  476. },
  477. "context": "double_field",
  478. "context_setup": {
  479. "index": "my-index-000001",
  480. "document": {
  481. "@timestamp": 1516470094000,
  482. "model_number": "QVKC92Q",
  483. "measures": {
  484. "voltage": 5.6
  485. }
  486. }
  487. }
  488. }
  489. ----
  490. // TEST[continued]
  491. The result includes the calculated voltage, which was determined by multiplying
  492. the original value of `5.6` by `1.7`:
  493. [source,console-result]
  494. ----
  495. {
  496. "result" : [
  497. 9.52
  498. ]
  499. }
  500. ----
  501. [[painless-runtime-geo]]
  502. ===== `geo_point_field`
  503. {ref}/geo-point.html[Geo-point] fields accept latitude-longitude pairs. You can
  504. define a geo-point field in several ways, and include values for latitude and
  505. longitude in the document for your script.
  506. If you already have a known geo-point, it's simpler to clearly state the
  507. positions of `lat` and `lon` in your index mappings.
  508. [source,console]
  509. ----
  510. PUT /my-index-000001/
  511. {
  512. "mappings": {
  513. "properties": {
  514. "lat": {
  515. "type": "double"
  516. },
  517. "lon": {
  518. "type": "double"
  519. }
  520. }
  521. }
  522. }
  523. ----
  524. You can then use the `geo_point_field` runtime field context to write a script
  525. that retrieves the `lat` and `lon` values.
  526. [source,console]
  527. ----
  528. POST /_scripts/painless/_execute
  529. {
  530. "script": {
  531. "source": """
  532. emit(doc['lat'].value, doc['lon'].value);
  533. """
  534. },
  535. "context": "geo_point_field",
  536. "context_setup": {
  537. "index": "my-index-000001",
  538. "document": {
  539. "lat": 41.12,
  540. "lon": -71.34
  541. }
  542. }
  543. }
  544. ----
  545. // TEST[continued]
  546. Because you're working with a geo-point field type, the response includes
  547. results that are formatted as `coordinates`.
  548. [source,console-result]
  549. ----
  550. {
  551. "result" : [
  552. {
  553. "coordinates" : [
  554. -71.34000004269183,
  555. 41.1199999647215
  556. ],
  557. "type" : "Point"
  558. }
  559. ]
  560. }
  561. ----
  562. [NOTE]
  563. The emit function for {ref}/geo-point.html[geo-point] fields takes two parameters ordered with
  564. `lat` before `lon`, but the output GeoJSON format orders the `coordinates` as `[ lon, lat ]`.
  565. [[painless-runtime-ip]]
  566. ===== `ip_field`
  567. The `ip_field` context is useful for data that includes IP addresses of type
  568. {ref}/ip.html[`ip`]. For example, let's say you have a `message` field from an Apache
  569. log. This field contains an IP address, but also other data that you don't need.
  570. You can add the `message` field to your index mappings as a `wildcard` to accept
  571. pretty much any data you want to put in that field.
  572. [source,console]
  573. ----
  574. PUT /my-index-000001/
  575. {
  576. "mappings": {
  577. "properties": {
  578. "message": {
  579. "type": "wildcard"
  580. }
  581. }
  582. }
  583. }
  584. ----
  585. You can then define a runtime script with a grok pattern that extracts
  586. structured fields out of the `message` field.
  587. The script matches on the `%{COMMONAPACHELOG}` log pattern, which understands
  588. the structure of Apache logs. If the pattern matches, the script emits the
  589. value matching the IP address. If the pattern doesn’t match
  590. (`clientip != null`), the script just returns the field value without crashing.
  591. [source,console]
  592. ----
  593. POST /_scripts/painless/_execute
  594. {
  595. "script": {
  596. "source": """
  597. String clientip=grok('%{COMMONAPACHELOG}').extract(doc["message"].value)?.clientip;
  598. if (clientip != null) emit(clientip);
  599. """
  600. },
  601. "context": "ip_field",
  602. "context_setup": {
  603. "index": "my-index-000001",
  604. "document": {
  605. "message": "40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  606. }
  607. }
  608. }
  609. ----
  610. // TEST[continued]
  611. The response includes only the IP address, ignoring all of the other data in the
  612. `message` field.
  613. [source,console-result]
  614. ----
  615. {
  616. "result" : [
  617. "40.135.0.0"
  618. ]
  619. }
  620. ----
  621. [[painless-runtime-keyword]]
  622. ===== `keyword_field`
  623. {ref}/keyword.html[Keyword fields] are often used in sorting, aggregations, and
  624. term-level queries.
  625. Let's say you have a timestamp. You want to calculate the day of the week based
  626. on that value and return it, such as `Thursday`. The following request adds a
  627. `@timestamp` field of type `date` to the index mappings:
  628. [source,console]
  629. ----
  630. PUT /my-index-000001
  631. {
  632. "mappings": {
  633. "properties": {
  634. "@timestamp": {
  635. "type": "date"
  636. }
  637. }
  638. }
  639. }
  640. ----
  641. To return the equivalent day of week based on your timestamp, you can create a
  642. script in the `keyword_field` runtime field context:
  643. [source,console]
  644. ----
  645. POST /_scripts/painless/_execute
  646. {
  647. "script": {
  648. "source": """
  649. emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT));
  650. """
  651. },
  652. "context": "keyword_field",
  653. "context_setup": {
  654. "index": "my-index-000001",
  655. "document": {
  656. "@timestamp": "2020-04-30T14:31:43-05:00"
  657. }
  658. }
  659. }
  660. ----
  661. // TEST[continued]
  662. The script operates on the value provided for the `@timestamp` field to
  663. calculate and return the day of the week:
  664. [source,console-result]
  665. ----
  666. {
  667. "result" : [
  668. "Thursday"
  669. ]
  670. }
  671. ----
  672. [[painless-runtime-long]]
  673. ===== `long_field`
  674. Let's say you have sensor data that a `measures` object. This object includes
  675. a `start` and `end` field, and you want to calculate the difference between
  676. those values.
  677. The following request adds a `measures` object to the mappings with two fields,
  678. both of type `long`:
  679. [source,console]
  680. ----
  681. PUT /my-index-000001/
  682. {
  683. "mappings": {
  684. "properties": {
  685. "measures": {
  686. "properties": {
  687. "start": {
  688. "type": "long"
  689. },
  690. "end": {
  691. "type": "long"
  692. }
  693. }
  694. }
  695. }
  696. }
  697. }
  698. ----
  699. You can then define a script that assigns values to the `start` and `end` fields
  700. and operate on them. The following script extracts the value for the `end`
  701. field from the `measures` object and subtracts it from the `start` field:
  702. [source,console]
  703. ----
  704. POST /_scripts/painless/_execute
  705. {
  706. "script": {
  707. "source": """
  708. emit(doc['measures.end'].value - doc['measures.start'].value);
  709. """
  710. },
  711. "context": "long_field",
  712. "context_setup": {
  713. "index": "my-index-000001",
  714. "document": {
  715. "measures": {
  716. "voltage": "4.0",
  717. "start": "400",
  718. "end": "8625309"
  719. }
  720. }
  721. }
  722. }
  723. ----
  724. // TEST[continued]
  725. The response includes the calculated value from the script valuation:
  726. [source,console-result]
  727. ----
  728. {
  729. "result" : [
  730. 8624909
  731. ]
  732. }
  733. ----
  734. [[painless-runtime-composite]]
  735. ===== `composite_field`
  736. Let's say you have logging data with a raw `message` field which you want to split
  737. in multiple sub-fields that can be accessed separately.
  738. The following request adds a `message` field to the mappings of type `keyword`:
  739. [source,console]
  740. ----
  741. PUT /my-index-000001/
  742. {
  743. "mappings": {
  744. "properties": {
  745. "message": {
  746. "type" : "keyword"
  747. }
  748. }
  749. }
  750. }
  751. ----
  752. You can then define a script that splits such message field into subfields using
  753. the grok function:
  754. [source,console]
  755. ----
  756. POST /_scripts/painless/_execute
  757. {
  758. "script": {
  759. "source": "emit(grok(\"%{COMMONAPACHELOG}\").extract(doc[\"message\"].value));"
  760. },
  761. "context": "composite_field",
  762. "context_setup": {
  763. "index": "my-index-000001",
  764. "document": {
  765. "timestamp":"2020-04-30T14:31:27-05:00",
  766. "message":"252.0.0.0 - - [30/Apr/2020:14:31:27 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  767. }
  768. }
  769. }
  770. ----
  771. // TEST[continued]
  772. The response includes the values that the script emitted:
  773. [source,console-result]
  774. ----
  775. {
  776. "result" : {
  777. "composite_field.timestamp" : [
  778. "30/Apr/2020:14:31:27 -0500"
  779. ],
  780. "composite_field.auth" : [
  781. "-"
  782. ],
  783. "composite_field.response" : [
  784. "200"
  785. ],
  786. "composite_field.ident" : [
  787. "-"
  788. ],
  789. "composite_field.httpversion" : [
  790. "1.0"
  791. ],
  792. "composite_field.verb" : [
  793. "GET"
  794. ],
  795. "composite_field.bytes" : [
  796. "24736"
  797. ],
  798. "composite_field.clientip" : [
  799. "252.0.0.0"
  800. ],
  801. "composite_field.request" : [
  802. "/images/hm_bg.jpg"
  803. ]
  804. }
  805. }
  806. ----