scripted-metric-aggregation.asciidoc 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. [[search-aggregations-metrics-scripted-metric-aggregation]]
  2. === Scripted Metric Aggregation
  3. experimental[]
  4. A metric aggregation that executes using scripts to provide a metric output.
  5. Example:
  6. [source,js]
  7. --------------------------------------------------
  8. {
  9. "query" : {
  10. "match_all" : {}
  11. },
  12. "aggs": {
  13. "profit": {
  14. "scripted_metric": {
  15. "init_script" : "_agg['transactions'] = []",
  16. "map_script" : "if (doc['type'].value == \"sale\") { _agg.transactions.add(doc['amount'].value) } else { _agg.transactions.add(-1 * doc['amount'].value) }", <1>
  17. "combine_script" : "profit = 0; for (t in _agg.transactions) { profit += t }; return profit",
  18. "reduce_script" : "profit = 0; for (a in _aggs) { profit += a }; return profit"
  19. }
  20. }
  21. }
  22. }
  23. --------------------------------------------------
  24. <1> `map_script` is the only required parameter
  25. The above aggregation demonstrates how one would use the script aggregation compute the total profit from sale and cost transactions.
  26. The response for the above aggregation:
  27. [source,js]
  28. --------------------------------------------------
  29. {
  30. ...
  31. "aggregations": {
  32. "profit": {
  33. "value": 170
  34. }
  35. }
  36. }
  37. --------------------------------------------------
  38. The above example can also be specified using file scripts as follows:
  39. [source,js]
  40. --------------------------------------------------
  41. {
  42. "query" : {
  43. "match_all" : {}
  44. },
  45. "aggs": {
  46. "profit": {
  47. "scripted_metric": {
  48. "init_script" : {
  49. "file": "my_init_script"
  50. },
  51. "map_script" : {
  52. "file": "my_map_script"
  53. },
  54. "combine_script" : {
  55. "file": "my_combine_script"
  56. },
  57. "params": {
  58. "field": "amount" <1>
  59. },
  60. "reduce_script" : {
  61. "file": "my_reduce_script"
  62. },
  63. }
  64. }
  65. }
  66. }
  67. --------------------------------------------------
  68. <1> script parameters for init, map and combine scripts must be specified in a global `params` object so that it can be share between the scripts
  69. For more details on specifying scripts see <<modules-scripting, script documentation>>.
  70. ==== Allowed return types
  71. Whilst and valid script object can be used within a single script. the scripts must return or store in the `_agg` object only the following types:
  72. * primitive types
  73. * String
  74. * Map (containing only keys and values of the types listed here)
  75. * Array (containing elements of only the types listed here)
  76. ==== Scope of scripts
  77. The scripted metric aggregation uses scripts at 4 stages of its execution:
  78. init_script:: Executed prior to any collection of documents. Allows the aggregation to set up any initial state.
  79. +
  80. In the above example, the `init_script` creates an array `transactions` in the `_agg` object.
  81. map_script:: Executed once per document collected. This is the only required script. If no combine_script is specified, the resulting state
  82. needs to be stored in an object named `_agg`.
  83. +
  84. In the above example, the `map_script` checks the value of the type field. If the value if 'sale' the value of the amount field
  85. is added to the transactions array. If the value of the type field is not 'sale' the negated value of the amount field is added
  86. to transactions.
  87. combine_script:: Executed once on each shard after document collection is complete. Allows the aggregation to consolidate the state returned from
  88. each shard. If a combine_script is not provided the combine phase will return the aggregation variable.
  89. +
  90. In the above example, the `combine_script` iterates through all the stored transactions, summing the values in the `profit` variable
  91. and finally returns `profit`.
  92. reduce_script:: Executed once on the coordinating node after all shards have returned their results. The script is provided with access to a
  93. variable `_aggs` which is an array of the result of the combine_script on each shard. If a reduce_script is not provided
  94. the reduce phase will return the `_aggs` variable.
  95. +
  96. In the above example, the `reduce_script` iterates through the `profit` returned by each shard summing the values before returning the
  97. final combined profit which will be returned in the response of the aggregation.
  98. ==== Worked Example
  99. Imagine a situation where you index the following documents into and index with 2 shards:
  100. [source,js]
  101. --------------------------------------------------
  102. $ curl -XPUT 'http://localhost:9200/transactions/stock/1' -d '
  103. {
  104. "type": "sale",
  105. "amount": 80
  106. }
  107. '
  108. $ curl -XPUT 'http://localhost:9200/transactions/stock/2' -d '
  109. {
  110. "type": "cost",
  111. "amount": 10
  112. }
  113. '
  114. $ curl -XPUT 'http://localhost:9200/transactions/stock/3' -d '
  115. {
  116. "type": "cost",
  117. "amount": 30
  118. }
  119. '
  120. $ curl -XPUT 'http://localhost:9200/transactions/stock/4' -d '
  121. {
  122. "type": "sale",
  123. "amount": 130
  124. }
  125. '
  126. --------------------------------------------------
  127. Lets say that documents 1 and 3 end up on shard A and documents 2 and 4 end up on shard B. The following is a breakdown of what the aggregation result is
  128. at each stage of the example above.
  129. ===== Before init_script
  130. No params object was specified so the default params object is used:
  131. [source,js]
  132. --------------------------------------------------
  133. "params" : {
  134. "_agg" : {}
  135. }
  136. --------------------------------------------------
  137. ===== After init_script
  138. This is run once on each shard before any document collection is performed, and so we will have a copy on each shard:
  139. Shard A::
  140. +
  141. [source,js]
  142. --------------------------------------------------
  143. "params" : {
  144. "_agg" : {
  145. "transactions" : []
  146. }
  147. }
  148. --------------------------------------------------
  149. Shard B::
  150. +
  151. [source,js]
  152. --------------------------------------------------
  153. "params" : {
  154. "_agg" : {
  155. "transactions" : []
  156. }
  157. }
  158. --------------------------------------------------
  159. ===== After map_script
  160. Each shard collects its documents and runs the map_script on each document that is collected:
  161. Shard A::
  162. +
  163. [source,js]
  164. --------------------------------------------------
  165. "params" : {
  166. "_agg" : {
  167. "transactions" : [ 80, -30 ]
  168. }
  169. }
  170. --------------------------------------------------
  171. Shard B::
  172. +
  173. [source,js]
  174. --------------------------------------------------
  175. "params" : {
  176. "_agg" : {
  177. "transactions" : [ -10, 130 ]
  178. }
  179. }
  180. --------------------------------------------------
  181. ===== After combine_script
  182. The combine_script is executed on each shard after document collection is complete and reduces all the transactions down to a single profit figure for each
  183. shard (by summing the values in the transactions array) which is passed back to the coordinating node:
  184. Shard A:: 50
  185. Shard B:: 120
  186. ===== After reduce_script
  187. The reduce_script receives an `_aggs` array containing the result of the combine script for each shard:
  188. [source,js]
  189. --------------------------------------------------
  190. "_aggs" : [
  191. 50,
  192. 120
  193. ]
  194. --------------------------------------------------
  195. It reduces the responses for the shards down to a final overall profit figure (by summing the values) and returns this as the result of the aggregation to
  196. produce the response:
  197. [source,js]
  198. --------------------------------------------------
  199. {
  200. ...
  201. "aggregations": {
  202. "profit": {
  203. "value": 170
  204. }
  205. }
  206. }
  207. --------------------------------------------------
  208. ==== Other Parameters
  209. [horizontal]
  210. params:: Optional. An object whose contents will be passed as variables to the `init_script`, `map_script` and `combine_script`. This can be
  211. useful to allow the user to control the behavior of the aggregation and for storing state between the scripts. If this is not specified,
  212. the default is the equivalent of providing:
  213. +
  214. [source,js]
  215. --------------------------------------------------
  216. "params" : {
  217. "_agg" : {}
  218. }
  219. --------------------------------------------------
  220. reduce_params:: Optional. An object whose contents will be passed as variables to the `reduce_script`. This can be useful to allow the user to control
  221. the behavior of the reduce phase. If this is not specified the variable will be undefined in the reduce_script execution.