[ML] Enable alerts filtering with KQL bar#240100
Conversation
|
Pinging @elastic/ml-ui (:ml) |
There was a problem hiding this comment.
Pull Request Overview
This PR adds KQL-based filtering capability to ML Anomaly Detection alerting rules, allowing users to filter which anomalies trigger alerts based on field values. The implementation provides autocomplete suggestions tailored to the selected job and result type, and automatically disables conflicting UI controls when users specify score or interim filters in the KQL expression.
Key Changes:
- Added KQL filter input component with autocomplete for anomaly result fields
- Implemented logic to detect when KQL filters conflict with UI controls (severity, interim results) and disable those controls accordingly
- Extended server-side query logic to apply custom KQL filters when fetching anomaly results
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
alerting_service.ts |
Added KQL filter parsing and integration into Elasticsearch queries for anomaly detection alerts |
severity_control.tsx |
Added disabled state support with help text when KQL contains score filters |
register_anomaly_detection_rule.tsx |
Added KQL filter validation in rule registration |
ml_anomaly_alert_trigger.tsx |
Integrated KQL filter component and state management for field usage detection |
interim_results_control.tsx |
Added disabled state with tooltip when KQL contains is_interim filter |
get_relevant_anomaly_fields.ts |
Helper function to determine which anomaly fields are relevant for autocomplete based on job configuration and result type |
anomaly_kql_filter.tsx |
New component implementing KQL search bar with ML anomalies data view and filtered suggestions |
detect_anomaly_alert_field_usage.ts |
Utility to parse KQL and detect usage of score and interim fields |
alerts.ts |
Added customFilter parameter to alert params type definition |
alerts.ts (constants) |
Moved score field mapping to shared constant |
v1.ts |
Added customFilter to schema validation |
x-pack/platform/plugins/shared/ml/server/lib/alerts/alerting_service.ts
Outdated
Show resolved
Hide resolved
...atform/plugins/shared/ml/public/alerting/anomaly_detection_rule/ml_anomaly_alert_trigger.tsx
Show resolved
Hide resolved
|
@rbrtj, it looks like you're updating the parameters for a rule type! Please review the guidelines for making additive changes to rule type parameters and determine if your changes require an intermediate release. |
| } | ||
| } else { | ||
| if (savedFilterForNonBucketTypes && !ruleParams.customFilter) { | ||
| setRuleParams('customFilter', savedFilterForNonBucketTypes); |
There was a problem hiding this comment.
I'm finding that alerts aren't triggering if I don't have a filter set (Kibana sample data logs, logs_response_code_rates job, record type). Have you seen alerts with no filter?
There was a problem hiding this comment.
There might be some odd results here as the job against the sample logs data had results going into the future. Running up 'now' looks better, but worth checking the query when no filter and the time range being applied.
There was a problem hiding this comment.
Good catch!
It should be fixed with 61f41ce
What happened is that the query was missing 'LTE' filter
range: {
timestamp: {
gte: `now-${lookBackTimeInterval}`,
lte: 'now', // previously missing
},
},
It was working fine previously (probably by coincidence). I assume that after adding filters, Elasticsearch computes it differently, and future anomalies are detected. Adding the LTE filter fixes this behavior and makes it more predictable.
There was a problem hiding this comment.
I'm also able to see alerts when no filter and the time range being applied (with proper lookback interval).
| ) : ( | ||
| <FormattedMessage | ||
| id="xpack.ml.anomalyDetectionAlert.anomalyFilterDescription" | ||
| defaultMessage="Filter which anomalies trigger this alert based on field values." |
There was a problem hiding this comment.
Looking at the labels used for some other rules (cluster health, index threshold), this would be more consistent...
Use a KQL expression to limit which anomalies trigger alerts.
Also I wonder if the filter query bar should be below the severity slider seeing as it's an optional field?
darnautov
left a comment
There was a problem hiding this comment.
Left some comments. I also think this change deserves some API integration tests.
| /** User's override for the top N buckets */ | ||
| topNBuckets: schema.nullable(schema.number({ min: 1 })), | ||
| /** Optional KQL filter */ | ||
| customFilter: schema.nullable(schema.string()), |
There was a problem hiding this comment.
I think we should validate query string on the schema level, because alerting rules can be created via the API.
- Check if it's a valid KQL string
- Should not contain a job_id. Perhaps it'd be better to have an allowlist of fields.
| includeInterim: boolean; | ||
| lookbackInterval: string | null | undefined; | ||
| topNBuckets: number | null | undefined; | ||
| customFilter?: string | null; |
There was a problem hiding this comment.
Not sure about the name, because this filter and other params are not mutually exclusive. queryStringmaybe?
| export interface AnomalyAlertFieldUsage { | ||
| hasAnomalyScoreFilter: boolean; | ||
| hasInterimFilter: boolean; | ||
| } |
There was a problem hiding this comment.
Would it be easier to validate the query string and disallow these fields?
There was a problem hiding this comment.
And only show fields from allowlist in KQL bar suggestions
There was a problem hiding this comment.
Totally makes sense to me, removed in c9fadcf
| true | ||
| ); | ||
|
|
||
| setMlAnomaliesDataView(dataView); |
There was a problem hiding this comment.
potentially setting state for unmounted component here
| const fetchDataView = async () => { | ||
| try { | ||
| const allFields = await dataViewsService.getFieldsForWildcard({ | ||
| pattern: '.ml-anomalies-*', |
There was a problem hiding this comment.
there is const for this index pattern
| return acc; | ||
| }, {}); | ||
|
|
||
| const dataView = await dataViewsService.create( |
There was a problem hiding this comment.
you also need to clean up ad-hoc data views on unmount
| useEffect( | ||
| function parseAndNotifyFieldUsage() { | ||
| if (onFieldUsageChange) { | ||
| const usage = detectAnomalyAlertFieldUsage(value); | ||
| onFieldUsageChange(usage); | ||
| } | ||
| }, | ||
| [value, onFieldUsageChange] | ||
| ); |
There was a problem hiding this comment.
do we need this effect? can this logic be a part of onChange callback?
| useEffect( | ||
| function handleFilterPreservationAcrossResultTypes() { |
There was a problem hiding this comment.
why do we need this effect? it is quite difficult to follow. is it here to restore the prev filter value when the user is clicking on different result type tiles?
There was a problem hiding this comment.
Yup, I wanted to achieve such behavior:
- The user types something into the query bar when the record type is
recordorinfluencer - They switch to the
bucketresult type -> the KQL bar becomes empty and disabled - They switch back to the
recordorinfluencertype -> the KQL bar is restored with the previous filter
When switching betweenrecordandinfluencerit is preserved.
peteharverson
left a comment
There was a problem hiding this comment.
Overall looks good. Tested each of the result types with a variety of filters. Just left one question on jobs without influencers.
peteharverson
left a comment
There was a problem hiding this comment.
Tested latest changes and LGTM
jgowdyelastic
left a comment
There was a problem hiding this comment.
Sorry, left a load of nit picks about the preferred use of ?? over ||
But otherwise, LGTM
x-pack/platform/plugins/shared/ml/public/alerting/anomaly_detection_rule/anomaly_kql_filter.tsx
Outdated
Show resolved
Hide resolved
x-pack/platform/plugins/shared/ml/public/alerting/anomaly_detection_rule/anomaly_kql_filter.tsx
Outdated
Show resolved
Hide resolved
...form/plugins/shared/ml/public/alerting/anomaly_detection_rule/get_relevant_anomaly_fields.ts
Outdated
Show resolved
Hide resolved
...form/plugins/shared/ml/public/alerting/anomaly_detection_rule/get_relevant_anomaly_fields.ts
Outdated
Show resolved
Hide resolved
|
|
||
| if (jobConfigs.length > 0) { | ||
| jobConfigs.forEach((job) => { | ||
| const detectors = job.analysis_config?.detectors || []; |
There was a problem hiding this comment.
nit
| const detectors = job.analysis_config?.detectors || []; | |
| const detectors = job.analysis_config?.detectors ?? []; |
💛 Build succeeded, but was flaky
Failed CI StepsTest Failures
Metrics [docs]Module Count
Public APIs missing comments
Async chunks
Page load bundle
Unknown metric groupsAPI count
ESLint disabled line counts
Total ESLint disabled count
History
cc @rbrtj |
Resolves elastic#136392 This PR adds alert filtering capability for the Anomaly Detection Alerting Rule using the KQL bar. It provides proper auto-suggestions for the selected result and job type. How to test: ``` 1. Create a pre-configured Kibana sample e-commerce job without starting the datafeed. 2. Create an Anomaly Detection alerting rule based on the created job, e.g., with a 168h lookback interval and 168 latest buckets, select either the `record` or `influencer` result type. 3. Go to the AD jobs page and start the datafeed with `beginning of data` and `no end time` 4. Navigate back to the alerting rule, run the rule, and verify that it triggers an alert. 5. Create a new alerting rule with the desired filter. For example, if you alert was triggered for `customer_full_name.keyword: Eddie Lambert`, try filtering it out with: `NOT customer_full_name.keyword: "Eddie Lambert"` 6. Verify that the new rule does not trigger an alert for the specified `customer_full_name` 7. It's easier to use an email or slack connector to inspect the alerts. ``` If the user provides `record_score` or `influencer_score` in the KQL bar, the severity control is disabled and the provided query value is used. The same applies to the `is_interim` control. <img width="990" height="930" alt="image" src="https://github.com/user-attachments/assets/f53a4b8f-0191-46cd-8bca-913ec6077316" /> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Resolves elastic#136392 This PR adds alert filtering capability for the Anomaly Detection Alerting Rule using the KQL bar. It provides proper auto-suggestions for the selected result and job type. How to test: ``` 1. Create a pre-configured Kibana sample e-commerce job without starting the datafeed. 2. Create an Anomaly Detection alerting rule based on the created job, e.g., with a 168h lookback interval and 168 latest buckets, select either the `record` or `influencer` result type. 3. Go to the AD jobs page and start the datafeed with `beginning of data` and `no end time` 4. Navigate back to the alerting rule, run the rule, and verify that it triggers an alert. 5. Create a new alerting rule with the desired filter. For example, if you alert was triggered for `customer_full_name.keyword: Eddie Lambert`, try filtering it out with: `NOT customer_full_name.keyword: "Eddie Lambert"` 6. Verify that the new rule does not trigger an alert for the specified `customer_full_name` 7. It's easier to use an email or slack connector to inspect the alerts. ``` If the user provides `record_score` or `influencer_score` in the KQL bar, the severity control is disabled and the provided query value is used. The same applies to the `is_interim` control. <img width="990" height="930" alt="image" src="https://github.com/user-attachments/assets/f53a4b8f-0191-46cd-8bca-913ec6077316" /> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Resolves elastic#136392 This PR adds alert filtering capability for the Anomaly Detection Alerting Rule using the KQL bar. It provides proper auto-suggestions for the selected result and job type. How to test: ``` 1. Create a pre-configured Kibana sample e-commerce job without starting the datafeed. 2. Create an Anomaly Detection alerting rule based on the created job, e.g., with a 168h lookback interval and 168 latest buckets, select either the `record` or `influencer` result type. 3. Go to the AD jobs page and start the datafeed with `beginning of data` and `no end time` 4. Navigate back to the alerting rule, run the rule, and verify that it triggers an alert. 5. Create a new alerting rule with the desired filter. For example, if you alert was triggered for `customer_full_name.keyword: Eddie Lambert`, try filtering it out with: `NOT customer_full_name.keyword: "Eddie Lambert"` 6. Verify that the new rule does not trigger an alert for the specified `customer_full_name` 7. It's easier to use an email or slack connector to inspect the alerts. ``` If the user provides `record_score` or `influencer_score` in the KQL bar, the severity control is disabled and the provided query value is used. The same applies to the `is_interim` control. <img width="990" height="930" alt="image" src="https://github.com/user-attachments/assets/f53a4b8f-0191-46cd-8bca-913ec6077316" /> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
… alerting rule (#241274) Follow up to #240100 Resolves #239946 This PR enables the `Create alert rule` action from the Anomalies Table, Single Metric Viewer chart and Anomaly Charts. It pre-populates the alert rule form with: **Alert settings**: - Job ID - Severity - `anomaly score - 5` - Result Type - Score **KQL Filter**: - Partition filter field (if present) - Over filter field (if present) - By filter field (if present) - Influencer filters - all influencers from the anomaly - Actual value threshold https://github.com/user-attachments/assets/26a1934b-191f-48dd-8882-d7a1e1d60534
… alerting rule (elastic#241274) Follow up to elastic#240100 Resolves elastic#239946 This PR enables the `Create alert rule` action from the Anomalies Table, Single Metric Viewer chart and Anomaly Charts. It pre-populates the alert rule form with: **Alert settings**: - Job ID - Severity - `anomaly score - 5` - Result Type - Score **KQL Filter**: - Partition filter field (if present) - Over filter field (if present) - By filter field (if present) - Influencer filters - all influencers from the anomaly - Actual value threshold https://github.com/user-attachments/assets/26a1934b-191f-48dd-8882-d7a1e1d60534

Resolves #136392
This PR adds alert filtering capability for the Anomaly Detection Alerting Rule using the KQL bar.
It provides proper auto-suggestions for the selected result and job type.
How to test: