Skip to content

Commit

Permalink
add support for structured property filters, not full support for dat…
Browse files Browse the repository at this point in the history
…e filters yet
  • Loading branch information
chriscollins3456 committed Dec 11, 2024
1 parent a72e668 commit 063f50e
Show file tree
Hide file tree
Showing 35 changed files with 706 additions and 207 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import com.linkedin.datahub.graphql.generated.EntityPath;
import com.linkedin.datahub.graphql.generated.EntityRelationship;
import com.linkedin.datahub.graphql.generated.EntityRelationshipLegacy;
import com.linkedin.datahub.graphql.generated.FacetMetadata;
import com.linkedin.datahub.graphql.generated.ForeignKeyConstraint;
import com.linkedin.datahub.graphql.generated.FormActorAssignment;
import com.linkedin.datahub.graphql.generated.FreshnessContract;
Expand Down Expand Up @@ -1474,6 +1475,19 @@ private void configureGenericEntityResolvers(final RuntimeWiring.Builder builder
"entity",
new EntityTypeResolver(
entityTypes, (env) -> ((BrowsePathEntry) env.getSource()).getEntity())))
.type(
"FacetMetadata",
typeWiring ->
typeWiring.dataFetcher(
"entity",
new EntityTypeResolver(
entityTypes,
(env) -> {
FacetMetadata facetMetadata = env.getSource();
return facetMetadata.getEntity() != null
? facetMetadata.getEntity()
: null;
})))
.type(
"LineageRelationship",
typeWiring ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,17 @@ public CompletableFuture<AggregateResults> get(DataFetchingEnvironment environme

final Filter inputFilter = ResolverUtils.buildFilter(null, input.getOrFilters());

final SearchFlags searchFlags = mapInputFlags(context, input.getSearchFlags());
final SearchFlags searchFlags =
input.getSearchFlags() != null
? mapInputFlags(context, input.getSearchFlags())
: new SearchFlags();

final List<String> facets =
input.getFacets() != null && input.getFacets().size() > 0 ? input.getFacets() : null;

// do not include default facets if we're requesting any facets specifically
searchFlags.setIncludeDefaultFacets(facets == null || facets.size() <= 0);

List<String> finalEntities =
maybeResolvedView != null
? SearchUtils.intersectEntityTypes(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@

import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;
import static com.linkedin.datahub.graphql.resolvers.search.SearchUtils.*;
import static com.linkedin.datahub.graphql.resolvers.search.SearchUtils.getEntityNames;

import com.google.common.collect.ImmutableList;
import com.linkedin.common.urn.UrnUtils;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.concurrency.GraphQLConcurrencyUtils;
import com.linkedin.datahub.graphql.generated.EntityType;
import com.linkedin.datahub.graphql.generated.SearchAcrossEntitiesInput;
import com.linkedin.datahub.graphql.generated.SearchResults;
import com.linkedin.datahub.graphql.resolvers.ResolverUtils;
import com.linkedin.datahub.graphql.types.mappers.UrnSearchResultsMapper;
import com.linkedin.entity.client.EntityClient;
import com.linkedin.metadata.query.SearchFlags;
import com.linkedin.metadata.query.filter.Condition;
import com.linkedin.metadata.query.filter.ConjunctiveCriterion;
import com.linkedin.metadata.query.filter.ConjunctiveCriterionArray;
import com.linkedin.metadata.query.filter.CriterionArray;
import com.linkedin.metadata.query.filter.Filter;
import com.linkedin.metadata.query.filter.SortCriterion;
import com.linkedin.metadata.search.SearchResult;
import com.linkedin.metadata.service.FormService;
import com.linkedin.metadata.service.ViewService;
import com.linkedin.metadata.utils.CriterionUtils;
import com.linkedin.view.DataHubViewInfo;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
Expand Down Expand Up @@ -64,24 +74,7 @@ public CompletableFuture<SearchResults> get(DataFetchingEnvironment environment)
ResolverUtils.buildFilter(input.getFilters(), input.getOrFilters());

SearchFlags searchFlags = mapInputFlags(context, input.getSearchFlags());
List<SortCriterion> sortCriteria;
if (input.getSortInput() != null) {
if (input.getSortInput().getSortCriteria() != null) {
sortCriteria =
input.getSortInput().getSortCriteria().stream()
.map(SearchUtils::mapSortCriterion)
.collect(Collectors.toList());
} else {
sortCriteria =
input.getSortInput().getSortCriterion() != null
? Collections.singletonList(
mapSortCriterion(input.getSortInput().getSortCriterion()))
: Collections.emptyList();
}

} else {
sortCriteria = Collections.emptyList();
}
List<SortCriterion> sortCriteria = SearchUtils.getSortCriteria(input.getSortInput());

try {
log.debug(
Expand All @@ -101,6 +94,14 @@ public CompletableFuture<SearchResults> get(DataFetchingEnvironment environment)
return SearchUtils.createEmptySearchResults(start, count);
}

boolean shouldIncludeStructuredPropertyFacets =
input.getSearchFlags() != null
&& input.getSearchFlags().getIncludeStructuredPropertyFacets() != null
? input.getSearchFlags().getIncludeStructuredPropertyFacets()
: false;
List<String> structuredPropertyFacets =
shouldIncludeStructuredPropertyFacets ? getStructuredPropertyFacets(context) : null;

return UrnSearchResultsMapper.map(
context,
_entityClient.searchAcrossEntities(
Expand All @@ -113,7 +114,8 @@ public CompletableFuture<SearchResults> get(DataFetchingEnvironment environment)
: baseFilter,
start,
count,
sortCriteria));
sortCriteria,
structuredPropertyFacets));
} catch (Exception e) {
log.error(
"Failed to execute search for multiple entities: entity types {}, query {}, filters: {}, start: {}, count: {}",
Expand All @@ -133,4 +135,45 @@ public CompletableFuture<SearchResults> get(DataFetchingEnvironment environment)
this.getClass().getSimpleName(),
"get");
}

private List<String> getStructuredPropertyFacets(final QueryContext context) {
try {
SearchFlags searchFlags = new SearchFlags().setSkipCache(true);
SearchResult result =
_entityClient.searchAcrossEntities(
context.getOperationContext().withSearchFlags(flags -> searchFlags),
getEntityNames(ImmutableList.of(EntityType.STRUCTURED_PROPERTY)),
"*",
createStructuredPropertyFilter(),
0,
100,
Collections.emptyList(),
null);
return result.getEntities().stream()
.map(entity -> String.format("structuredProperties.%s", entity.getEntity().getId()))
.collect(Collectors.toList());
} catch (Exception e) {
log.error("Failed to get structured property facets to filter on", e);
return Collections.emptyList();
}
}

private Filter createStructuredPropertyFilter() {
return new Filter()
.setOr(
new ConjunctiveCriterionArray(
ImmutableList.of(
new ConjunctiveCriterion()
.setAnd(
new CriterionArray(
ImmutableList.of(
CriterionUtils.buildCriterion(
"filterStatus", Condition.EQUAL, "ENABLED")))),
new ConjunctiveCriterion()
.setAnd(
new CriterionArray(
ImmutableList.of(
CriterionUtils.buildCriterion(
"showInSearchFilters", Condition.EQUAL, "true")))))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.linkedin.datahub.graphql.generated.EntityType;
import com.linkedin.datahub.graphql.generated.FacetFilterInput;
import com.linkedin.datahub.graphql.generated.SearchResults;
import com.linkedin.datahub.graphql.generated.SearchSortInput;
import com.linkedin.datahub.graphql.types.common.mappers.SearchFlagsInputMapper;
import com.linkedin.datahub.graphql.types.entitytype.EntityTypeMapper;
import com.linkedin.metadata.query.SearchFlags;
Expand Down Expand Up @@ -326,4 +327,25 @@ public static SearchResults createEmptySearchResults(final int start, final int
result.setFacets(new ArrayList<>());
return result;
}

public static List<SortCriterion> getSortCriteria(@Nullable final SearchSortInput sortInput) {
List<SortCriterion> sortCriteria;
if (sortInput != null) {
if (sortInput.getSortCriteria() != null) {
sortCriteria =
sortInput.getSortCriteria().stream()
.map(SearchUtils::mapSortCriterion)
.collect(Collectors.toList());
} else {
sortCriteria =
sortInput.getSortCriterion() != null
? Collections.singletonList(mapSortCriterion(sortInput.getSortCriterion()))
: new ArrayList<>();
}
} else {
sortCriteria = new ArrayList<>();
}

return sortCriteria;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ public static FacetMetadata mapFacet(
aggregationFacets.stream()
.map(facet -> facet.equals("entity") || facet.contains("_entityType"))
.collect(Collectors.toList());
if (aggregationMetadata.getEntity() != null) {
facetMetadata.setEntity(UrnToEntityMapper.map(context, aggregationMetadata.getEntity()));
}
facetMetadata.setField(aggregationMetadata.getName());
facetMetadata.setDisplayName(
Optional.ofNullable(aggregationMetadata.getDisplayName())
Expand Down
10 changes: 10 additions & 0 deletions datahub-graphql-core/src/main/resources/search.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ input SearchFlags {
fields to include for custom Highlighting
"""
customHighlightingFields: [String!]

"""
Whether or not to fetch and request for structured property facets when doing a search
"""
includeStructuredPropertyFacets: Boolean
}

"""
Expand Down Expand Up @@ -872,6 +877,11 @@ type FacetMetadata {
"""
displayName: String

"""
Entity corresponding to the facet
"""
entity: Entity

"""
Aggregated search result counts by value of the field
"""
Expand Down
Loading

0 comments on commit 063f50e

Please sign in to comment.