-
Notifications
You must be signed in to change notification settings - Fork 25.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ML] adding support for composite aggs in anomaly detection #69970
Changes from 23 commits
8bb5c5c
5262ef7
dfa7abc
dd69d16
d9e7c6f
3fc4159
4fc5492
673460c
8397358
b0d6ba8
767bf04
4640b56
df2c7d3
39e048a
bf52d69
055460e
41faec4
0ff5f47
a248998
5152978
1878a19
eb7d11d
cc6e470
825d4a7
94b6833
05ffe9b
47f3d40
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,57 +11,61 @@ distributes these calculations across your cluster. You can then feed this | |
aggregated data into the {ml-features} instead of raw results, which | ||
reduces the volume of data that must be considered while detecting anomalies. | ||
|
||
TIP: If you use a terms aggregation and the cardinality of a term is high, the | ||
aggregation might not be effective and you might want to just use the default | ||
search and scroll behavior. | ||
TIP: If you use a terms aggregation and the cardinality of a term is high but | ||
still significantly less than your total number of documents, use | ||
{ref}/search-aggregations-bucket-composite-aggregation.html[composite aggregations] | ||
experimental:[Support for composite aggregations inside datafeeds is currently experimental]. | ||
|
||
[discrete] | ||
[[aggs-limits-dfeeds]] | ||
== Requirements and limitations | ||
|
||
There are some limitations to using aggregations in {dfeeds}. Your aggregation | ||
must include a `date_histogram` aggregation, which in turn must contain a `max` | ||
aggregation on the time field. This requirement ensures that the aggregated data | ||
is a time series and the timestamp of each bucket is the time of the last record | ||
in the bucket. | ||
There are some limitations to using aggregations in {dfeeds}. | ||
|
||
IMPORTANT: The name of the aggregation and the name of the field that the agg | ||
operates on need to match, otherwise the aggregation doesn't work. For example, | ||
if you use a `max` aggregation on a time field called `responsetime`, the name | ||
Your aggregation must include a `date_histogram` aggregation or a top level `composite` aggregation, | ||
which in turn must contain a `max` aggregation on the time field. | ||
This requirement ensures that the aggregated data is a time series and the timestamp | ||
of each bucket is the time of the last record in the bucket. | ||
|
||
IMPORTANT: The name of the aggregation and the name of the field that it | ||
operates on need to match, otherwise the aggregation doesn't work. For example, | ||
if you use a `max` aggregation on a time field called `responsetime`, the name | ||
of the aggregation must be also `responsetime`. | ||
|
||
You must also consider the interval of the date histogram aggregation carefully. | ||
The bucket span of your {anomaly-job} must be divisible by the value of the | ||
`calendar_interval` or `fixed_interval` in your aggregation (with no remainder). | ||
If you specify a `frequency` for your {dfeed}, it must also be divisible by this | ||
interval. {anomaly-jobs-cap} cannot use date histograms with an interval | ||
measured in months because the length of the month is not fixed. {dfeeds-cap} | ||
tolerate weeks or smaller units. | ||
You must consider the interval of the `date_histogram` or `composite` | ||
aggregation carefully. The bucket span of your {anomaly-job} must be divisible | ||
by the value of the `calendar_interval` or `fixed_interval` in your aggregation | ||
(with no remainder). If you specify a `frequency` for your {dfeed}, | ||
it must also be divisible by this interval. {anomaly-jobs-cap} cannot use | ||
`date_histogram` or `composite` aggregations with an interval measured in months | ||
because the length of the month is not fixed; they can use weeks or smaller units. | ||
|
||
TIP: As a rule of thumb, if your detectors use <<ml-metric-functions,metric>> or | ||
<<ml-sum-functions,sum>> analytical functions, set the date histogram | ||
<<ml-sum-functions,sum>> analytical functions, set the `date_histogram` or `composite` | ||
aggregation interval to a tenth of the bucket span. This suggestion creates | ||
finer, more granular time buckets, which are ideal for this type of analysis. If | ||
your detectors use <<ml-count-functions,count>> or <<ml-rare-functions,rare>> | ||
functions, set the interval to the same value as the bucket span. | ||
|
||
If your <<aggs-dfeeds,{dfeed} uses aggregations with nested `terms` aggs>> and | ||
model plot is not enabled for the {anomaly-job}, neither the **Single Metric | ||
Viewer** nor the **Anomaly Explorer** can plot and display an anomaly | ||
chart for the job. In these cases, the charts are not visible and an explanatory | ||
If your <<aggs-dfeeds,{dfeed} uses aggregations with nested `terms` aggs>> and | ||
model plot is not enabled for the {anomaly-job}, neither the **Single Metric | ||
Viewer** nor the **Anomaly Explorer** can plot and display an anomaly | ||
chart for the job. In these cases, the charts are not visible and an explanatory | ||
message is shown. | ||
|
||
When the aggregation interval of the {dfeed} and the bucket span of the job | ||
don't match, the values of the chart plotted in both the **Single Metric | ||
Viewer** and the **Anomaly Explorer** differ from the actual values of the job. | ||
To avoid this behavior, make sure that the aggregation interval in the {dfeed} | ||
configuration and the bucket span in the {anomaly-job} configuration have the | ||
When the aggregation interval of the {dfeed} and the bucket span of the job | ||
don't match, the values of the chart plotted in both the **Single Metric | ||
Viewer** and the **Anomaly Explorer** differ from the actual values of the job. | ||
To avoid this behavior, make sure that the aggregation interval in the {dfeed} | ||
configuration and the bucket span in the {anomaly-job} configuration have the | ||
same values. | ||
|
||
Your {dfeed} can contain multiple aggregations, but only the ones with names | ||
that match values in the job configuration are fed to the job. | ||
|
||
[discrete] | ||
[[aggs-include-jobs]] | ||
== Including aggregations in {anomaly-jobs} | ||
[[aggs-using-date-histogram]] | ||
=== Including aggregations in {anomaly-jobs} | ||
|
||
When you create or update an {anomaly-job}, you can include the names of | ||
aggregations, for example: | ||
|
@@ -86,8 +90,8 @@ PUT _ml/anomaly_detectors/farequote | |
---------------------------------- | ||
// TEST[skip:setup:farequote_data] | ||
|
||
<1> The `airline`, `responsetime`, and `time` fields are aggregations. Only the | ||
aggregated fields defined in the `analysis_config` object are analyzed by the | ||
<1> The `airline`, `responsetime`, and `time` fields are aggregations. Only the | ||
aggregated fields defined in the `analysis_config` object are analyzed by the | ||
{anomaly-job}. | ||
|
||
NOTE: When the `summary_count_field_name` property is set to a non-null value, | ||
|
@@ -134,25 +138,135 @@ PUT _ml/datafeeds/datafeed-farequote | |
---------------------------------- | ||
// TEST[skip:setup:farequote_job] | ||
|
||
<1> The aggregations have names that match the fields that they operate on. The | ||
<1> The aggregations have names that match the fields that they operate on. The | ||
`max` aggregation is named `time` and its field also needs to be `time`. | ||
<2> The `term` aggregation is named `airline` and its field is also named | ||
<2> The `term` aggregation is named `airline` and its field is also named | ||
`airline`. | ||
<3> The `avg` aggregation is named `responsetime` and its field is also named | ||
<3> The `avg` aggregation is named `responsetime` and its field is also named | ||
`responsetime`. | ||
|
||
Your {dfeed} can contain multiple aggregations, but only the ones with names | ||
that match values in the job configuration are fed to the job. | ||
TIP: If you are using a `term` aggregation to gather influencer or partition | ||
field information, consider using a `composite` aggregation. It performs | ||
better than a `date_histogram` with a nested `term` aggregation and also includes | ||
all the values of the field instead of the top values per bucket. | ||
|
||
[discrete] | ||
[[aggs-using-composite]] | ||
=== Using composite aggregations in {anomaly-jobs} | ||
|
||
experimental::[] | ||
|
||
For `composite` aggregation support, there must be exactly one `date_histogram` value | ||
source. That value source must not be sorted in descending order. Additional | ||
`composite` aggregation value sources are allowed, such as `terms`. | ||
|
||
NOTE: A {dfeed} that uses composite aggregations may not be as performant as datafeeds that use scrolling or | ||
date histogram aggregations. Composite aggregations are optimized | ||
for queries that are either `match_all` or `range` filters. Other types of | ||
queries may cause the `composite` aggregation to be ineffecient. | ||
|
||
Here is an example that uses a `composite` aggregation instead of a | ||
`date_histogram`. | ||
|
||
Assuming the same job configuration as above. | ||
|
||
[source,console] | ||
---------------------------------- | ||
PUT _ml/anomaly_detectors/farequote-composite | ||
{ | ||
"analysis_config": { | ||
"bucket_span": "60m", | ||
"detectors": [{ | ||
"function": "mean", | ||
"field_name": "responsetime", | ||
"by_field_name": "airline" | ||
}], | ||
"summary_count_field_name": "doc_count" | ||
}, | ||
"data_description": { | ||
"time_field":"time" | ||
} | ||
} | ||
---------------------------------- | ||
// TEST[skip:setup:farequote_data] | ||
|
||
This is an example of a datafeed that uses a `composite` aggregation to bucket | ||
the metrics based on time and terms: | ||
|
||
[source,console] | ||
---------------------------------- | ||
PUT _ml/datafeeds/datafeed-farequote-composite | ||
{ | ||
"job_id": "farequote-composite", | ||
"indices": [ | ||
"farequote" | ||
], | ||
"aggregations": { | ||
"buckets": { | ||
"composite": { | ||
"size": 1000, <1> | ||
"sources": [ | ||
{ | ||
"time_bucket": { <2> | ||
"date_histogram": { | ||
"field": "time", | ||
"fixed_interval": "360s", | ||
"time_zone": "UTC" | ||
} | ||
} | ||
}, | ||
{ | ||
"airline": { <3> | ||
"terms": { | ||
"field": "airline" | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
"aggregations": { | ||
"time": { <4> | ||
"max": { | ||
"field": "time" | ||
} | ||
}, | ||
"responsetime": { <5> | ||
"avg": { | ||
"field": "responsetime" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
---------------------------------- | ||
// TEST[skip:setup:farequote_job] | ||
|
||
<1> Provide the `size` to the composite agg to control how many resources | ||
are used when aggregating the data. A larger `size` means a faster datafeed but | ||
more cluster resources are used when searching. | ||
<2> The required `date_histogram` composite aggregation source. Make sure it | ||
is named differently than your desired time field. | ||
<3> Instead of using a regular `term` aggregation, adding a composite | ||
aggregation `term` source with the name `airline` works. Note its name | ||
is the same as the field. | ||
<4> The required `max` aggregation whose name is the time field in the | ||
job analysis config. | ||
<5> The `avg` aggregation is named `responsetime` and its field is also named | ||
`responsetime`. | ||
|
||
[discrete] | ||
[[aggs-dfeeds]] | ||
== Nested aggregations in {dfeeds} | ||
|
||
{dfeeds-cap} support complex nested aggregations. This example uses the | ||
`derivative` pipeline aggregation to find the first order derivative of the | ||
{dfeeds-cap} support complex nested aggregations. This example uses the | ||
`derivative` pipeline aggregation to find the first order derivative of the | ||
counter `system.network.out.bytes` for each value of the field `beat.name`. | ||
|
||
NOTE: `derivative` or other pipeline aggregations may not work within `composite` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Can we provide more information about when/why they might not work? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a link to the composite agg docs referencing pipeline aggs. |
||
aggregations. See | ||
{ref}/search-aggregations-bucket-composite-aggregation-pipeline-aggregations.html [composite aggregations and pipeline aggregations]. | ||
benwtrent marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
[source,js] | ||
---------------------------------- | ||
"aggregations": { | ||
|
@@ -247,8 +361,9 @@ number of unique entries for the `error` field. | |
[[aggs-define-dfeeds]] | ||
== Defining aggregations in {dfeeds} | ||
|
||
When you define an aggregation in a {dfeed}, it must have the following form: | ||
When you define an aggregation in a {dfeed}, it must have one of the following forms: | ||
|
||
When using a `date_histogram` aggregation to bucket by time: | ||
[source,js] | ||
---------------------------------- | ||
"aggregations": { | ||
|
@@ -282,36 +397,75 @@ When you define an aggregation in a {dfeed}, it must have the following form: | |
---------------------------------- | ||
// NOTCONSOLE | ||
|
||
The top level aggregation must be either a | ||
{ref}/search-aggregations-bucket.html[bucket aggregation] containing as single | ||
sub-aggregation that is a `date_histogram` or the top level aggregation is the | ||
required `date_histogram`. There must be exactly one `date_histogram` | ||
aggregation. For more information, see | ||
{ref}/search-aggregations-bucket-datehistogram-aggregation.html[Date histogram aggregation]. | ||
When using a `composite` aggregation: | ||
|
||
[source,js] | ||
---------------------------------- | ||
"aggregations": { | ||
"composite_agg": { | ||
"sources": [ | ||
{ | ||
"date_histogram_agg": { | ||
"field": "time", | ||
...settings... | ||
} | ||
}, | ||
...other valid sources... | ||
], | ||
...composite agg settings..., | ||
"aggregations": { | ||
"timestamp": { | ||
"max": { | ||
"field": "time" | ||
} | ||
}, | ||
...other aggregations... | ||
[ | ||
[,"aggregations" : { | ||
[<sub_aggregation>]+ | ||
} ] | ||
}] | ||
} | ||
} | ||
} | ||
---------------------------------- | ||
// NOTCONSOLE | ||
|
||
The top level aggregation must be exclusively one of the following: | ||
* A {ref}/search-aggregations-bucket.html[bucket aggregation] containing a single | ||
sub-aggregation that is a `date_histogram` | ||
* A top level aggregation that is a `date_histogram` | ||
* A top level aggregation is a `composite` aggregation. | ||
|
||
There must be exactly one `date_histogram`, `composite` aggregation. For more information, see | ||
{ref}/search-aggregations-bucket-datehistogram-aggregation.html[Date histogram aggregation] and | ||
{ref}/search-aggregations-bucket-composite-aggregation.html[Composite aggregation]. | ||
|
||
NOTE: The `time_zone` parameter in the date histogram aggregation must be set to | ||
`UTC`, which is the default value. | ||
|
||
Each histogram bucket has a key, which is the bucket start time. This key cannot | ||
be used for aggregations in {dfeeds}, however, because they need to know the | ||
time of the latest record within a bucket. Otherwise, when you restart a | ||
{dfeed}, it continues from the start time of the histogram bucket and possibly | ||
fetches the same data twice. The max aggregation for the time field is therefore | ||
necessary to provide the time of the latest record within a bucket. | ||
Each histogram or composite bucket has a key, which is the bucket start time. | ||
This key cannot be used for aggregations in {dfeeds}, however, because | ||
they need to know the time of the latest record within a bucket. | ||
Otherwise, when you restart a {dfeed}, it continues from the start time of the | ||
histogram or composite bucket and possibly fetches the same data twice. | ||
The max aggregation for the time field is therefore necessary to provide | ||
the time of the latest record within a bucket. | ||
|
||
You can optionally specify a terms aggregation, which creates buckets for | ||
different values of a field. | ||
|
||
IMPORTANT: If you use a terms aggregation, by default it returns buckets for | ||
the top ten terms. Thus if the cardinality of the term is greater than 10, not | ||
all terms are analyzed. | ||
all terms are analyzed. In this case, consider using `composite` aggregations | ||
experimental:[Support for composite aggregations inside datafeeds is currently experimental]. | ||
|
||
You can change this behavior by setting the `size` parameter. To | ||
determine the cardinality of your data, you can run searches such as: | ||
|
||
[source,js] | ||
-------------------------------------------------- | ||
GET .../_search | ||
GET .../_search | ||
{ | ||
"aggs": { | ||
"service_cardinality": { | ||
|
@@ -324,10 +478,11 @@ GET .../_search | |
-------------------------------------------------- | ||
// NOTCONSOLE | ||
|
||
|
||
By default, {es} limits the maximum number of terms returned to 10000. For high | ||
cardinality fields, the query might not run. It might return errors related to | ||
circuit breaking exceptions that indicate that the data is too large. In such | ||
cases, do not use aggregations in your {dfeed}. For more information, see | ||
cases, use `composite` aggregations in your {dfeed}. For more information, see | ||
{ref}/search-aggregations-bucket-terms-aggregation.html[Terms aggregation]. | ||
|
||
You can also optionally specify multiple sub-aggregations. The sub-aggregations | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'll eventually need to number these examples and perhaps even add anchors so that it's clear which are being referred to. Not necessarily in this PR, though.