From b677d2feb4240891fa6e4a77467c3df842f428ea Mon Sep 17 00:00:00 2001 From: Suman Das <59254445+sumandas0@users.noreply.github.com> Date: Mon, 19 Aug 2024 08:42:15 +0530 Subject: [PATCH 1/4] feat: enable hierarchical filters for qualifedName --- .../apache/atlas/repository/Constants.java | 1 + .../graph/GraphBackedSearchIndexer.java | 1 + .../store/aliasstore/ESAliasStore.java | 37 ++++++++++++++++--- .../store/graph/v2/AtlasEntityStoreV2.java | 32 ++++++++++++++++ 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/org/apache/atlas/repository/Constants.java b/common/src/main/java/org/apache/atlas/repository/Constants.java index 640be44ba9..908e8e6539 100644 --- a/common/src/main/java/org/apache/atlas/repository/Constants.java +++ b/common/src/main/java/org/apache/atlas/repository/Constants.java @@ -56,6 +56,7 @@ public final class Constants { public static final String GUID_PROPERTY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "guid"); public static final String RELATIONSHIP_GUID_PROPERTY_KEY = encodePropertyKey(RELATIONSHIP_PROPERTY_KEY_PREFIX + GUID_PROPERTY_KEY); public static final String HISTORICAL_GUID_PROPERTY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "historicalGuids"); + public static final String QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "qualifiedNameHierarchy"); public static final String FREETEXT_REQUEST_HANDLER = "/freetext"; public static final String TERMS_REQUEST_HANDLER = "/terms"; public static final String ES_API_ALIASES = "/_aliases"; diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedSearchIndexer.java b/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedSearchIndexer.java index 52ec9840ae..5f79de4dd8 100755 --- a/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedSearchIndexer.java +++ b/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedSearchIndexer.java @@ -351,6 +351,7 @@ private void initialize(AtlasGraph graph) throws RepositoryException, IndexExcep // create vertex indexes createCommonVertexIndex(management, GUID_PROPERTY_KEY, UniqueKind.GLOBAL_UNIQUE, String.class, SINGLE, true, false, true); createCommonVertexIndex(management, HISTORICAL_GUID_PROPERTY_KEY, UniqueKind.GLOBAL_UNIQUE, String.class, SINGLE, true, false); + createCommonVertexIndex(management, QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY, UniqueKind.NONE, String.class, SET, false, false, true); createCommonVertexIndex(management, TYPENAME_PROPERTY_KEY, UniqueKind.GLOBAL_UNIQUE, String.class, SINGLE, true, false); createCommonVertexIndex(management, TYPESERVICETYPE_PROPERTY_KEY, UniqueKind.NONE, String.class, SINGLE, true, false); diff --git a/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java b/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java index 220d380077..054d221900 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java @@ -26,6 +26,7 @@ import org.apache.atlas.repository.graphdb.AtlasGraph; import org.apache.atlas.repository.graphdb.janus.AtlasElasticsearchDatabase; import org.apache.atlas.repository.store.graph.v2.EntityGraphRetriever; +import org.apache.atlas.service.FeatureFlagStore; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; @@ -47,6 +48,7 @@ import static org.apache.atlas.repository.Constants.QUALIFIED_NAME; import static org.apache.atlas.repository.Constants.TRAIT_NAMES_PROPERTY_KEY; import static org.apache.atlas.repository.Constants.VERTEX_INDEX_NAME; +import static org.apache.atlas.repository.Constants.QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY; import static org.apache.atlas.repository.util.AccessControlUtils.ACCESS_READ_PERSONA_DOMAIN; import static org.apache.atlas.repository.util.AccessControlUtils.ACCESS_READ_PERSONA_METADATA; import static org.apache.atlas.repository.util.AccessControlUtils.ACCESS_READ_PERSONA_GLOSSARY; @@ -68,6 +70,7 @@ public class ESAliasStore implements IndexAliasStore { private static final Logger LOG = LoggerFactory.getLogger(ESAliasStore.class); public static final String NEW_WILDCARD_DOMAIN_SUPER = "default/domain/*/super"; + public static final String ENABLE_PERSONA_HIERARCHY_FILTER = "enable_persona_hierarchy_filter"; private final AtlasGraph graph; private final EntityGraphRetriever entityRetriever; @@ -160,7 +163,8 @@ private Map getFilterForPersona(AtlasEntity.AtlasEntityWithExtIn policies.add(policy); } if (CollectionUtils.isNotEmpty(policies)) { - personaPolicyToESDslClauses(policies, allowClauseList); + boolean useHierarchicalQualifiedNameFilter = FeatureFlagStore.evaluate(ENABLE_PERSONA_HIERARCHY_FILTER, "true"); + personaPolicyToESDslClauses(policies, allowClauseList, useHierarchicalQualifiedNameFilter); } return esClausesToFilter(allowClauseList); @@ -177,9 +181,10 @@ private Map getFilterForPurpose(AtlasEntity purpose) throws Atla } private void personaPolicyToESDslClauses(List policies, - List> allowClauseList) throws AtlasBaseException { + List> allowClauseList, boolean useHierarchicalQualifiedNameFilter) throws AtlasBaseException { Set terms = new HashSet<>(); Set glossaryQualifiedNames =new HashSet<>(); + Set metadataPolicyQualifiedNames = new HashSet<>(); for (AtlasEntity policy: policies) { @@ -198,16 +203,33 @@ private void personaPolicyToESDslClauses(List policies, } for (String asset : assets) { - if (asset.contains("*") || asset.contains("?")) { - //DG-898 Bug fix + /* + * We are introducing a hierarchical filter for qualifiedName. + * This requires a migration of existing data to have a hierarchical qualifiedName. + * So this will only work if migration is done, upon migration completion we will set the feature flag to true + * This will be dictated by the feature flag ENABLE_PERSONA_HIERARCHY_FILTER + */ + + boolean isWildcard = asset.contains("*") || asset.contains("?"); + + if (isWildcard) { allowClauseList.add(mapOf("wildcard", mapOf(QUALIFIED_NAME, asset))); + } else if (useHierarchicalQualifiedNameFilter) { + metadataPolicyQualifiedNames.add(asset); } else { terms.add(asset); } - allowClauseList.add(mapOf("wildcard", mapOf(QUALIFIED_NAME, asset + "/*"))); + + if (!useHierarchicalQualifiedNameFilter || isWildcard) { + allowClauseList.add(mapOf("wildcard", mapOf(QUALIFIED_NAME, asset + "/*"))); + } } - terms.add(connectionQName); + if (useHierarchicalQualifiedNameFilter) { + metadataPolicyQualifiedNames.add(connectionQName); + } else { + terms.add(connectionQName); + } } else if (getPolicyActions(policy).contains(ACCESS_READ_PERSONA_GLOSSARY)) { if (CollectionUtils.isNotEmpty(assets)) { @@ -250,6 +272,9 @@ private void personaPolicyToESDslClauses(List policies, } allowClauseList.add(mapOf("terms", mapOf(QUALIFIED_NAME, new ArrayList<>(terms)))); + if (CollectionUtils.isNotEmpty(metadataPolicyQualifiedNames)) { + allowClauseList.add(mapOf("terms", mapOf(QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY, new ArrayList<>(metadataPolicyQualifiedNames)))); + } if (CollectionUtils.isNotEmpty(glossaryQualifiedNames)) { allowClauseList.add(mapOf("terms", mapOf(GLOSSARY_PROPERTY_KEY, new ArrayList<>(glossaryQualifiedNames)))); diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java index a5b168f1e7..80401353aa 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java @@ -1456,6 +1456,7 @@ private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_CREATE, new AtlasEntityHeader(entity)), "create entity: type=", entity.getTypeName()); } + createQualifiedNameHierarchyField(entity, context.getVertex(entity.getGuid())); } } // for existing entities, skip update if incoming entity doesn't have any change @@ -1475,6 +1476,10 @@ private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean AtlasEntityDiffResult diffResult = entityComparator.getDiffResult(entity, storedVertex, !storeDifferentialAudits); if (diffResult.hasDifference()) { + if (diffResult.getDiffEntity().hasAttribute(QUALIFIED_NAME)) { + createQualifiedNameHierarchyField(entity, storedVertex); + } + if (storeDifferentialAudits) { diffResult.getDiffEntity().setGuid(entity.getGuid()); reqContext.cacheDifferentialEntity(diffResult.getDiffEntity()); @@ -1802,6 +1807,33 @@ private AtlasStruct getStarredDetailsStruct(String assetStarredBy, long assetSta return starredDetails; } + private void createQualifiedNameHierarchyField(AtlasEntity entity, AtlasVertex vertex) { + if (entity.hasAttribute(QUALIFIED_NAME)) { + String qualifiedName = (String) entity.getAttribute(QUALIFIED_NAME); + if (StringUtils.isNotEmpty(qualifiedName)) { + vertex.removeProperty(QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY); + String[] parts = qualifiedName.split("/"); + StringBuilder currentPath = new StringBuilder(); + + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (StringUtils.isNotEmpty(part)) { + if (i > 0) { + currentPath.append("/"); + } + currentPath.append(part); + // i>1 reason: we don't want to add the first part of the qualifiedName as it is the entity name + // Example qualifiedName : default/snowflake/123/db_name we only want `default/snowflake/123` and `default/snowflake/123/db_name` + if (i > 1) { + AtlasGraphUtilsV2.addEncodedProperty(vertex, QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY, currentPath.toString()); + } + } + } + } + } + } + + public PreProcessor getPreProcessor(String typeName) { PreProcessor preProcessor = null; From 9f5ea5fa3489f4be4d540aae953b2d2b72e11265 Mon Sep 17 00:00:00 2001 From: Suman Das <59254445+sumandas0@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:55:38 +0530 Subject: [PATCH 2/4] fix: no need to add connectionQNames in the hierarchical filter, as it will bring all the assets under that connection --- .../atlas/repository/store/aliasstore/ESAliasStore.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java b/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java index 054d221900..499b572b76 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java @@ -225,11 +225,7 @@ private void personaPolicyToESDslClauses(List policies, } } - if (useHierarchicalQualifiedNameFilter) { - metadataPolicyQualifiedNames.add(connectionQName); - } else { - terms.add(connectionQName); - } + terms.add(connectionQName); } else if (getPolicyActions(policy).contains(ACCESS_READ_PERSONA_GLOSSARY)) { if (CollectionUtils.isNotEmpty(assets)) { From 03da5ca9ba9732ca4fbc8666d7929a9bac9f85aa Mon Sep 17 00:00:00 2001 From: Suman Das <59254445+sumandas0@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:38:41 +0530 Subject: [PATCH 3/4] feat: add qualifiedName hierarchy after preprocessor --- .../store/aliasstore/ESAliasStore.java | 6 +- .../store/graph/v2/AtlasEntityStoreV2.java | 63 ++++++++++++------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java b/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java index 499b572b76..b5962de2b7 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/aliasstore/ESAliasStore.java @@ -210,8 +210,12 @@ private void personaPolicyToESDslClauses(List policies, * This will be dictated by the feature flag ENABLE_PERSONA_HIERARCHY_FILTER */ + // If asset resource ends with /* then add it in hierarchical filter + boolean isHierarchical = asset.endsWith("/*"); + if (isHierarchical) { + asset = asset.substring(0, asset.length() - 2); + } boolean isWildcard = asset.contains("*") || asset.contains("?"); - if (isWildcard) { allowClauseList.add(mapOf("wildcard", mapOf(QUALIFIED_NAME, asset))); } else if (useHierarchicalQualifiedNameFilter) { diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java index 80401353aa..eb66158603 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java @@ -1456,7 +1456,6 @@ private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_CREATE, new AtlasEntityHeader(entity)), "create entity: type=", entity.getTypeName()); } - createQualifiedNameHierarchyField(entity, context.getVertex(entity.getGuid())); } } // for existing entities, skip update if incoming entity doesn't have any change @@ -1476,10 +1475,6 @@ private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean AtlasEntityDiffResult diffResult = entityComparator.getDiffResult(entity, storedVertex, !storeDifferentialAudits); if (diffResult.hasDifference()) { - if (diffResult.getDiffEntity().hasAttribute(QUALIFIED_NAME)) { - createQualifiedNameHierarchyField(entity, storedVertex); - } - if (storeDifferentialAudits) { diffResult.getDiffEntity().setGuid(entity.getGuid()); reqContext.cacheDifferentialEntity(diffResult.getDiffEntity()); @@ -1534,6 +1529,20 @@ private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean executePreProcessor(context); + // Updating hierarchy after preprocessor is executed so that qualifiedName update during preprocessor is considered + for (AtlasEntity entity : context.getCreatedEntities()) { + createQualifiedNameHierarchyField(entity, context.getVertex(entity.getGuid())); + } + + for (AtlasEntity entity : context.getUpdatedEntities()) { + // If qualifiedName update is part of the update, update the qualifiedName hierarchy field + AtlasEntity diffEntity = RequestContext.get().getDifferentialEntitiesMap().get(entity.getGuid()); + if (diffEntity != null && diffEntity.hasAttribute(QUALIFIED_NAME)) { + createQualifiedNameHierarchyField(entity, context.getVertex(entity.getGuid())); + } + } + + EntityMutationResponse ret = entityGraphMapper.mapAttributesAndClassifications(context, isPartialUpdate, replaceClassifications, replaceBusinessAttributes, isOverwriteBusinessAttribute); @@ -1808,28 +1817,36 @@ private AtlasStruct getStarredDetailsStruct(String assetStarredBy, long assetSta } private void createQualifiedNameHierarchyField(AtlasEntity entity, AtlasVertex vertex) { - if (entity.hasAttribute(QUALIFIED_NAME)) { - String qualifiedName = (String) entity.getAttribute(QUALIFIED_NAME); - if (StringUtils.isNotEmpty(qualifiedName)) { - vertex.removeProperty(QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY); - String[] parts = qualifiedName.split("/"); - StringBuilder currentPath = new StringBuilder(); - - for (int i = 0; i < parts.length; i++) { - String part = parts[i]; - if (StringUtils.isNotEmpty(part)) { - if (i > 0) { - currentPath.append("/"); - } - currentPath.append(part); - // i>1 reason: we don't want to add the first part of the qualifiedName as it is the entity name - // Example qualifiedName : default/snowflake/123/db_name we only want `default/snowflake/123` and `default/snowflake/123/db_name` - if (i > 1) { - AtlasGraphUtilsV2.addEncodedProperty(vertex, QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY, currentPath.toString()); + MetricRecorder metric = RequestContext.get().startMetricRecord("createQualifiedNameHierarchyField"); + try { + if (vertex == null) { + vertex = AtlasGraphUtilsV2.findByGuid(graph, entity.getGuid()); + } + if (entity.hasAttribute(QUALIFIED_NAME)) { + String qualifiedName = (String) entity.getAttribute(QUALIFIED_NAME); + if (StringUtils.isNotEmpty(qualifiedName)) { + vertex.removeProperty(QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY); + String[] parts = qualifiedName.split("/"); + StringBuilder currentPath = new StringBuilder(); + + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (StringUtils.isNotEmpty(part)) { + if (i > 0) { + currentPath.append("/"); + } + currentPath.append(part); + // i>1 reason: we don't want to add the first part of the qualifiedName as it is the entity name + // Example qualifiedName : default/snowflake/123/db_name we only want `default/snowflake/123` and `default/snowflake/123/db_name` + if (i > 1) { + AtlasGraphUtilsV2.addEncodedProperty(vertex, QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY, currentPath.toString()); + } } } } } + } finally { + RequestContext.get().endMetricRecord(metric); } } From dd3b077b1abefd66099d7ce2b4e362ed1e04a5e7 Mon Sep 17 00:00:00 2001 From: Suman Das <59254445+sumandas0@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:01:16 +0530 Subject: [PATCH 4/4] fix: fix diff for data products and domains as diff had the stale data --- .../store/graph/v2/AtlasEntityStoreV2.java | 15 +++++++++------ .../datamesh/DataDomainPreProcessor.java | 13 +++++++++++++ .../datamesh/DataProductPreProcessor.java | 11 +++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java index eb66158603..c0bb42298c 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java @@ -1534,11 +1534,9 @@ private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean createQualifiedNameHierarchyField(entity, context.getVertex(entity.getGuid())); } - for (AtlasEntity entity : context.getUpdatedEntities()) { - // If qualifiedName update is part of the update, update the qualifiedName hierarchy field - AtlasEntity diffEntity = RequestContext.get().getDifferentialEntitiesMap().get(entity.getGuid()); - if (diffEntity != null && diffEntity.hasAttribute(QUALIFIED_NAME)) { - createQualifiedNameHierarchyField(entity, context.getVertex(entity.getGuid())); + for (Map.Entry entry : RequestContext.get().getDifferentialEntitiesMap().entrySet()) { + if (entry.getValue().hasAttribute(QUALIFIED_NAME)) { + createQualifiedNameHierarchyField(entry.getValue(), context.getVertex(entry.getKey())); } } @@ -1818,6 +1816,8 @@ private AtlasStruct getStarredDetailsStruct(String assetStarredBy, long assetSta private void createQualifiedNameHierarchyField(AtlasEntity entity, AtlasVertex vertex) { MetricRecorder metric = RequestContext.get().startMetricRecord("createQualifiedNameHierarchyField"); + boolean isDataMeshType = entity.getTypeName().equals(DATA_PRODUCT_ENTITY_TYPE) || entity.getTypeName().equals(DATA_DOMAIN_ENTITY_TYPE); + int qualifiedNameOffset = isDataMeshType ? 2 : 1; try { if (vertex == null) { vertex = AtlasGraphUtilsV2.findByGuid(graph, entity.getGuid()); @@ -1838,7 +1838,10 @@ private void createQualifiedNameHierarchyField(AtlasEntity entity, AtlasVertex v currentPath.append(part); // i>1 reason: we don't want to add the first part of the qualifiedName as it is the entity name // Example qualifiedName : default/snowflake/123/db_name we only want `default/snowflake/123` and `default/snowflake/123/db_name` - if (i > 1) { + if (i > qualifiedNameOffset) { + if (isDataMeshType && (part.equals("domain") || part.equals("product"))) { + continue; + } AtlasGraphUtilsV2.addEncodedProperty(vertex, QUALIFIED_NAME_HIERARCHY_PROPERTY_KEY, currentPath.toString()); } } diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/datamesh/DataDomainPreProcessor.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/datamesh/DataDomainPreProcessor.java index 4d0792a70e..929e97bdcc 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/datamesh/DataDomainPreProcessor.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/datamesh/DataDomainPreProcessor.java @@ -196,6 +196,7 @@ private void processMoveSubDomainToAnotherDomain(AtlasEntity domain, try { String domainName = (String) domain.getAttribute(NAME); String updatedQualifiedName = ""; + LinkedHashMap updatedAttributes = new LinkedHashMap<>(); LOG.info("Moving subdomain {} to Domain {}", domainName, targetDomainQualifiedName); @@ -210,6 +211,10 @@ private void processMoveSubDomainToAnotherDomain(AtlasEntity domain, domain.setAttribute(PARENT_DOMAIN_QN_ATTR, null); domain.setAttribute(SUPER_DOMAIN_QN_ATTR, null); superDomainQualifiedName = updatedQualifiedName ; + + updatedAttributes.put(QUALIFIED_NAME, updatedQualifiedName); + updatedAttributes.put(PARENT_DOMAIN_QN_ATTR, null); + updatedAttributes.put(SUPER_DOMAIN_QN_ATTR, null); } else{ if(StringUtils.isEmpty(sourceDomainQualifiedName)){ @@ -221,6 +226,10 @@ private void processMoveSubDomainToAnotherDomain(AtlasEntity domain, domain.setAttribute(QUALIFIED_NAME, updatedQualifiedName); domain.setAttribute(PARENT_DOMAIN_QN_ATTR, targetDomainQualifiedName); domain.setAttribute(SUPER_DOMAIN_QN_ATTR, superDomainQualifiedName); + + updatedAttributes.put(QUALIFIED_NAME, updatedQualifiedName); + updatedAttributes.put(PARENT_DOMAIN_QN_ATTR, targetDomainQualifiedName); + updatedAttributes.put(SUPER_DOMAIN_QN_ATTR, superDomainQualifiedName); } Iterator existingParentEdges = domainVertex.getEdges(AtlasEdgeDirection.IN, DOMAIN_PARENT_EDGE_LABEL).iterator(); @@ -232,6 +241,10 @@ private void processMoveSubDomainToAnotherDomain(AtlasEntity domain, this.updatedPolicyResources.put("entity:" + currentQualifiedName, "entity:" + updatedQualifiedName); this.updatedDomainQualifiedNames.put(currentQualifiedName, updatedQualifiedName); + for (Map.Entry entry : updatedAttributes.entrySet()) { + RequestContext.get().getDifferentialEntitiesMap().get(domain.getGuid()).setAttribute(entry.getKey(), entry.getValue()); + } + moveChildren(domainVertex, superDomainQualifiedName, updatedQualifiedName, sourceDomainQualifiedName, targetDomainQualifiedName); updatePolicies(this.updatedPolicyResources, this.context); updateStakeholderTitlesAndStakeholders(this.updatedDomainQualifiedNames, this.context); diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/datamesh/DataProductPreProcessor.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/datamesh/DataProductPreProcessor.java index a619aad063..d8aee05974 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/datamesh/DataProductPreProcessor.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/datamesh/DataProductPreProcessor.java @@ -190,6 +190,7 @@ private void processMoveDataProductToAnotherDomain(AtlasEntity product, try { String productName = (String) product.getAttribute(NAME); + LinkedHashMap updatedAttributes = new LinkedHashMap<>(); LOG.info("Moving dataProduct {} to Domain {}", productName, targetDomainQualifiedName); @@ -206,6 +207,10 @@ private void processMoveDataProductToAnotherDomain(AtlasEntity product, product.setAttribute(PARENT_DOMAIN_QN_ATTR, targetDomainQualifiedName); product.setAttribute(SUPER_DOMAIN_QN_ATTR, superDomainQualifiedName); + updatedAttributes.put(QUALIFIED_NAME, updatedQualifiedName); + updatedAttributes.put(PARENT_DOMAIN_QN_ATTR, targetDomainQualifiedName); + updatedAttributes.put(SUPER_DOMAIN_QN_ATTR, superDomainQualifiedName); + Iterator existingParentEdges = productVertex.getEdges(AtlasEdgeDirection.IN, DATA_PRODUCT_EDGE_LABEL).iterator(); if (existingParentEdges.hasNext()) { graph.removeEdge(existingParentEdges.next()); @@ -216,8 +221,14 @@ private void processMoveDataProductToAnotherDomain(AtlasEntity product, String updatedResource = "entity:"+ updatedQualifiedName; this.updatedPolicyResources.put(currentResource, updatedResource); + for (Map.Entry entry : updatedAttributes.entrySet()) { + RequestContext.get().getDifferentialEntitiesMap() + .get(product.getGuid()).setAttribute(entry.getKey(), entry.getValue()); + } + LOG.info("Moved dataProduct {} to Domain {}", productName, targetDomainQualifiedName); + } finally { RequestContext.get().endMetricRecord(recorder); }