Skip to content

[ML] Anomaly Detection: Adds an action to create an anomaly detection alerting rule#241274

Merged
rbrtj merged 15 commits intoelastic:mainfrom
rbrtj:anomalies-table-anomaly-detection-alerting-rule
Dec 11, 2025
Merged

[ML] Anomaly Detection: Adds an action to create an anomaly detection alerting rule#241274
rbrtj merged 15 commits intoelastic:mainfrom
rbrtj:anomalies-table-anomaly-detection-alerting-rule

Conversation

@rbrtj
Copy link
Contributor

@rbrtj rbrtj commented Oct 30, 2025

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
Screen.Recording.2025-12-01.at.10.56.05.mov
@github-actions
Copy link
Contributor

@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.

@rbrtj rbrtj self-assigned this Dec 1, 2025
@rbrtj rbrtj changed the title [WIP] Create Alerting rule action in Anomalies table & Single Metric Viewer chart Dec 1, 2025
@rbrtj rbrtj added release_note:enhancement :ml backport:skip This PR does not require backporting Team:ML Team label for ML (also use :ml) t// v9.3.0 labels Dec 1, 2025
@rbrtj rbrtj marked this pull request as ready for review December 1, 2025 09:59
@rbrtj rbrtj requested a review from a team as a code owner December 1, 2025 09:59
@elasticmachine
Copy link
Contributor

Pinging @elastic/ml-ui (:ml)

addFieldFilter(kqlParts, anomaly.source.by_field_name, anomaly.source.by_field_value);

// Add influencer filters
if (Array.isArray(anomaly.influencers) && anomaly.influencers.length > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this part working? I don't see influencers getting adding to the rule.

Screen.Recording.2025-12-01.at.17.58.35.mov

Although I wonder if we actually want to include influencers? What would we do in the example above where there are multiple influencers contributing to the spike in bytes? It is probably simpler to just filter on the 'found for' field shown in the table.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is failing because the structure of the influencers inside the anomaly is like this:

Screenshot 2025-12-02 at 10 37 29

But as mentioned above, not convinced we should be filtering on influencers here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the influencers filter in be15197

* Builds initial alert parameters from an anomaly record.
* Pre-populates job ID, severity, result type, and KQL filter based on the anomaly's characteristics.
*/
export function buildAlertParamsFromAnomaly(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might be best off using an approach similar to that used in getEntityFieldList which is used elsewhere in the UI, to and the entity fields from the record in the KQL filter, and don't add the influencers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in be15197

}

// Combine all KQL parts
const kqlQueryString = kqlParts.length > 0 ? kqlParts.join(' and ') : null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit - when I created this rule I first thought that the actual value hadn't been appended, till I realized it had overflowed onto a second line. Is there anything we could do here to make it clearer that the full string is over more than one line?

Screenshot 2025-12-03 at 09 47 09 Screenshot 2025-12-03 at 09 49 09 Screenshot 2025-12-03 at 09 52 07
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there is an easy solution for this. I checked several places, and the KQL bar behaves the same everywhere

Copy link
Contributor

@peteharverson peteharverson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested latest changes against a variety of job configs (including categorization jobs) and LGTM.

Just left one comment about the KQL query input.

Copy link
Member

@jgowdyelastic jgowdyelastic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

}
});

const actualValue = Array.isArray(anomaly.actual) ? anomaly.actual[0] : anomaly.actual;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, does this also need a anomaly.actual.length check? or will it always be populated if it is an array?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it doesn't, the same pattern is used in various places in ML + we later check if actualValue is defined.

@rbrtj rbrtj enabled auto-merge (squash) December 11, 2025 15:16
@rbrtj rbrtj merged commit b8173e3 into elastic:main Dec 11, 2025
12 checks passed
@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
ml 4187 4188 +1

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
ml 5.6MB 5.6MB +18.9KB
Unknown metric groups

async chunk count

id before after diff
ml 110 111 +1

History

cc @rbrtj

seanrathier pushed a commit to seanrathier/kibana that referenced this pull request Dec 15, 2025
… 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting :ml release_note:enhancement Team:ML Team label for ML (also use :ml) t// v9.3.0

4 participants