Fixes #30678: propagate inherited domain to descendants in search on asset move - #31137
Fixes #30678: propagate inherited domain to descendants in search on asset move#31137sonika-shah wants to merge 1 commit into
Conversation
0731e8f to
28979de
Compare
❌ PR checklist incompleteThis PR cannot be merged until the following are addressed on its linked issue:
The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically. Maintainers can bypass this check by adding the |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (1)
openmetadata-service/src/main/java/org/openmetadata/service/search/SearchRepository.java:2576
- propagateInheritedDomainsToChildren uses the raw
searchClientfield and does not handle the “client unavailable” path. Both ES/OS clients’updateChildren(...)short-circuit when unavailable (no IOException), so this propagation can be silently dropped without enqueueing toSearchIndexRetryQueue(unlikeupdateAssetDomainsByIds,updateDomainFqnByPrefix, etc., which explicitly enqueue when the client is unavailable). UsinggetSearchClient()and enqueueing on unavailable keeps behavior consistent and makes the move recoverable via retries.
deferIfFlushScopeActive(
() -> {
try {
searchClient.updateChildren(childAliases, parentMatch, updates);
} catch (IOException e) {
SearchIndexRetryQueue.enqueue(
28979de to
6f6d7c4
Compare
| if (!dryRun) { | ||
| searchRepository.propagateInheritedDomainsToChildren( | ||
| request.getAssets(), isAdd ? List.of(domainRef) : List.of()); | ||
| } |
There was a problem hiding this comment.
Correct — clearing descendants on remove is wrong, since after detaching a domain the asset (and its descendants) may re-inherit from its own parent rather than go empty. Restricted the propagation to the add/move path (isAdd && !dryRun), which is the route the stale-descendant bug actually occurs on (a Domain-page move comes through as an add after cleanupOldDomain). The remove path keeps its prior behavior (no child propagation) — a correct remove-time re-inheritance would be a separate change.
| // The removal must NOT blank out the inherited descendant in search — its ancestry still | ||
| // carries | ||
| // a domain, so clearing it would be wrong. | ||
| List<EntityReference> childDomains = | ||
| searchDomains(inheritedChild.getId(), "table_search_index"); | ||
| assertNotNull(childDomains, "Child should still be indexed after removal"); | ||
| assertFalse( | ||
| childDomains.isEmpty(), | ||
| "Removing the schema from a domain must not clear its inherited descendant's domain in search"); |
There was a problem hiding this comment.
💡 Quality: Negative assertion on child domain not wrapped in Awaitility
In test_domainAssetRemove_doesNotClearReinheritingDescendantInSearch, the final check that the inheriting child was NOT cleared (lines 1641-1646) runs once, immediately after the schema re-inherit await. Because remove-propagation to descendants is asynchronous, a regression that erroneously clears the child's domain could land after this snapshot, letting the test pass while the bug exists — a weak negative assertion. Consider re-checking the child inside a short Awaitility poll (or a fixed settle delay after the schema converges) so the assertion holds across the full propagation window.
Was this helpful? React with 👍 / 👎
| } catch (IOException e) { | ||
| String reason = | ||
| SearchIndexRetryQueue.failureReason("propagateInheritedDomainsToChildren", e); | ||
| parentIds.forEach(id -> SearchIndexRetryQueue.enqueue(id, null, entityType, reason)); | ||
| } |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.
Suppressed comments (3)
openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/DomainResourceIT.java:1597
- This test name suggests it verifies that the descendant re-inherits the correct domain in search after removal, but the assertion only checks that the descendant
domainsfield is non-empty. Renaming the test to match what it actually asserts will avoid misleading future readers.
void test_domainAssetRemove_doesNotClearReinheritingDescendantInSearch(TestNamespace ns)
docker/development/docker-compose.omfix.yml:4
- This override compose file relies on the custom
!overrideYAML tag. If a developer’s Docker Compose version doesn’t support this tag/merge behavior, the file may not work as intended (ports/volumes may merge instead of replacing, or parsing may fail). Consider adding a brief note about the required Docker Compose capability/version in the header comment, or provide an alternative override approach for older compose versions.
# `!override` replaces the base list instead of merging (compose merges by default).
openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DomainRepository.java:388
domainRefis fetched even for dry-run requests, but it is only used on the non-dry-run add/move path (relationship write + lineage + search propagation). This adds an unnecessary DB read to dry-run validation requests.
EntityReference domainRef = isAdd ? getEntityReferenceById(DOMAIN, entityId, ALL) : null;
…change Two related search-index domain-propagation bugs, both surfaced as the entity page and the search index disagreeing for descendants. 1) open-metadata#30678 — Data Product domain change and the Domain-page asset move migrated only the directly-attached asset's domain in search; descendants that inherit their domain kept the old value in the index (the entity page was correct because inheritance is recomputed at read time). Add SearchRepository.propagateInheritedDomainsToChildren (one batched terms update-by-query per asset type, chunked, deferred out of the transaction), wired into both routes, reusing the inherited-guarded ADD_DOMAINS_SCRIPT so descendants that carry an explicit domain are left untouched. 2) open-metadata#31162 — A domain/owner change is recorded as delete-old + add-new, so child propagation runs generateRemoveListScript then generateAddListScript. The add script is inherited-guarded, but the remove script re-added the parent's new (inherited) domain unconditionally, appending it onto descendants that already carry an explicit domain (a search-only divergence; the DB stays correct). Guard the re-add so it runs only when no explicit value remains after removing inherited refs, mirroring the add script. The shared path also corrects the same latent behaviour for owners and dataProducts. Tests: DataProductResourceIT and DomainResourceIT integration tests covering the data-product route, the domain-page add/remove route, multi-level descendants, and the explicit-child over-append on a domain change. Fixes open-metadata#30678 Fixes open-metadata#31162
Code Review 👍 Approved with suggestions 3 resolved / 4 findingsPropagates inherited domains to descendants in the search index during asset moves, addressing the missing search propagation finding. Consider wrapping the negative assertion in Awaitility for the domain removal test. 💡 Quality: Negative assertion on child domain not wrapped in AwaitilityIn test_domainAssetRemove_doesNotClearReinheritingDescendantInSearch, the final check that the inheriting child was NOT cleared (lines 1641-1646) runs once, immediately after the schema re-inherit await. Because remove-propagation to descendants is asynchronous, a regression that erroneously clears the child's domain could land after this snapshot, letting the test pass while the bug exists — a weak negative assertion. Consider re-checking the child inside a short Awaitility poll (or a fixed settle delay after the schema converges) so the assertion holds across the full propagation window. ✅ 3 resolved✅ Bug: Child domain propagation bypasses search-write deferral in @transaction
✅ Quality: Retry enqueue drops known entityType for failed child propagation
✅ Edge Case: Batched terms query may hit index.max_terms_count on large moves
🤖 Prompt for agentsOptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source |
Fixes #30678
What
When an asset's domain changes via an asset-move route, descendants that inherit their domain updated on the entity page but not in the search index, so Explore, domain filters and asset counts kept showing them under the old domain until a reindex.
Two routes were affected:
DataProductRepository.updateDataProductDomainsreindexed only the directly-attached assets (updateAssetDomainsByIds, an ids-query).DomainRepository.bulkAssetsOperationcallsSearchRepository.updateEntity(ref), which nulls the change description, sorequiresPropagationis false and the child fan-out never runs.A normal single-entity domain PATCH already fans the change out to inherited descendants in search via
propagateInheritedFieldsToChildren. The two move routes bypassed that step; the DB side stayed correct only because inherited domains are recomputed at read time (EntityRepository.inheritDomains), while the search index stores a materializeddomainsarray that needs an explicit push.Fix
New
SearchRepository.propagateInheritedDomainsToChildren(entityType, assetId, newDomains)that pushes the moved asset's new domains onto its children in search, wired into both move routes.It reuses the existing
ADD_DOMAINS_SCRIPT, which overwrites a child'sdomainsonly when that child's domain is empty or inherited — so descendants that carry an explicit domain are left untouched, exactly as today. Child matching and service-vs-entity keying reuse the existingfilterChildAliasesByCapability/resolveParentFieldNamehelpers, so multi-level hierarchies (database → schema → table) are covered through the denormalized parent-id fields, the same way normal-PATCH propagation already works.Behaviour (per the issue)
For a schema asset in
Financemoved toHR:HRHRFinance(stale)HRFinanceFinanceFinance(unchanged)MarketingMarketingMarketing(unchanged)Tests
Integration test
DataProductResourceIT#test_changeDataProductDomain_propagatesInheritedDomainToChildTablesInSearch: assigns a schema (with inheriting + explicit-domain child tables) as a data product asset, moves the data product's domain, and asserts each child table'sdomainsin the search index — inheriting child follows, explicit-domain children stay put. Fails without the fix.Out of scope
This is issue #1 of #30676 (targeted for an early release). The remaining items — warning when a moved asset's own explicit domain is overwritten, and the conflicting-data-product-assignment cleanup (#30679) — are separate.
Also fixes #31162 — over-append to explicit-domain descendants on a domain change
While validating the above, a related search-propagation bug surfaced on the normal entity-update path (changing an entity's own domain, e.g. a schema's domain from its entity page): the parent's new domain was appended (as inherited) to descendants that already carry their own explicit domain — a search-only divergence (the entity/DB stays correct).
Root cause: a domain (or owner) change is recorded as delete-old + add-new, so child propagation runs
generateRemoveListScript(from the delete) thengenerateAddListScript(from the add). The add script is guarded and skips explicit children, but the remove script didremoveIf(inherited); addAll(removed<Field>)unconditionally, andremoved<Field>resolves to the parent's new domains marked inherited — appending them onto explicit children. Fix: only re-add when no explicit (non-inherited) value remains after removing inherited refs, mirroring the add script. Inherited descendants still follow the change; explicit ones keep their own domain. The shared path corrects the same latent behaviour forownersanddataProducts.Regression test:
DomainResourceIT#test_entityDomainChange_doesNotOverAppendToExplicitDescendantInSearch.