[Infra] Post-enrichment filtering for Hosts exclusion filters#260426
[Infra] Post-enrichment filtering for Hosts exclusion filters#260426rmyz merged 6 commits intoelastic:mainfrom
Conversation
Hosts that should be excluded by negative filters (e.g., NOT cloud.provider: gcp) were still appearing because APM documents often lack the filtered field, allowing them to bypass Elasticsearch must_not clauses. This adds a post-enrichment filter that checks enriched metadata values against the exclusion criteria after data retrieval, catching hosts that slip through earlier query-level filters. Closes elastic#256157 Made-with: Cursor
|
/ci |
💔 Build Failed
Failed CI StepsTest Failures
Metrics [docs]
Historycc @rmyz |
|
/ci |
There was a problem hiding this comment.
Pull request overview
Fixes Hosts UI negative-filter exclusions by post-filtering enriched host metadata so hosts whose APM docs lack the filtered field don’t “slip through” must_not and reappear after enrichment.
Changes:
- Adds
extractExcludedMetadataValuesto parsemust_notexclusions for enriched host metadata fields. - Applies post-enrichment filtering in
getHoststo remove hosts whose enriched metadata matches excluded values. - Updates
getHostsCountto align with the new behavior by post-filtering via a lightweight metadata aggregation.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| x-pack/solutions/observability/plugins/infra/server/routes/infra/lib/utils.ts | Adds utility to extract excluded metadata values from must_not query clauses. |
| x-pack/solutions/observability/plugins/infra/server/routes/infra/lib/utils.test.ts | Adds unit tests for excluded-metadata extraction. |
| x-pack/solutions/observability/plugins/infra/server/routes/infra/lib/host/get_hosts_count.ts | Aligns count logic with post-enrichment exclusion filtering using metadata aggregations. |
| x-pack/solutions/observability/plugins/infra/server/routes/infra/lib/host/get_hosts.ts | Applies post-enrichment filtering to host results and simplifies host-name collection. |
| x-pack/solutions/observability/plugins/infra/server/routes/infra/lib/host/get_hosts.test.ts | Adds unit tests covering union behavior and post-enrichment filtering scenarios. |
| x-pack/solutions/observability/plugins/infra/server/routes/infra/lib/host/get_filtered_hosts.ts | Simplifies API to return string[] and adjusts query filter composition/agg naming. |
| x-pack/solutions/observability/plugins/infra/common/constants.ts | Extracts MAX_HOST_COUNT_LIMIT constant. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Wrap documentsFilter in nested bool inside filter to enforce minimum_should_match - Handle multi-valued metadata (host.ip) in post-enrichment filtering - Guard bool.should extraction with minimum_should_match check Made-with: Cursor
|
/ci |
…ction When must/filter clauses are present in a bool query, ES defaults minimum_should_match to 0, making should clauses optional. Only extract excluded values from bool.should when it is actually required. Made-with: Cursor
|
/ci |
|
Pinging @elastic/obs-presentation-team (Team:obs-presentation) |
ApprovabilityVerdict: Needs human review This PR introduces post-enrichment filtering that changes which hosts are returned and counted based on metadata exclusion filters - a significant runtime behavior change affecting data processing pipelines. Additionally, the author does not own any of the modified files, which are all owned by @elastic/obs-presentation-team. You can customize Macroscope's approvability policy. Learn more. |
sbelastic
left a comment
There was a problem hiding this comment.
code LGTM, also tested locally and everything worked :)
|
Starting backport for target branches: 9.2, 9.3 |
💔 Some backports could not be created
Note: Successful backport PRs will be merged automatically after passing CI. Manual backportTo create the backport manually run: Questions ?Please refer to the Backport tool documentation |
💚 All backports created successfully
Note: Successful backport PRs will be merged automatically after passing CI. Questions ?Please refer to the Backport tool documentation |
…260426) (#260649) # Backport This will backport the following commits from `main` to `9.3`: - [[Infra] Post-enrichment filtering for Hosts exclusion filters (#260426)](#260426) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Sergi Romeu","email":"sergi.romeu@elastic.co"},"sourceCommit":{"committedDate":"2026-04-01T09:11:10Z","message":"[Infra] Post-enrichment filtering for Hosts exclusion filters (#260426)","sha":"705ddb99317ff5143909e5c8352db962affac98b","branchLabelMapping":{"^v9.4.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","backport:version","v9.4.0","Team:obs-presentation","v9.3.3","v9.2.8"],"title":"[Infra] Post-enrichment filtering for Hosts exclusion filters","number":260426,"url":"https://github.com/elastic/kibana/pull/260426","mergeCommit":{"message":"[Infra] Post-enrichment filtering for Hosts exclusion filters (#260426)","sha":"705ddb99317ff5143909e5c8352db962affac98b"}},"sourceBranch":"main","suggestedTargetBranches":["9.3","9.2"],"targetPullRequestStates":[{"branch":"main","label":"v9.4.0","branchLabelMappingKey":"^v9.4.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/260426","number":260426,"mergeCommit":{"message":"[Infra] Post-enrichment filtering for Hosts exclusion filters (#260426)","sha":"705ddb99317ff5143909e5c8352db962affac98b"}},{"branch":"9.3","label":"v9.3.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.2","label":"v9.2.8","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Sergi Romeu <sergi.romeu@elastic.co>
…260426) (#260658) # Backport This will backport the following commits from `main` to `9.2`: - [[Infra] Post-enrichment filtering for Hosts exclusion filters (#260426)](#260426) <!--- Backport version: 11.0.1 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Sergi Romeu","email":"sergi.romeu@elastic.co"},"sourceCommit":{"committedDate":"2026-04-01T09:11:10Z","message":"[Infra] Post-enrichment filtering for Hosts exclusion filters (#260426)","sha":"705ddb99317ff5143909e5c8352db962affac98b","branchLabelMapping":{"^v9.4.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","backport:version","v9.4.0","Team:obs-presentation","v9.3.3","v9.2.8"],"title":"[Infra] Post-enrichment filtering for Hosts exclusion filters","number":260426,"url":"https://github.com/elastic/kibana/pull/260426","mergeCommit":{"message":"[Infra] Post-enrichment filtering for Hosts exclusion filters (#260426)","sha":"705ddb99317ff5143909e5c8352db962affac98b"}},"sourceBranch":"main","suggestedTargetBranches":["9.2"],"targetPullRequestStates":[{"branch":"main","label":"v9.4.0","branchLabelMappingKey":"^v9.4.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/260426","number":260426,"mergeCommit":{"message":"[Infra] Post-enrichment filtering for Hosts exclusion filters (#260426)","sha":"705ddb99317ff5143909e5c8352db962affac98b"}},{"branch":"9.3","label":"v9.3.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/260649","number":260649,"state":"OPEN"},{"branch":"9.2","label":"v9.2.8","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
Summary
Closes #256157
Hosts that should be excluded by negative filters (e.g.,
NOT cloud.provider: gcp) were still appearing in the Hosts UI. This happened because APM documents for some hosts lack the filtered field entirely, which causes Elasticsearchmust_notclauses to pass those documents through. After enrichment (getAllHosts), these hosts would show the excluded metadata value (e.g.,cloud.provider: gcp), contradicting the user's filter.Changes
getHosts: AftergetAllHostsenriches host data with metadata (cloud.provider,host.os.name,host.ip), a new filter checks each host's metadata againstmust_notexclusion values from the user's query. Hosts whose enriched metadata matches an excluded value are removed from the final result.extractExcludedMetadataValuesutility: Parsesmust_notclauses from the query and extracts excluded field/value pairs for metadata fields. Supportsmatch_phrase,match,term,terms, and nestedbool.shouldinsidemust_not.getHostsCount: The count endpoint now follows the same pattern — gets the host name union, and when there are excluded metadata values, runs a lightweight metadata-only query to post-filter before counting.getFilteredHostNames: Returnsstring[]instead of{ allHosts, filteredHosts }. TheallHostssub-aggregation was removed since it's no longer needed.getHostNames: Reverted to a plain union of infra + APM hosts. The previous infra-based exclusion logic was insufficient for APM-only hosts not recognized by infra.getHasDataFromSystemIntegrationcall: The pre-check was unnecessary sincegetFilteredHostNameshandles empty results gracefully.MAX_HOST_COUNT_LIMITtocommon/constants.tsinstead of hardcoding.queryHasNegationutility (no longer needed).Demo
Before
Kapture.2026-03-31.at.15.37.33.mp4
After
Kapture.2026-03-31.at.12.43.39.mp4
How it works
Testing
getHostscovering union behavior and post-enrichment filtering (including the exact reproduction scenario)extractExcludedMetadataValuescovering all query clause types