diff --git a/gms/api/src/main/snapshot/com.linkedin.entity.entities.snapshot.json b/gms/api/src/main/snapshot/com.linkedin.entity.entities.snapshot.json index 2ce05be51b..0cbec524f7 100644 --- a/gms/api/src/main/snapshot/com.linkedin.entity.entities.snapshot.json +++ b/gms/api/src/main/snapshot/com.linkedin.entity.entities.snapshot.json @@ -3651,7 +3651,7 @@ "Aspect" : { "name" : "glossaryTermInfo" } - }, "com.linkedin.common.Ownership", "com.linkedin.common.Status" ] + }, "com.linkedin.common.Ownership", "com.linkedin.common.Status", "com.linkedin.common.BrowsePaths" ] } }, "doc" : "The list of metadata aspects associated with the GlossaryTerm. Depending on the use case, this can either be all, or a selection, of supported aspects." diff --git a/gms/api/src/main/snapshot/com.linkedin.glossary.glossaryTerms.snapshot.json b/gms/api/src/main/snapshot/com.linkedin.glossary.glossaryTerms.snapshot.json index 25dc2fc35a..6b3503f77f 100644 --- a/gms/api/src/main/snapshot/com.linkedin.glossary.glossaryTerms.snapshot.json +++ b/gms/api/src/main/snapshot/com.linkedin.glossary.glossaryTerms.snapshot.json @@ -30,6 +30,28 @@ "doc" : "The entity (e.g. a service URN) which performs the change on behalf of the Actor and must be authorized to act as the Actor.", "optional" : true } ] + }, { + "type" : "record", + "name" : "BrowsePaths", + "namespace" : "com.linkedin.common", + "doc" : "Shared aspect containing Browse Paths to be indexed for an entity.", + "fields" : [ { + "name" : "paths", + "type" : { + "type" : "array", + "items" : "string" + }, + "doc" : "A list of valid browse paths for the entity.\n\nBrowse paths are expected to be backslash-separated strings. For example: 'prod/snowflake/datasetName'", + "Searchable" : { + "/*" : { + "fieldName" : "browsePaths", + "fieldType" : "BROWSE_PATH" + } + } + } ], + "Aspect" : { + "name" : "browsePaths" + } }, { "type" : "typeref", "name" : "GlossaryNodeUrn", @@ -306,7 +328,7 @@ "Aspect" : { "name" : "glossaryTermKey" } - }, "com.linkedin.glossary.GlossaryTermInfo", "com.linkedin.common.Ownership", "com.linkedin.common.Status" ] + }, "com.linkedin.glossary.GlossaryTermInfo", "com.linkedin.common.Ownership", "com.linkedin.common.Status", "com.linkedin.common.BrowsePaths" ] }, "com.linkedin.metadata.key.GlossaryTermKey", { "type" : "record", "name" : "AggregationMetadata", diff --git a/metadata-builders/src/main/java/com/linkedin/metadata/builders/search/GlossaryTermInfoIndexBuilder.java b/metadata-builders/src/main/java/com/linkedin/metadata/builders/search/GlossaryTermInfoIndexBuilder.java index d75891c23a..a5e3115921 100644 --- a/metadata-builders/src/main/java/com/linkedin/metadata/builders/search/GlossaryTermInfoIndexBuilder.java +++ b/metadata-builders/src/main/java/com/linkedin/metadata/builders/search/GlossaryTermInfoIndexBuilder.java @@ -32,7 +32,7 @@ public class GlossaryTermInfoIndexBuilder extends BaseIndexBuilder List[Union["GlossaryTermKeyClass", "GlossaryTermInfoClass", "OwnershipClass", "StatusClass"]]: + def aspects(self) -> List[Union["GlossaryTermKeyClass", "GlossaryTermInfoClass", "OwnershipClass", "StatusClass", "BrowsePathsClass"]]: """Getter: The list of metadata aspects associated with the GlossaryTerm. Depending on the use case, this can either be all, or a selection, of supported aspects.""" return self._inner_dict.get('aspects') # type: ignore @aspects.setter - def aspects(self, value: List[Union["GlossaryTermKeyClass", "GlossaryTermInfoClass", "OwnershipClass", "StatusClass"]]) -> None: + def aspects(self, value: List[Union["GlossaryTermKeyClass", "GlossaryTermInfoClass", "OwnershipClass", "StatusClass", "BrowsePathsClass"]]) -> None: """Setter: The list of metadata aspects associated with the GlossaryTerm. Depending on the use case, this can either be all, or a selection, of supported aspects.""" self._inner_dict['aspects'] = value diff --git a/metadata-ingestion/src/datahub/metadata/schemas/MetadataAuditEvent.avsc b/metadata-ingestion/src/datahub/metadata/schemas/MetadataAuditEvent.avsc index c25f6e5c3f..8ad368a6f4 100644 --- a/metadata-ingestion/src/datahub/metadata/schemas/MetadataAuditEvent.avsc +++ b/metadata-ingestion/src/datahub/metadata/schemas/MetadataAuditEvent.avsc @@ -4580,7 +4580,8 @@ } }, "com.linkedin.pegasus2avro.common.Ownership", - "com.linkedin.pegasus2avro.common.Status" + "com.linkedin.pegasus2avro.common.Status", + "com.linkedin.pegasus2avro.common.BrowsePaths" ] }, "doc": "The list of metadata aspects associated with the GlossaryTerm. Depending on the use case, this can either be all, or a selection, of supported aspects." diff --git a/metadata-ingestion/src/datahub/metadata/schemas/MetadataChangeEvent.avsc b/metadata-ingestion/src/datahub/metadata/schemas/MetadataChangeEvent.avsc index 9a1fc04edc..e507e31147 100644 --- a/metadata-ingestion/src/datahub/metadata/schemas/MetadataChangeEvent.avsc +++ b/metadata-ingestion/src/datahub/metadata/schemas/MetadataChangeEvent.avsc @@ -4579,7 +4579,8 @@ } }, "com.linkedin.pegasus2avro.common.Ownership", - "com.linkedin.pegasus2avro.common.Status" + "com.linkedin.pegasus2avro.common.Status", + "com.linkedin.pegasus2avro.common.BrowsePaths" ] }, "doc": "The list of metadata aspects associated with the GlossaryTerm. Depending on the use case, this can either be all, or a selection, of supported aspects." diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/utils/BrowsePathUtils.java b/metadata-io/src/main/java/com/linkedin/metadata/search/utils/BrowsePathUtils.java index 7582d83c5e..92b3d79b61 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/utils/BrowsePathUtils.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/utils/BrowsePathUtils.java @@ -6,6 +6,7 @@ import com.linkedin.common.urn.DashboardUrn; import com.linkedin.common.urn.DataFlowUrn; import com.linkedin.common.urn.DataJobUrn; import com.linkedin.common.urn.DatasetUrn; +import com.linkedin.common.urn.GlossaryTermUrn; import com.linkedin.common.urn.Urn; import com.linkedin.data.template.RecordTemplate; import com.linkedin.data.template.StringArray; @@ -20,11 +21,14 @@ import com.linkedin.metadata.aspect.DataJobAspect; import com.linkedin.metadata.aspect.DataJobAspectArray; import com.linkedin.metadata.aspect.DatasetAspect; import com.linkedin.metadata.aspect.DatasetAspectArray; +import com.linkedin.metadata.aspect.GlossaryTermAspect; +import com.linkedin.metadata.aspect.GlossaryTermAspectArray; import com.linkedin.metadata.builders.search.ChartIndexBuilder; import com.linkedin.metadata.builders.search.DashboardIndexBuilder; import com.linkedin.metadata.builders.search.DataFlowIndexBuilder; import com.linkedin.metadata.builders.search.DataJobIndexBuilder; import com.linkedin.metadata.builders.search.DatasetIndexBuilder; +import com.linkedin.metadata.builders.search.GlossaryTermInfoIndexBuilder; import com.linkedin.metadata.dao.utils.RecordUtils; import com.linkedin.metadata.snapshot.Snapshot; import java.net.URISyntaxException; @@ -59,6 +63,8 @@ public class BrowsePathUtils { return DataFlowIndexBuilder.buildBrowsePath(DataFlowUrn.createFromUrn(urn)); case "dataJob": return DataJobIndexBuilder.buildBrowsePath(DataJobUrn.createFromUrn(urn)); + case "glossaryTerm": + return GlossaryTermInfoIndexBuilder.buildBrowsePath(GlossaryTermUrn.createFromUrn(urn)); default: log.debug(String.format("Failed to generate default browse path for unknown entity type %s", urn.getEntityType())); return ""; @@ -85,6 +91,20 @@ public class BrowsePathUtils { aspects.add(DatasetAspect.create(defaultBrowsePaths)); } } + if (urn.getEntityType().equals("glossaryTerm")) { + final GlossaryTermAspectArray aspects = snapshot.getGlossaryTermSnapshot().getAspects(); + boolean hasBrowse = false; + if (browsePathEntity != null) { + final GlossaryTermAspectArray aspectsWithExistingBrowse = browsePathEntity.getValue().getGlossaryTermSnapshot().getAspects(); + hasBrowse = aspects.stream() + .filter(glossaryTermAspect -> glossaryTermAspect.isBrowsePaths()).findFirst().isPresent() + || aspectsWithExistingBrowse.stream() + .filter(glossaryTermAspect -> glossaryTermAspect.isBrowsePaths()).findFirst().isPresent(); + } + if (!hasBrowse) { + aspects.add(GlossaryTermAspect.create(defaultBrowsePaths)); + } + } if (urn.getEntityType().equals("chart")) { final ChartAspectArray aspects = snapshot.getChartSnapshot().getAspects(); boolean hasBrowse = false; diff --git a/metadata-models/src/main/pegasus/com/linkedin/metadata/aspect/GlossaryTermAspect.pdl b/metadata-models/src/main/pegasus/com/linkedin/metadata/aspect/GlossaryTermAspect.pdl index d4208bd8c1..f976698f14 100644 --- a/metadata-models/src/main/pegasus/com/linkedin/metadata/aspect/GlossaryTermAspect.pdl +++ b/metadata-models/src/main/pegasus/com/linkedin/metadata/aspect/GlossaryTermAspect.pdl @@ -4,8 +4,10 @@ import com.linkedin.glossary.GlossaryTermInfo import com.linkedin.metadata.key.GlossaryTermKey import com.linkedin.common.Ownership import com.linkedin.common.Status +import com.linkedin.common.BrowsePaths + /** * A union of all supported metadata aspects for a CorpUser */ -typeref GlossaryTermAspect = union[GlossaryTermKey, GlossaryTermInfo, Ownership, Status] \ No newline at end of file +typeref GlossaryTermAspect = union[GlossaryTermKey, GlossaryTermInfo, Ownership, Status,BrowsePaths] \ No newline at end of file