| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 | [role="xpack"][testenv="basic"][[rollup-search]]=== Rollup search++++<titleabbrev>Rollup search</titleabbrev>++++Enables searching rolled-up data using the standard query DSL.  experimental[][[rollup-search-request]]==== {api-request-title}`GET <index>/_rollup_search`[[rollup-search-desc]]==== {api-description-title}The rollup search endpoint is needed because, internally, rolled-up documentsutilize a different document structure than the original data. The rollup searchendpoint rewrites standard query DSL into a format that matches the rollupdocuments, then takes the response and rewrites it back to what a client wouldexpect given the original query.[[rollup-search-path-params]]==== {api-path-parms-title}`<index>`::  (Required, string) Index, indices or index-pattern to execute a rollup search  against.  This can include both rollup and non-rollup indices.Rules for the `index` parameter:- At least one index/index-pattern must be specified. This can be either arollup or non-rollup index.  Omitting the index parameter, or using `_all`, isnot permitted.- Multiple non-rollup indices may be specified- Only one rollup index may be specified. If more than one are supplied, anexception occurs.- Index patterns may be used, but if they match more than one rollup index anexception occurs.[[rollup-search-request-body]]==== {api-request-body-title}The request body supports a subset of features from the regular Search API. Itsupports:- `query` param for specifying an DSL query, subject to some limitations(see <<rollup-search-limitations>> and <<rollup-agg-limitations>>- `aggregations` param for specifying aggregationsFunctionality that is not available:- `size`: Because rollups work on pre-aggregated data, no search hits can bereturned and so size must be set to zero or omitted entirely.- `highlighter`, `suggestors`, `post_filter`, `profile`, `explain`: These aresimilarly disallowed.[[rollup-search-example]]==== {api-examples-title}===== Historical-only search exampleImagine we have an index named `sensor-1` full of raw data, and we have createda {rollup-job} with the following configuration:[source,console]--------------------------------------------------PUT _rollup/job/sensor{    "index_pattern": "sensor-*",    "rollup_index": "sensor_rollup",    "cron": "*/30 * * * * ?",    "page_size" :1000,    "groups" : {      "date_histogram": {        "field": "timestamp",        "fixed_interval": "1h",        "delay": "7d"      },      "terms": {        "fields": ["node"]      }    },    "metrics": [        {            "field": "temperature",            "metrics": ["min", "max", "sum"]        },        {            "field": "voltage",            "metrics": ["avg"]        }    ]}--------------------------------------------------// TEST[setup:sensor_index]This rolls up the `sensor-*` pattern and stores the results in `sensor_rollup`.To search this rolled up data, we need to use the `_rollup_search` endpoint.However, you'll notice that we can use regular query DSL to search the rolled-updata:[source,console]--------------------------------------------------GET /sensor_rollup/_rollup_search{    "size": 0,    "aggregations": {        "max_temperature": {            "max": {                "field": "temperature"            }        }    }}--------------------------------------------------// TEST[setup:sensor_prefab_data]// TEST[s/_rollup_search/_rollup_search?filter_path=took,timed_out,terminated_early,_shards,hits,aggregations/]The query is targeting the `sensor_rollup` data, since this contains the rollupdata as configured in the job. A `max` aggregation has been used on the`temperature` field, yielding the following response:[source,console-result]----{  "took" : 102,  "timed_out" : false,  "terminated_early" : false,  "_shards" : ... ,  "hits" : {    "total" : {        "value": 0,        "relation": "eq"    },    "max_score" : 0.0,    "hits" : [ ]  },  "aggregations" : {    "max_temperature" : {      "value" : 202.0    }  }}----// TESTRESPONSE[s/"took" : 102/"took" : $body.$_path/]// TESTRESPONSE[s/"_shards" : \.\.\. /"_shards" : $body.$_path/]The response is exactly as you'd expect from a regular query + aggregation; itprovides some metadata about the request (`took`, `_shards`, etc), the searchhits (which is always empty for rollup searches), and the aggregation response.Rollup searches are limited to functionality that was configured in the{rollup-job}. For example, we are not able to calculate the average temperaturebecause `avg` was not one of the configured metrics for the `temperature` field.If we try to execute that search:[source,console]--------------------------------------------------GET sensor_rollup/_rollup_search{    "size": 0,    "aggregations": {        "avg_temperature": {            "avg": {                "field": "temperature"            }        }    }}--------------------------------------------------// TEST[continued]// TEST[catch:/illegal_argument_exception/][source,console-result]----{    "error" : {        "root_cause" : [            {                "type" : "illegal_argument_exception",                "reason" : "There is not a rollup job that has a [avg] agg with name [avg_temperature] which also satisfies all requirements of query.",                "stack_trace": ...            }        ],        "type" : "illegal_argument_exception",        "reason" : "There is not a rollup job that has a [avg] agg with name [avg_temperature] which also satisfies all requirements of query.",        "stack_trace": ...    },    "status": 400}----// TESTRESPONSE[s/"stack_trace": \.\.\./"stack_trace": $body.$_path/]===== Searching both historical rollup and non-rollup dataThe rollup search API has the capability to search across both "live"non-rollup data and the aggregated rollup data. This is done by simply addingthe live indices to the URI:[source,console]--------------------------------------------------GET sensor-1,sensor_rollup/_rollup_search <1>{    "size": 0,    "aggregations": {        "max_temperature": {            "max": {                "field": "temperature"            }        }    }}--------------------------------------------------// TEST[continued]// TEST[s/_rollup_search/_rollup_search?filter_path=took,timed_out,terminated_early,_shards,hits,aggregations/]<1> Note the URI now searches `sensor-1` and `sensor_rollup` at the same timeWhen the search is executed, the rollup search endpoint does two things:1. The original request is sent to the non-rollup index unaltered.2. A rewritten version of the original request is sent to the rollup index.When the two responses are received, the endpoint rewrites the rollup responseand merges the two together. During the merging process, if there is any overlapin buckets between the two responses, the buckets from the non-rollup index areused.The response to the above query looks as expected, despite spanning rollup andnon-rollup indices:[source,console-result]----{  "took" : 102,  "timed_out" : false,  "terminated_early" : false,  "_shards" : ... ,  "hits" : {    "total" : {        "value": 0,        "relation": "eq"    },    "max_score" : 0.0,    "hits" : [ ]  },  "aggregations" : {    "max_temperature" : {      "value" : 202.0    }  }}----// TESTRESPONSE[s/"took" : 102/"took" : $body.$_path/]// TESTRESPONSE[s/"_shards" : \.\.\. /"_shards" : $body.$_path/]
 |