From 79968522e274c5c984f06725c078f53f867ec909 Mon Sep 17 00:00:00 2001 From: RyanHolstien Date: Tue, 25 Jun 2024 11:20:58 -0500 Subject: [PATCH 1/7] feat(search): support sorting on multiple fields --- .../analytics/resolver/GetChartsResolver.java | 7 +-- .../GetMetadataAnalyticsResolver.java | 3 +- .../resolvers/auth/DebugAccessResolver.java | 3 +- .../auth/ListAccessTokensResolver.java | 11 +++-- .../container/ContainerEntitiesResolver.java | 3 +- .../domain/DomainEntitiesResolver.java | 3 +- .../resolvers/domain/ListDomainsResolver.java | 8 ++-- .../resolvers/group/ListGroupsResolver.java | 8 ++-- .../incident/EntityIncidentsResolver.java | 9 ++-- ...estionSourceExecutionRequestsResolver.java | 8 ++-- .../ingest/secret/ListSecretsResolver.java | 8 ++-- .../resolvers/jobs/DataJobRunsResolver.java | 9 ++-- .../resolvers/jobs/EntityRunsResolver.java | 9 ++-- .../ownership/ListOwnershipTypesResolver.java | 2 +- .../resolvers/post/ListPostsResolver.java | 13 +++-- .../resolvers/query/ListQueriesResolver.java | 7 +-- .../AggregateAcrossEntitiesResolver.java | 3 +- .../search/GetQuickFiltersResolver.java | 3 +- .../search/SearchAcrossEntitiesResolver.java | 26 ++++++++-- .../resolvers/search/SearchResolver.java | 3 +- .../view/ListGlobalViewsResolver.java | 2 +- .../resolvers/view/ListMyViewsResolver.java | 2 +- .../src/main/resources/search.graphql | 7 ++- .../auth/ListAccessTokensResolverTest.java | 4 +- .../ContainerEntitiesResolverTest.java | 2 +- .../domain/DomainEntitiesResolverTest.java | 2 +- .../domain/ListDomainsResolverTest.java | 15 +++--- .../incident/EntityIncidentsResolverTest.java | 3 +- ...onSourceExecutionRequestsResolverTest.java | 4 +- .../secret/ListSecretsResolverTest.java | 6 +-- .../query/ListQueriesResolverTest.java | 7 +-- .../AggregateAcrossEntitiesResolverTest.java | 6 +-- .../search/GetQuickFiltersResolverTest.java | 5 +- .../SearchAcrossEntitiesResolverTest.java | 4 +- .../resolvers/search/SearchResolverTest.java | 12 +++-- .../metadata/aspect/GraphRetriever.java | 4 +- .../java/com/datahub/util/RecordUtils.java | 8 ++++ .../metadata/client/JavaEntityClient.java | 39 ++++++++------- .../graph/dgraph/DgraphGraphService.java | 2 +- .../graph/elastic/ESGraphQueryDAO.java | 8 ++-- .../elastic/ElasticSearchGraphService.java | 4 +- .../graph/neo4j/Neo4jGraphService.java | 2 +- .../metadata/search/LineageSearchService.java | 26 +++++----- .../metadata/search/SearchService.java | 28 +++++------ .../search/SearchServiceSearchRetriever.java | 2 +- .../search/cache/CachedSearchResult.java | 23 +++++++++ .../client/CachingEntitySearchService.java | 37 +++++++------- .../elasticsearch/ElasticSearchService.java | 40 ++++++++-------- .../elasticsearch/query/ESSearchDAO.java | 34 +++++-------- .../query/request/SearchRequestHandler.java | 14 +++--- .../metadata/search/utils/ESUtils.java | 29 +++++------ .../ElasticSearchTimeseriesAspectService.java | 8 ++-- .../fixtures/SampleDataFixtureTestBase.java | 6 +-- .../v2/delegates/EntityApiDelegateImpl.java | 21 +++++--- .../controller/GenericEntitiesController.java | 17 +++++-- .../elastic/OperationsController.java | 8 ++-- .../v2/controller/TimeseriesController.java | 4 +- ...com.linkedin.entity.entities.restspec.json | 28 +++++++++++ ...com.linkedin.entity.entities.snapshot.json | 28 +++++++++++ .../linkedin/entity/client/EntityClient.java | 20 ++++---- .../entity/client/RestliEntityClient.java | 45 +++++++++++------ .../restli-servlet-impl/build.gradle | 3 ++ .../resources/entity/EntityResource.java | 48 ++++++++++++++++--- .../resources/restli/RestliConstants.java | 1 + .../mock/MockTimeseriesAspectService.java | 2 +- .../metadata/search/EntitySearchService.java | 22 ++++----- .../timeseries/TimeseriesAspectService.java | 2 +- 67 files changed, 500 insertions(+), 290 deletions(-) create mode 100644 metadata-io/src/main/java/com/linkedin/metadata/search/cache/CachedSearchResult.java diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetChartsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetChartsResolver.java index 767c9b4d4e71b..4847aea224ccd 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetChartsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetChartsResolver.java @@ -159,9 +159,10 @@ private SearchResult searchForNewUsers(@Nonnull final OperationContext opContext .setValue( String.valueOf( trailingMonthDateRange.getStart())))))))), - new SortCriterion() - .setField(CORP_USER_STATUS_LAST_MODIFIED_FIELD_NAME) - .setOrder(SortOrder.DESCENDING), + Collections.singletonList( + new SortCriterion() + .setField(CORP_USER_STATUS_LAST_MODIFIED_FIELD_NAME) + .setOrder(SortOrder.DESCENDING)), 0, 100); } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetMetadataAnalyticsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetMetadataAnalyticsResolver.java index 01f2e6c8462e3..6045b1e726c7a 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetMetadataAnalyticsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetMetadataAnalyticsResolver.java @@ -77,7 +77,8 @@ private List getCharts(MetadataAnalyticsInput input, OperationCo } SearchResult searchResult = - _entityClient.searchAcrossEntities(opContext, entities, query, filter, 0, 0, null, null); + _entityClient.searchAcrossEntities( + opContext, entities, query, filter, 0, 0, Collections.emptyList(), null); List aggregationMetadataList = searchResult.getMetadata().getAggregations(); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/auth/DebugAccessResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/auth/DebugAccessResolver.java index 44604e92c35de..8372b6b5126a3 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/auth/DebugAccessResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/auth/DebugAccessResolver.java @@ -33,6 +33,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -181,7 +182,7 @@ private Set getPoliciesFor( Constants.POLICY_ENTITY_NAME, "", buildFilterToGetPolicies(user, groups, roles), - sortCriterion, + Collections.singletonList(sortCriterion), 0, 10000) .getEntities() diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/auth/ListAccessTokensResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/auth/ListAccessTokensResolver.java index dc57ed3c673c1..e0ecebbbc7bc2 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/auth/ListAccessTokensResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/auth/ListAccessTokensResolver.java @@ -59,10 +59,11 @@ public CompletableFuture get(DataFetchingEnvironment envi if (AuthorizationUtils.canManageTokens(context) || isListingSelfTokens(filters, context)) { try { - final SortCriterion sortCriterion = - new SortCriterion() - .setField(EXPIRES_AT_FIELD_NAME) - .setOrder(SortOrder.DESCENDING); + final List sortCriteria = + Collections.singletonList( + new SortCriterion() + .setField(EXPIRES_AT_FIELD_NAME) + .setOrder(SortOrder.DESCENDING)); final SearchResult searchResult = _entityClient.search( context @@ -74,7 +75,7 @@ public CompletableFuture get(DataFetchingEnvironment envi filters, Collections.emptyList(), context.getOperationContext().getAspectRetriever()), - sortCriterion, + sortCriteria, start, count); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/container/ContainerEntitiesResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/container/ContainerEntitiesResolver.java index 15927eef236ca..5a3207633c07c 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/container/ContainerEntitiesResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/container/ContainerEntitiesResolver.java @@ -19,6 +19,7 @@ import com.linkedin.metadata.query.filter.Filter; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import lombok.extern.slf4j.Slf4j; @@ -92,7 +93,7 @@ public CompletableFuture get(final DataFetchingEnvironment enviro new CriterionArray(ImmutableList.of(filterCriterion))))), start, count, - null, + Collections.emptyList(), null)); } catch (Exception e) { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/DomainEntitiesResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/DomainEntitiesResolver.java index 75796f637525e..6a880503802cb 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/DomainEntitiesResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/DomainEntitiesResolver.java @@ -19,6 +19,7 @@ import com.linkedin.metadata.query.filter.Filter; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.util.Collections; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -98,7 +99,7 @@ public CompletableFuture get(final DataFetchingEnvironment enviro new ConjunctiveCriterion().setAnd(criteria))), start, count, - null, + Collections.emptyList(), null)); } catch (Exception e) { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/ListDomainsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/ListDomainsResolver.java index 0c16470c642b7..e6d4238bc7054 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/ListDomainsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/ListDomainsResolver.java @@ -22,6 +22,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -66,9 +67,10 @@ public CompletableFuture get(final DataFetchingEnvironment en Constants.DOMAIN_ENTITY_NAME, query, filter, - new SortCriterion() - .setField(DOMAIN_CREATED_TIME_INDEX_FIELD_NAME) - .setOrder(SortOrder.DESCENDING), + Collections.singletonList( + new SortCriterion() + .setField(DOMAIN_CREATED_TIME_INDEX_FIELD_NAME) + .setOrder(SortOrder.DESCENDING)), start, count); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/group/ListGroupsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/group/ListGroupsResolver.java index fce404a6baa16..0632af68998dc 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/group/ListGroupsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/group/ListGroupsResolver.java @@ -21,6 +21,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -64,9 +65,10 @@ public CompletableFuture get(final DataFetchingEnvironment env CORP_GROUP_ENTITY_NAME, query, null, - new SortCriterion() - .setField(CORP_GROUP_CREATED_TIME_INDEX_FIELD_NAME) - .setOrder(SortOrder.DESCENDING), + Collections.singletonList( + new SortCriterion() + .setField(CORP_GROUP_CREATED_TIME_INDEX_FIELD_NAME) + .setOrder(SortOrder.DESCENDING)), start, count); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/incident/EntityIncidentsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/incident/EntityIncidentsResolver.java index 2d4b24243073a..d79634c27d881 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/incident/EntityIncidentsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/incident/EntityIncidentsResolver.java @@ -21,6 +21,7 @@ import graphql.schema.DataFetchingEnvironment; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -60,13 +61,13 @@ public CompletableFuture get(DataFetchingEnvironment envi // Index! // We use the search index so that we can easily sort by the last updated time. final Filter filter = buildIncidentsEntityFilter(entityUrn, maybeState); - final SortCriterion sortCriterion = buildIncidentsSortCriterion(); + final List sortCriteria = buildIncidentsSortCriteria(); final SearchResult searchResult = _entityClient.filter( context.getOperationContext(), Constants.INCIDENT_ENTITY_NAME, filter, - sortCriterion, + sortCriteria, start, count); @@ -118,10 +119,10 @@ private Filter buildIncidentsEntityFilter( return QueryUtils.newFilter(criterionMap); } - private SortCriterion buildIncidentsSortCriterion() { + private List buildIncidentsSortCriteria() { final SortCriterion sortCriterion = new SortCriterion(); sortCriterion.setField(CREATED_TIME_SEARCH_INDEX_FIELD_NAME); sortCriterion.setOrder(SortOrder.DESCENDING); - return sortCriterion; + return Collections.singletonList(sortCriterion); } } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ingest/execution/IngestionSourceExecutionRequestsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ingest/execution/IngestionSourceExecutionRequestsResolver.java index 4a3b75deddc45..a4c2ab42227d9 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ingest/execution/IngestionSourceExecutionRequestsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ingest/execution/IngestionSourceExecutionRequestsResolver.java @@ -23,6 +23,7 @@ import com.linkedin.metadata.search.SearchResult; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.util.Collections; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -76,9 +77,10 @@ public CompletableFuture get( new ConjunctiveCriterion() .setAnd( new CriterionArray(ImmutableList.of(filterCriterion))))), - new SortCriterion() - .setField(REQUEST_TIME_MS_FIELD_NAME) - .setOrder(SortOrder.DESCENDING), + Collections.singletonList( + new SortCriterion() + .setField(REQUEST_TIME_MS_FIELD_NAME) + .setOrder(SortOrder.DESCENDING)), start, count); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ingest/secret/ListSecretsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ingest/secret/ListSecretsResolver.java index 106a2d0d1e18e..bf8d7c800ccae 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ingest/secret/ListSecretsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ingest/secret/ListSecretsResolver.java @@ -26,6 +26,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -73,9 +74,10 @@ public CompletableFuture get(final DataFetchingEnvironment en Constants.SECRETS_ENTITY_NAME, query, null, - new SortCriterion() - .setField(DOMAIN_CREATED_TIME_INDEX_FIELD_NAME) - .setOrder(SortOrder.DESCENDING), + Collections.singletonList( + new SortCriterion() + .setField(DOMAIN_CREATED_TIME_INDEX_FIELD_NAME) + .setOrder(SortOrder.DESCENDING)), start, count); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/jobs/DataJobRunsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/jobs/DataJobRunsResolver.java index 591712ef3f55b..09039e530631d 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/jobs/DataJobRunsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/jobs/DataJobRunsResolver.java @@ -26,6 +26,7 @@ import graphql.schema.DataFetchingEnvironment; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -61,13 +62,13 @@ public CompletableFuture get(DataFetchingEnvironment // Index! // We use the search index so that we can easily sort by the last updated time. final Filter filter = buildTaskRunsEntityFilter(entityUrn); - final SortCriterion sortCriterion = buildTaskRunsSortCriterion(); + final List sortCriteria = buildTaskRunsSortCriteria(); final SearchResult gmsResult = _entityClient.filter( context.getOperationContext(), Constants.DATA_PROCESS_INSTANCE_ENTITY_NAME, filter, - sortCriterion, + sortCriteria, start, count); final List dataProcessInstanceUrns = @@ -123,10 +124,10 @@ private Filter buildTaskRunsEntityFilter(final String entityUrn) { return filter; } - private SortCriterion buildTaskRunsSortCriterion() { + private List buildTaskRunsSortCriteria() { final SortCriterion sortCriterion = new SortCriterion(); sortCriterion.setField(CREATED_TIME_SEARCH_INDEX_FIELD_NAME); sortCriterion.setOrder(SortOrder.DESCENDING); - return sortCriterion; + return Collections.singletonList(sortCriterion); } } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/jobs/EntityRunsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/jobs/EntityRunsResolver.java index 163fc30fb6e6c..82c5b73d87152 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/jobs/EntityRunsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/jobs/EntityRunsResolver.java @@ -27,6 +27,7 @@ import graphql.schema.DataFetchingEnvironment; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -67,13 +68,13 @@ public CompletableFuture get(DataFetchingEnvironment // Index! // We use the search index so that we can easily sort by the last updated time. final Filter filter = buildTaskRunsEntityFilter(entityUrn, direction); - final SortCriterion sortCriterion = buildTaskRunsSortCriterion(); + final List sortCriteria = buildTaskRunsSortCriteria(); final SearchResult gmsResult = _entityClient.filter( context.getOperationContext(), Constants.DATA_PROCESS_INSTANCE_ENTITY_NAME, filter, - sortCriterion, + sortCriteria, start, count); final List dataProcessInstanceUrns = @@ -133,10 +134,10 @@ private Filter buildTaskRunsEntityFilter( return filter; } - private SortCriterion buildTaskRunsSortCriterion() { + private List buildTaskRunsSortCriteria() { final SortCriterion sortCriterion = new SortCriterion(); sortCriterion.setField(CREATED_TIME_SEARCH_INDEX_FIELD_NAME); sortCriterion.setOrder(SortOrder.DESCENDING); - return sortCriterion; + return Collections.singletonList(sortCriterion); } } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ownership/ListOwnershipTypesResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ownership/ListOwnershipTypesResolver.java index 9f6951e44dd73..da0d5dd07a94f 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ownership/ListOwnershipTypesResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/ownership/ListOwnershipTypesResolver.java @@ -67,7 +67,7 @@ public CompletableFuture get(DataFetchingEnvironment e filters, Collections.emptyList(), context.getOperationContext().getAspectRetriever()), - DEFAULT_SORT_CRITERION, + Collections.singletonList(DEFAULT_SORT_CRITERION), start, count); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/post/ListPostsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/post/ListPostsResolver.java index 12e4047c2dc4e..dc7797882371b 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/post/ListPostsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/post/ListPostsResolver.java @@ -18,7 +18,9 @@ import com.linkedin.metadata.search.SearchResult; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -49,10 +51,11 @@ public CompletableFuture get(final DataFetchingEnvironment envi return GraphQLConcurrencyUtils.supplyAsync( () -> { try { - final SortCriterion sortCriterion = - new SortCriterion() - .setField(LAST_MODIFIED_FIELD_NAME) - .setOrder(SortOrder.DESCENDING); + final List sortCriteria = + Collections.singletonList( + new SortCriterion() + .setField(LAST_MODIFIED_FIELD_NAME) + .setOrder(SortOrder.DESCENDING)); // First, get all Post Urns. final SearchResult gmsResult = @@ -61,7 +64,7 @@ public CompletableFuture get(final DataFetchingEnvironment envi POST_ENTITY_NAME, query, null, - sortCriterion, + sortCriteria, start, count); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/query/ListQueriesResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/query/ListQueriesResolver.java index 95be3a68e895c..aa411f019a4c0 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/query/ListQueriesResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/query/ListQueriesResolver.java @@ -61,8 +61,9 @@ public CompletableFuture get(final DataFetchingEnvironment en return GraphQLConcurrencyUtils.supplyAsync( () -> { try { - final SortCriterion sortCriterion = - new SortCriterion().setField(CREATED_AT_FIELD).setOrder(SortOrder.DESCENDING); + final List sortCriteria = + Collections.singletonList( + new SortCriterion().setField(CREATED_AT_FIELD).setOrder(SortOrder.DESCENDING)); // First, get all Query Urns. final SearchResult gmsResult = @@ -74,7 +75,7 @@ public CompletableFuture get(final DataFetchingEnvironment en QUERY_ENTITY_NAME, query, buildFilters(input, context.getOperationContext().getAspectRetriever()), - sortCriterion, + sortCriteria, start, count); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/AggregateAcrossEntitiesResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/AggregateAcrossEntitiesResolver.java index 04a72b14eeb02..19bccaf265086 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/AggregateAcrossEntitiesResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/AggregateAcrossEntitiesResolver.java @@ -22,6 +22,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -94,7 +95,7 @@ public CompletableFuture get(DataFetchingEnvironment environme : inputFilter, 0, 0, // 0 entity count because we don't want resolved entities - null, + Collections.emptyList(), facets)); } catch (Exception e) { log.error( diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/GetQuickFiltersResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/GetQuickFiltersResolver.java index a61d9111321ca..b07e3fa912641 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/GetQuickFiltersResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/GetQuickFiltersResolver.java @@ -25,6 +25,7 @@ import graphql.schema.DataFetchingEnvironment; import io.datahubproject.metadata.context.OperationContext; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Optional; @@ -107,7 +108,7 @@ private SearchResult getSearchResults( : null, 0, 0, - null, + Collections.emptyList(), null); } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolver.java index 287e339ddee50..0dbed92b7d58e 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolver.java @@ -18,8 +18,10 @@ import com.linkedin.view.DataHubViewInfo; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -65,10 +67,24 @@ public CompletableFuture get(DataFetchingEnvironment environment) context.getOperationContext().getAspectRetriever()); SearchFlags searchFlags = mapInputFlags(context, input.getSearchFlags()); - SortCriterion sortCriterion = - input.getSortInput() != null - ? mapSortCriterion(input.getSortInput().getSortCriterion()) - : null; + List 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(); + } try { log.debug( @@ -100,7 +116,7 @@ public CompletableFuture get(DataFetchingEnvironment environment) : baseFilter, start, count, - sortCriterion)); + sortCriteria)); } catch (Exception e) { log.error( "Failed to execute search for multiple entities: entity types {}, query {}, filters: {}, start: {}, count: {}", diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/SearchResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/SearchResolver.java index 5fb2f8f14b293..7a48e305dbfe4 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/SearchResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/SearchResolver.java @@ -20,6 +20,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import io.opentelemetry.extension.annotations.WithSpan; +import java.util.Collections; import java.util.concurrent.CompletableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -89,7 +90,7 @@ public CompletableFuture get(DataFetchingEnvironment environment) input.getFilters(), input.getOrFilters(), context.getOperationContext().getAspectRetriever()), - null, + Collections.emptyList(), start, count)); } catch (Exception e) { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/view/ListGlobalViewsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/view/ListGlobalViewsResolver.java index 952e55ca117f2..265f4d5f5d56e 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/view/ListGlobalViewsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/view/ListGlobalViewsResolver.java @@ -74,7 +74,7 @@ public CompletableFuture get(final DataFetchingEnvironment envi Constants.DATAHUB_VIEW_ENTITY_NAME, query, buildFilters(context.getOperationContext().getAspectRetriever()), - DEFAULT_SORT_CRITERION, + Collections.singletonList(DEFAULT_SORT_CRITERION), start, count); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/view/ListMyViewsResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/view/ListMyViewsResolver.java index 32eb0e46bb616..abfdeb2d60869 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/view/ListMyViewsResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/view/ListMyViewsResolver.java @@ -79,7 +79,7 @@ public CompletableFuture get(final DataFetchingEnvironment envi viewType, context.getActorUrn(), context.getOperationContext().getAspectRetriever()), - DEFAULT_SORT_CRITERION, + Collections.singletonList(DEFAULT_SORT_CRITERION), start, count); diff --git a/datahub-graphql-core/src/main/resources/search.graphql b/datahub-graphql-core/src/main/resources/search.graphql index c7b5e61e9831c..09a7217073527 100644 --- a/datahub-graphql-core/src/main/resources/search.graphql +++ b/datahub-graphql-core/src/main/resources/search.graphql @@ -1372,7 +1372,12 @@ input SearchSortInput { """ A criterion to sort search results on """ - sortCriterion: SortCriterion! + sortCriterion: SortCriterion @deprecated(reason: "Use sortCriteria instead") + + """ + A list of values to sort search results on + """ + sortCriteria: [SortCriterion!] } """ diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/auth/ListAccessTokensResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/auth/ListAccessTokensResolverTest.java index 6c876226a45e6..020f74475ea60 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/auth/ListAccessTokensResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/auth/ListAccessTokensResolverTest.java @@ -12,11 +12,11 @@ import com.linkedin.datahub.graphql.generated.ListAccessTokenResult; import com.linkedin.entity.client.EntityClient; import com.linkedin.metadata.Constants; -import com.linkedin.metadata.query.filter.SortCriterion; import com.linkedin.metadata.search.SearchEntityArray; import com.linkedin.metadata.search.SearchResult; import graphql.schema.DataFetchingEnvironment; import java.util.Collections; +import java.util.List; import org.mockito.Mockito; import org.testng.annotations.Test; @@ -47,7 +47,7 @@ public void testGetSuccess() throws Exception { Mockito.eq(Constants.ACCESS_TOKEN_ENTITY_NAME), Mockito.eq(""), Mockito.eq(buildFilter(filters, Collections.emptyList(), null)), - Mockito.any(SortCriterion.class), + Mockito.any(List.class), Mockito.eq(input.getStart()), Mockito.eq(input.getCount()))) .thenReturn( diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/container/ContainerEntitiesResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/container/ContainerEntitiesResolverTest.java index c63c9bccab68b..48732727762ee 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/container/ContainerEntitiesResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/container/ContainerEntitiesResolverTest.java @@ -62,7 +62,7 @@ public void testGetSuccess() throws Exception { new CriterionArray(ImmutableList.of(filterCriterion)))))), Mockito.eq(0), Mockito.eq(20), - Mockito.eq(null), + Mockito.eq(Collections.emptyList()), Mockito.eq(null))) .thenReturn( new SearchResult() diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/DomainEntitiesResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/DomainEntitiesResolverTest.java index f970f9e2ea431..ad5d7f1ef6b06 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/DomainEntitiesResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/DomainEntitiesResolverTest.java @@ -68,7 +68,7 @@ public void testGetSuccess() throws Exception { new CriterionArray(ImmutableList.of(filterCriterion)))))), Mockito.eq(0), Mockito.eq(20), - Mockito.eq(null), + Mockito.eq(Collections.emptyList()), Mockito.eq(null))) .thenReturn( new SearchResult() diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/ListDomainsResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/ListDomainsResolverTest.java index 53a16ed5f6cc8..c3b1a8c564855 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/ListDomainsResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/ListDomainsResolverTest.java @@ -20,6 +20,7 @@ import com.linkedin.metadata.search.SearchResult; import com.linkedin.r2.RemoteInvocationException; import graphql.schema.DataFetchingEnvironment; +import java.util.Collections; import java.util.concurrent.CompletionException; import org.mockito.Mockito; import org.testng.annotations.Test; @@ -47,9 +48,10 @@ public void testGetSuccess() throws Exception { Mockito.eq(""), Mockito.eq(DomainUtils.buildParentDomainFilter(TEST_PARENT_DOMAIN_URN)), Mockito.eq( - new SortCriterion() - .setField(DOMAIN_CREATED_TIME_INDEX_FIELD_NAME) - .setOrder(SortOrder.DESCENDING)), + Collections.singletonList( + new SortCriterion() + .setField(DOMAIN_CREATED_TIME_INDEX_FIELD_NAME) + .setOrder(SortOrder.DESCENDING))), Mockito.eq(0), Mockito.eq(20))) .thenReturn( @@ -90,9 +92,10 @@ public void testGetSuccessNoParentDomain() throws Exception { Mockito.eq(""), Mockito.eq(DomainUtils.buildParentDomainFilter(null)), Mockito.eq( - new SortCriterion() - .setField(DOMAIN_CREATED_TIME_INDEX_FIELD_NAME) - .setOrder(SortOrder.DESCENDING)), + Collections.singletonList( + new SortCriterion() + .setField(DOMAIN_CREATED_TIME_INDEX_FIELD_NAME) + .setOrder(SortOrder.DESCENDING))), Mockito.eq(0), Mockito.eq(20))) .thenReturn( diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/incident/EntityIncidentsResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/incident/EntityIncidentsResolverTest.java index 4be7eeba1d018..4750143b8add8 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/incident/EntityIncidentsResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/incident/EntityIncidentsResolverTest.java @@ -37,6 +37,7 @@ import com.linkedin.metadata.search.utils.QueryUtils; import graphql.schema.DataFetchingEnvironment; import io.datahubproject.metadata.context.OperationContext; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.mockito.Mockito; @@ -92,7 +93,7 @@ public void testGetSuccess() throws Exception { Mockito.any(), Mockito.eq(Constants.INCIDENT_ENTITY_NAME), Mockito.eq(expectedFilter), - Mockito.eq(expectedSort), + Mockito.eq(Collections.singletonList(expectedSort)), Mockito.eq(0), Mockito.eq(10))) .thenReturn( diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/ingest/execution/IngestionSourceExecutionRequestsResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/ingest/execution/IngestionSourceExecutionRequestsResolverTest.java index c96dfe89adc5e..fe4fe00454a26 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/ingest/execution/IngestionSourceExecutionRequestsResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/ingest/execution/IngestionSourceExecutionRequestsResolverTest.java @@ -22,7 +22,6 @@ import com.linkedin.execution.ExecutionRequestResult; import com.linkedin.metadata.Constants; import com.linkedin.metadata.query.filter.Filter; -import com.linkedin.metadata.query.filter.SortCriterion; import com.linkedin.metadata.search.SearchEntity; import com.linkedin.metadata.search.SearchEntityArray; import com.linkedin.metadata.search.SearchResult; @@ -30,6 +29,7 @@ import graphql.schema.DataFetchingEnvironment; import io.datahubproject.metadata.context.OperationContext; import java.util.HashSet; +import java.util.List; import org.mockito.Mockito; import org.testng.annotations.Test; @@ -46,7 +46,7 @@ public void testGetSuccess() throws Exception { any(), Mockito.eq(Constants.EXECUTION_REQUEST_ENTITY_NAME), Mockito.any(Filter.class), - Mockito.any(SortCriterion.class), + Mockito.any(List.class), Mockito.eq(0), Mockito.eq(10))) .thenReturn( diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/ingest/secret/ListSecretsResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/ingest/secret/ListSecretsResolverTest.java index 82b8d895384ca..96a12dc3be5a7 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/ingest/secret/ListSecretsResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/ingest/secret/ListSecretsResolverTest.java @@ -15,7 +15,6 @@ import com.linkedin.entity.EnvelopedAspectMap; import com.linkedin.entity.client.EntityClient; import com.linkedin.metadata.Constants; -import com.linkedin.metadata.query.filter.SortCriterion; import com.linkedin.metadata.search.SearchEntity; import com.linkedin.metadata.search.SearchEntityArray; import com.linkedin.metadata.search.SearchResult; @@ -24,6 +23,7 @@ import graphql.schema.DataFetchingEnvironment; import io.datahubproject.metadata.context.OperationContext; import java.util.HashSet; +import java.util.List; import org.mockito.Mockito; import org.testng.annotations.Test; @@ -44,7 +44,7 @@ public void testGetSuccess() throws Exception { Mockito.eq(Constants.SECRETS_ENTITY_NAME), Mockito.eq(""), Mockito.eq(null), - Mockito.any(SortCriterion.class), + Mockito.any(List.class), Mockito.eq(0), Mockito.eq(20))) .thenReturn( @@ -112,7 +112,7 @@ public void testGetUnauthorized() throws Exception { Mockito.any(), Mockito.eq(""), Mockito.eq(null), - Mockito.any(SortCriterion.class), + Mockito.any(List.class), Mockito.anyInt(), Mockito.anyInt()); } diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/query/ListQueriesResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/query/ListQueriesResolverTest.java index 70b427a1606f1..ee728b17e8c62 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/query/ListQueriesResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/query/ListQueriesResolverTest.java @@ -69,9 +69,10 @@ public void testGetSuccess(final ListQueriesInput input) throws Exception { : input.getQuery()), Mockito.eq(buildFilter(input.getSource(), input.getDatasetUrn())), Mockito.eq( - new SortCriterion() - .setField(ListQueriesResolver.CREATED_AT_FIELD) - .setOrder(SortOrder.DESCENDING)), + Collections.singletonList( + new SortCriterion() + .setField(ListQueriesResolver.CREATED_AT_FIELD) + .setOrder(SortOrder.DESCENDING))), Mockito.eq(input.getStart()), Mockito.eq(input.getCount()))) .thenReturn( diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/AggregateAcrossEntitiesResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/AggregateAcrossEntitiesResolverTest.java index 40062ed08977a..d32eb9fcf120c 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/AggregateAcrossEntitiesResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/AggregateAcrossEntitiesResolverTest.java @@ -324,7 +324,7 @@ public static void testErrorFetchingResults() throws Exception { Mockito.any(), Mockito.anyInt(), Mockito.anyInt(), - Mockito.eq(null), + Mockito.eq(Collections.emptyList()), Mockito.eq(null))) .thenThrow(new RemoteInvocationException()); @@ -397,7 +397,7 @@ private static EntityClient initMockEntityClient( Mockito.eq(filter), Mockito.eq(start), Mockito.eq(limit), - Mockito.eq(null), + Mockito.eq(Collections.emptyList()), Mockito.eq(facets))) .thenReturn(result); return client; @@ -420,7 +420,7 @@ private static void verifyMockEntityClient( Mockito.eq(filter), Mockito.eq(start), Mockito.eq(limit), - Mockito.eq(null), + Mockito.eq(Collections.emptyList()), Mockito.eq(facets)); } diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/GetQuickFiltersResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/GetQuickFiltersResolverTest.java index 25e374c766deb..64042e82bbfe8 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/GetQuickFiltersResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/GetQuickFiltersResolverTest.java @@ -24,6 +24,7 @@ import com.linkedin.r2.RemoteInvocationException; import graphql.schema.DataFetchingEnvironment; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletionException; import java.util.stream.Collectors; @@ -114,7 +115,7 @@ public static void testGetQuickFiltersFailure() throws Exception { Mockito.any(), Mockito.anyInt(), Mockito.anyInt(), - Mockito.eq(null), + Mockito.eq(Collections.emptyList()), Mockito.eq(null))) .thenThrow(new RemoteInvocationException()); @@ -300,7 +301,7 @@ private static EntityClient initMockEntityClient( Mockito.eq(filter), Mockito.eq(start), Mockito.eq(limit), - Mockito.eq(null), + Mockito.eq(Collections.emptyList()), Mockito.eq(null))) .thenReturn(result); return client; diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolverTest.java index bcbfda6c71bba..770effa85ae1a 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolverTest.java @@ -437,7 +437,7 @@ public static void testApplyViewErrorFetchingView() throws Exception { Mockito.any(), Mockito.anyInt(), Mockito.anyInt(), - Mockito.eq(null), + Mockito.eq(Collections.emptyList()), Mockito.eq(null))) .thenThrow(new RemoteInvocationException()); @@ -506,7 +506,7 @@ private static void verifyMockEntityClient( Mockito.eq(filter), Mockito.eq(start), Mockito.eq(limit), - Mockito.eq(null)); + Mockito.eq(Collections.emptyList())); } private static void verifyMockViewService(ViewService mockService, Urn viewUrn) { diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchResolverTest.java index a5310a052f613..fbbf5cf314eda 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchResolverTest.java @@ -18,6 +18,8 @@ import com.linkedin.metadata.search.SearchResult; import com.linkedin.metadata.search.SearchResultMetadata; import graphql.schema.DataFetchingEnvironment; +import java.util.Collections; +import java.util.List; import org.mockito.Mockito; import org.testng.annotations.Test; @@ -56,7 +58,7 @@ public void testDefaultSearchFlags() throws Exception { Constants.DATASET_ENTITY_NAME, // Verify that merged entity types were used. "", null, - null, + Collections.emptyList(), 0, 10, setConvertSchemaFieldsToDatasets( @@ -97,7 +99,7 @@ public void testOverrideSearchFlags() throws Exception { Constants.DATASET_ENTITY_NAME, // Verify that merged entity types were used. "", null, - null, + Collections.emptyList(), 1, 11, setConvertSchemaFieldsToDatasets( @@ -129,7 +131,7 @@ public void testNonWildCardSearchFlags() throws Exception { Constants.DATASET_ENTITY_NAME, // Verify that merged entity types were used. "not a wildcard", null, // Verify that view filter was used. - null, + Collections.emptyList(), 0, 10, setConvertSchemaFieldsToDatasets( @@ -170,7 +172,7 @@ private void verifyMockSearchEntityClient( String entityName, String query, Filter filter, - SortCriterion sortCriterion, + List sortCriteria, int start, int limit, com.linkedin.metadata.query.SearchFlags searchFlags) @@ -181,7 +183,7 @@ private void verifyMockSearchEntityClient( Mockito.eq(entityName), Mockito.eq(query), Mockito.eq(filter), - Mockito.eq(sortCriterion), + Mockito.eq(sortCriteria), Mockito.eq(start), Mockito.eq(limit)); } diff --git a/entity-registry/src/main/java/com/linkedin/metadata/aspect/GraphRetriever.java b/entity-registry/src/main/java/com/linkedin/metadata/aspect/GraphRetriever.java index 9757a10e3f3c2..cedaac25ffee9 100644 --- a/entity-registry/src/main/java/com/linkedin/metadata/aspect/GraphRetriever.java +++ b/entity-registry/src/main/java/com/linkedin/metadata/aspect/GraphRetriever.java @@ -20,7 +20,7 @@ public interface GraphRetriever { * @param destinationEntityFilter * @param relationshipTypes * @param relationshipFilter - * @param sortCriterion + * @param sortCriteria * @param scrollId * @param count * @param startTimeMillis @@ -35,7 +35,7 @@ RelatedEntitiesScrollResult scrollRelatedEntities( @Nonnull Filter destinationEntityFilter, @Nonnull List relationshipTypes, @Nonnull RelationshipFilter relationshipFilter, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, @Nullable String scrollId, int count, @Nullable Long startTimeMillis, diff --git a/li-utils/src/main/java/com/datahub/util/RecordUtils.java b/li-utils/src/main/java/com/datahub/util/RecordUtils.java index 8183ecc21ee27..f9c89a1b99212 100644 --- a/li-utils/src/main/java/com/datahub/util/RecordUtils.java +++ b/li-utils/src/main/java/com/datahub/util/RecordUtils.java @@ -78,6 +78,14 @@ public static String toJsonString(@Nonnull RecordTemplate recordTemplate) { } } + public static String toJsonString(@Nonnull List recordTemplates) { + StringBuilder json = new StringBuilder(); + for (RecordTemplate recordTemplate : recordTemplates) { + json.append(toJsonString(recordTemplate)); + } + return json.toString(); + } + /** * Creates a {@link RecordTemplate} object from a serialized JSON string. * diff --git a/metadata-io/src/main/java/com/linkedin/metadata/client/JavaEntityClient.java b/metadata-io/src/main/java/com/linkedin/metadata/client/JavaEntityClient.java index 337288ab59c60..30603be5bea1d 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/client/JavaEntityClient.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/client/JavaEntityClient.java @@ -60,6 +60,7 @@ import java.net.URISyntaxException; import java.time.Clock; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -372,7 +373,13 @@ public SearchResult search( return ValidationUtils.validateSearchResult( opContext, entitySearchService.search( - opContext, List.of(entity), input, newFilter(requestFilters), null, start, count), + opContext, + List.of(entity), + input, + newFilter(requestFilters), + Collections.emptyList(), + start, + count), entityService); } @@ -403,7 +410,7 @@ public ListResult list( opContext.withSearchFlags(flags -> flags.setFulltext(false)), entity, newFilter(requestFilters), - null, + Collections.emptyList(), start, count)), entityService); @@ -414,7 +421,7 @@ public ListResult list( * * @param input search query * @param filter search filters - * @param sortCriterion sort criterion + * @param sortCriteria sort criteria * @param start start offset for search results * @param count max number of search results requested * @return Snapshot key @@ -426,14 +433,14 @@ public SearchResult search( @Nonnull String entity, @Nonnull String input, @Nullable Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int start, int count) throws RemoteInvocationException { return ValidationUtils.validateSearchResult( opContext, entitySearchService.search( - opContext, List.of(entity), input, filter, sortCriterion, start, count), + opContext, List.of(entity), input, filter, sortCriteria, start, count), entityService); } @@ -446,10 +453,10 @@ public SearchResult searchAcrossEntities( @Nullable Filter filter, int start, int count, - @Nullable SortCriterion sortCriterion) + List sortCriteria) throws RemoteInvocationException { return searchAcrossEntities( - opContext, entities, input, filter, start, count, sortCriterion, null); + opContext, entities, input, filter, start, count, sortCriteria, null); } /** @@ -461,7 +468,7 @@ public SearchResult searchAcrossEntities( * @param start start offset for search results * @param count max number of search results requested * @param facets list of facets we want aggregations for - * @param sortCriterion sorting criterion + * @param sortCriteria sorting criteria * @return Snapshot key * @throws RemoteInvocationException when unable to execute request */ @@ -473,7 +480,7 @@ public SearchResult searchAcrossEntities( @Nullable Filter filter, int start, int count, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable List facets) throws RemoteInvocationException { @@ -484,7 +491,7 @@ public SearchResult searchAcrossEntities( entities, input, filter, - sortCriterion, + sortCriteria, start, count, facets), @@ -526,7 +533,7 @@ public LineageSearchResult searchAcrossLineage( @Nullable String input, @Nullable Integer maxHops, @Nullable Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int start, int count) throws RemoteInvocationException { @@ -540,7 +547,7 @@ public LineageSearchResult searchAcrossLineage( input, maxHops, filter, - sortCriterion, + sortCriteria, start, count), entityService); @@ -556,7 +563,7 @@ public LineageScrollResult scrollAcrossLineage( @Nullable String input, @Nullable Integer maxHops, @Nullable Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nonnull String keepAlive, int count) @@ -574,7 +581,7 @@ public LineageScrollResult scrollAcrossLineage( input, maxHops, filter, - sortCriterion, + sortCriteria, scrollId, keepAlive, count), @@ -642,7 +649,7 @@ public SearchResult filter( @Nonnull OperationContext opContext, @Nonnull String entity, @Nonnull Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int start, int count) throws RemoteInvocationException { @@ -652,7 +659,7 @@ public SearchResult filter( opContext.withSearchFlags(flags -> flags.setFulltext(true)), entity, filter, - sortCriterion, + sortCriteria, start, count), entityService); diff --git a/metadata-io/src/main/java/com/linkedin/metadata/graph/dgraph/DgraphGraphService.java b/metadata-io/src/main/java/com/linkedin/metadata/graph/dgraph/DgraphGraphService.java index 27b603244d3b3..6703e07bfd915 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/graph/dgraph/DgraphGraphService.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/graph/dgraph/DgraphGraphService.java @@ -788,7 +788,7 @@ public RelatedEntitiesScrollResult scrollRelatedEntities( @Nonnull Filter destinationEntityFilter, @Nonnull List relationshipTypes, @Nonnull RelationshipFilter relationshipFilter, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, @Nullable String scrollId, int count, @Nullable Long startTimeMillis, diff --git a/metadata-io/src/main/java/com/linkedin/metadata/graph/elastic/ESGraphQueryDAO.java b/metadata-io/src/main/java/com/linkedin/metadata/graph/elastic/ESGraphQueryDAO.java index 30b688761d584..a94bfce5df27a 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/graph/elastic/ESGraphQueryDAO.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/graph/elastic/ESGraphQueryDAO.java @@ -1307,7 +1307,7 @@ public SearchResponse getSearchResponse( @Nullable final Filter destinationEntityFilter, @Nonnull final List relationshipTypes, @Nonnull final RelationshipFilter relationshipFilter, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, @Nullable String scrollId, int count) { @@ -1320,12 +1320,12 @@ public SearchResponse getSearchResponse( relationshipTypes, relationshipFilter); - return executeScrollSearchQuery(finalQuery, sortCriterion, scrollId, count); + return executeScrollSearchQuery(finalQuery, sortCriteria, scrollId, count); } private SearchResponse executeScrollSearchQuery( @Nonnull final QueryBuilder query, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, @Nullable String scrollId, final int count) { @@ -1341,7 +1341,7 @@ private SearchResponse executeScrollSearchQuery( searchSourceBuilder.size(count); searchSourceBuilder.query(query); - ESUtils.buildSortOrder(searchSourceBuilder, sortCriterion, List.of(), false); + ESUtils.buildSortOrder(searchSourceBuilder, sortCriteria, List.of(), false); searchRequest.source(searchSourceBuilder); ESUtils.setSearchAfter(searchSourceBuilder, sort, null, null); diff --git a/metadata-io/src/main/java/com/linkedin/metadata/graph/elastic/ElasticSearchGraphService.java b/metadata-io/src/main/java/com/linkedin/metadata/graph/elastic/ElasticSearchGraphService.java index ada5069d0cabe..42b92f2930c78 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/graph/elastic/ElasticSearchGraphService.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/graph/elastic/ElasticSearchGraphService.java @@ -317,7 +317,7 @@ public RelatedEntitiesScrollResult scrollRelatedEntities( @Nullable Filter destinationEntityFilter, @Nonnull List relationshipTypes, @Nonnull RelationshipFilter relationshipFilter, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, @Nullable String scrollId, int count, @Nullable Long startTimeMillis, @@ -333,7 +333,7 @@ public RelatedEntitiesScrollResult scrollRelatedEntities( destinationEntityFilter, relationshipTypes, relationshipFilter, - sortCriterion, + sortCriteria, scrollId, count); diff --git a/metadata-io/src/main/java/com/linkedin/metadata/graph/neo4j/Neo4jGraphService.java b/metadata-io/src/main/java/com/linkedin/metadata/graph/neo4j/Neo4jGraphService.java index 16c0804538dd7..9fe9c242fe48c 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/graph/neo4j/Neo4jGraphService.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/graph/neo4j/Neo4jGraphService.java @@ -921,7 +921,7 @@ public RelatedEntitiesScrollResult scrollRelatedEntities( @Nonnull Filter destinationEntityFilter, @Nonnull List relationshipTypes, @Nonnull RelationshipFilter relationshipFilter, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, @Nullable String scrollId, int count, @Nullable Long startTimeMillis, diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/LineageSearchService.java b/metadata-io/src/main/java/com/linkedin/metadata/search/LineageSearchService.java index 95c8eb13beb93..df38813781386 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/LineageSearchService.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/LineageSearchService.java @@ -118,7 +118,7 @@ public class LineageSearchService { * @param maxHops the maximum number of hops away to search for. If null, defaults to 1000 * @param inputFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param from index to start the search from * @param size the number of search hits to return * @return a {@link LineageSearchResult} that contains a list of matched documents and related @@ -134,7 +134,7 @@ public LineageSearchResult searchAcrossLineage( @Nullable String input, @Nullable Integer maxHops, @Nullable Filter inputFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size) { @@ -255,7 +255,7 @@ public LineageSearchResult searchAcrossLineage( SearchUtils.removeCriteria( inputFilters, criterion -> criterion.getField().equals(DEGREE_FILTER_INPUT)); - if (canDoLightning(lineageRelationships, finalInput, reducedFilters, sortCriterion)) { + if (canDoLightning(lineageRelationships, finalInput, reducedFilters, sortCriteria)) { codePath = "lightning"; // use lightning approach to return lineage search results LineageSearchResult lineageSearchResult = @@ -276,7 +276,7 @@ public LineageSearchResult searchAcrossLineage( lineageRelationships, finalInput, reducedFilters, - sortCriterion, + sortCriteria, from, size); if (!lineageSearchResult.getEntities().isEmpty()) { @@ -303,7 +303,7 @@ boolean canDoLightning( List lineageRelationships, String input, Filter inputFilters, - SortCriterion sortCriterion) { + List sortCriteria) { boolean simpleFilters = inputFilters == null || inputFilters.getOr() == null @@ -318,7 +318,7 @@ boolean canDoLightning( return (lineageRelationships.size() > cacheConfiguration.getLightningThreshold()) && input.equals("*") && simpleFilters - && sortCriterion == null; + && CollectionUtils.isNotEmpty(sortCriteria); } @VisibleForTesting @@ -533,7 +533,7 @@ private LineageSearchResult getSearchResultInBatches( List lineageRelationships, @Nonnull String input, @Nullable Filter inputFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size) { @@ -566,7 +566,7 @@ private LineageSearchResult getSearchResultInBatches( entitiesToQuery, input, finalFilter, - sortCriterion, + sortCriteria, queryFrom, querySize), urnToRelationship); @@ -761,7 +761,7 @@ private LineageSearchEntity buildLineageSearchEntity( * @param maxHops the maximum number of hops away to search for. If null, defaults to 1000 * @param inputFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param scrollId opaque scroll identifier to pass to search service * @param size the number of search hits to return * @return a {@link LineageSearchResult} that contains a list of matched documents and related @@ -777,7 +777,7 @@ public LineageScrollResult scrollAcrossLineage( @Nullable String input, @Nullable Integer maxHops, @Nullable Filter inputFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nonnull String keepAlive, int size) { @@ -831,7 +831,7 @@ public LineageScrollResult scrollAcrossLineage( lineageRelationships, input != null ? input : "*", reducedFilters, - sortCriterion, + sortCriteria, scrollId, keepAlive, size); @@ -843,7 +843,7 @@ private LineageScrollResult getScrollResultInBatches( List lineageRelationships, @Nonnull String input, @Nullable Filter inputFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nonnull String keepAlive, int size) { @@ -878,7 +878,7 @@ private LineageScrollResult getScrollResultInBatches( entitiesToQuery, input, finalFilter, - sortCriterion, + sortCriteria, scrollId, keepAlive, querySize), diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/SearchService.java b/metadata-io/src/main/java/com/linkedin/metadata/search/SearchService.java index c8525f829d206..1cd738656d972 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/SearchService.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/SearchService.java @@ -65,7 +65,7 @@ public Map docCountPerEntity( * @param input the search input text * @param postFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param from index to start the search from * @param size the number of search hits to return * @return a {@link SearchResult} that contains a list of matched documents and related search @@ -77,7 +77,7 @@ public SearchResult search( @Nonnull List entityNames, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size) { List entitiesToSearch = getEntitiesToSearch(opContext, entityNames, size); @@ -87,7 +87,7 @@ public SearchResult search( } SearchResult result = _cachingEntitySearchService.search( - opContext, entitiesToSearch, input, postFilters, sortCriterion, from, size, null); + opContext, entitiesToSearch, input, postFilters, sortCriteria, from, size, null); try { return result @@ -105,11 +105,11 @@ public SearchResult searchAcrossEntities( @Nonnull List entities, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size) { return searchAcrossEntities( - opContext, entities, input, postFilters, sortCriterion, from, size, null); + opContext, entities, input, postFilters, sortCriteria, from, size, null); } /** @@ -120,7 +120,7 @@ public SearchResult searchAcrossEntities( * @param input the search input text * @param postFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param from index to start the search from * @param size the number of search hits to return * @param facets list of facets we want aggregations for @@ -133,14 +133,14 @@ public SearchResult searchAcrossEntities( @Nonnull List entities, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size, @Nullable List facets) { log.debug( String.format( "Searching Search documents entities: %s, input: %s, postFilters: %s, sortCriterion: %s, from: %s, size: %s", - entities, input, postFilters, sortCriterion, from, size)); + entities, input, postFilters, sortCriteria, from, size)); // DEPRECATED // This is the legacy version of `_entityType`-- it operates as a special case and does not // support ORs, Unions, etc. @@ -160,7 +160,7 @@ public SearchResult searchAcrossEntities( } SearchResult result = _cachingEntitySearchService.search( - opContext, nonEmptyEntities, input, postFilters, sortCriterion, from, size, facets); + opContext, nonEmptyEntities, input, postFilters, sortCriteria, from, size, facets); if (facets == null || facets.contains("entity") || facets.contains("_entityType")) { Optional entityTypeAgg = result.getMetadata().getAggregations().stream() @@ -238,7 +238,7 @@ public List getEntitiesToSearch( * @param input the search input text * @param postFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param scrollId opaque scroll identifier for passing to search backend * @param size the number of search hits to return * @return a {@link ScrollResult} that contains a list of matched documents and related search @@ -250,21 +250,21 @@ public ScrollResult scrollAcrossEntities( @Nonnull List entities, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size) { log.debug( String.format( - "Searching Search documents entities: %s, input: %s, postFilters: %s, sortCriterion: %s, from: %s, size: %s", - entities, input, postFilters, sortCriterion, scrollId, size)); + "Searching Search documents entities: %s, input: %s, postFilters: %s, sortCriteria: %s, from: %s, size: %s", + entities, input, postFilters, sortCriteria, scrollId, size)); List entitiesToSearch = getEntitiesToSearch(opContext, entities, size); if (entitiesToSearch.isEmpty()) { // No indices with non-zero entries: skip querying and return empty result return getEmptyScrollResult(size); } return _cachingEntitySearchService.scroll( - opContext, entitiesToSearch, input, postFilters, sortCriterion, scrollId, keepAlive, size); + opContext, entitiesToSearch, input, postFilters, sortCriteria, scrollId, keepAlive, size); } private static SearchResult getEmptySearchResult(int from, int size) { diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/SearchServiceSearchRetriever.java b/metadata-io/src/main/java/com/linkedin/metadata/search/SearchServiceSearchRetriever.java index a5ef1c8fa58b1..8d7548e0ba90a 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/SearchServiceSearchRetriever.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/SearchServiceSearchRetriever.java @@ -43,7 +43,7 @@ public ScrollResult scroll( entities, "*", filters, - urnSort, + List.of(urnSort), scrollId, null, count); diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/cache/CachedSearchResult.java b/metadata-io/src/main/java/com/linkedin/metadata/search/cache/CachedSearchResult.java new file mode 100644 index 0000000000000..7fa93be62fd97 --- /dev/null +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/cache/CachedSearchResult.java @@ -0,0 +1,23 @@ +package com.linkedin.metadata.search.cache; + +import static com.datahub.util.RecordUtils.*; +import static com.linkedin.metadata.search.utils.GZIPUtil.*; + +import com.linkedin.metadata.search.SearchResult; +import java.io.Serializable; +import lombok.Data; + +@Data +public class CachedSearchResult implements Serializable { + private final byte[] searchResult; + private final long timestamp; + + public CachedSearchResult(SearchResult lineageResult, long timestamp) { + this.searchResult = gzipCompress(toJsonString(lineageResult)); + this.timestamp = timestamp; + } + + public SearchResult getSearchResult() { + return toRecordTemplate(SearchResult.class, gzipDecompress(searchResult)); + } +} diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/client/CachingEntitySearchService.java b/metadata-io/src/main/java/com/linkedin/metadata/search/client/CachingEntitySearchService.java index 5db427fa90148..cb062e0e3f448 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/client/CachingEntitySearchService.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/client/CachingEntitySearchService.java @@ -20,6 +20,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import lombok.RequiredArgsConstructor; +import org.apache.commons.collections.CollectionUtils; import org.javatuples.Septet; import org.javatuples.Sextet; import org.springframework.cache.Cache; @@ -47,7 +48,7 @@ public class CachingEntitySearchService { * @param entityNames the names of the entity to search * @param query the search query * @param filters the filters to include - * @param sortCriterion the sort criterion + * @param sortCriteria the sort criteria * @param from the start offset * @param size the count * @param facets list of facets we want aggregations for @@ -58,12 +59,12 @@ public SearchResult search( @Nonnull List entityNames, @Nonnull String query, @Nullable Filter filters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size, @Nullable List facets) { return getCachedSearchResults( - opContext, entityNames, query, filters, sortCriterion, from, size, facets); + opContext, entityNames, query, filters, sortCriteria, from, size, facets); } /** @@ -115,7 +116,7 @@ public BrowseResult browse( * @param entities the names of the entities to search * @param query the search query * @param filters the filters to include - * @param sortCriterion the sort criterion + * @param sortCriteria the sort criteria * @param scrollId opaque scroll identifier for a scroll request * @param keepAlive the string representation of how long to keep point in time alive * @param size the count @@ -126,12 +127,12 @@ public ScrollResult scroll( @Nonnull List entities, @Nonnull String query, @Nullable Filter filters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size) { return getCachedScrollResults( - opContext, entities, query, filters, sortCriterion, scrollId, keepAlive, size); + opContext, entities, query, filters, sortCriteria, scrollId, keepAlive, size); } /** @@ -145,7 +146,7 @@ public SearchResult getCachedSearchResults( @Nonnull List entityNames, @Nonnull String query, @Nullable Filter filters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size, @Nullable List facets) { @@ -158,7 +159,7 @@ public SearchResult getCachedSearchResults( entityNames, query, filters, - sortCriterion, + sortCriteria, querySize.getFrom(), querySize.getSize(), facets), @@ -168,7 +169,7 @@ public SearchResult getCachedSearchResults( entityNames, query, filters != null ? toJsonString(filters) : null, - sortCriterion != null ? toJsonString(sortCriterion) : null, + CollectionUtils.isNotEmpty(sortCriteria) ? toJsonString(sortCriteria) : null, facets, querySize), enableCache) @@ -269,7 +270,7 @@ public ScrollResult getCachedScrollResults( @Nonnull List entities, @Nonnull String query, @Nullable Filter filters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size) { @@ -291,7 +292,7 @@ public ScrollResult getCachedScrollResults( entities, query, filters != null ? toJsonString(filters) : null, - sortCriterion != null ? toJsonString(sortCriterion) : null, + CollectionUtils.isNotEmpty(sortCriteria) ? toJsonString(sortCriteria) : null, scrollId, size); String json = cache.get(cacheKey, String.class); @@ -305,7 +306,7 @@ public ScrollResult getCachedScrollResults( entities, query, filters, - sortCriterion, + sortCriteria, scrollId, keepAlive, size, @@ -321,7 +322,7 @@ public ScrollResult getCachedScrollResults( entities, query, filters, - sortCriterion, + sortCriteria, scrollId, keepAlive, size, @@ -337,12 +338,12 @@ private SearchResult getRawSearchResults( final List entityNames, final String input, final Filter filters, - final SortCriterion sortCriterion, + final List sortCriteria, final int start, final int count, @Nullable final List facets) { return entitySearchService.search( - opContext, entityNames, input, filters, sortCriterion, start, count, facets); + opContext, entityNames, input, filters, sortCriteria, start, count, facets); } /** Executes the expensive autocomplete query using the {@link EntitySearchService} */ @@ -373,17 +374,17 @@ private ScrollResult getRawScrollResults( final List entities, final String input, final Filter filters, - final SortCriterion sortCriterion, + final List sortCriteria, @Nullable final String scrollId, @Nullable final String keepAlive, final int count, final boolean fulltext) { if (fulltext) { return entitySearchService.fullTextScroll( - opContext, entities, input, filters, sortCriterion, scrollId, keepAlive, count); + opContext, entities, input, filters, sortCriteria, scrollId, keepAlive, count); } else { return entitySearchService.structuredScroll( - opContext, entities, input, filters, sortCriterion, scrollId, keepAlive, count); + opContext, entities, input, filters, sortCriteria, scrollId, keepAlive, count); } } diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/ElasticSearchService.java b/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/ElasticSearchService.java index 578c34611a75a..4d5fe8d0b8e60 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/ElasticSearchService.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/ElasticSearchService.java @@ -142,10 +142,10 @@ public SearchResult search( @Nonnull List entityNames, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size) { - return search(opContext, entityNames, input, postFilters, sortCriterion, from, size, null); + return search(opContext, entityNames, input, postFilters, sortCriteria, from, size, null); } @Nonnull @@ -154,14 +154,14 @@ public SearchResult search( @Nonnull List entityNames, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size, @Nullable List facets) { log.debug( String.format( - "Searching FullText Search documents entityName: %s, input: %s, postFilters: %s, sortCriterion: %s, from: %s, size: %s", - entityNames, input, postFilters, sortCriterion, from, size)); + "Searching FullText Search documents entityName: %s, input: %s, postFilters: %s, sortCriteria: %s, from: %s, size: %s", + entityNames, input, postFilters, sortCriteria, from, size)); return esSearchDAO.search( opContext.withSearchFlags( @@ -169,7 +169,7 @@ public SearchResult search( entityNames, input, postFilters, - sortCriterion, + sortCriteria, from, size, facets); @@ -181,20 +181,20 @@ public SearchResult filter( @Nonnull OperationContext opContext, @Nonnull String entityName, @Nullable Filter filters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size) { log.debug( String.format( - "Filtering Search documents entityName: %s, filters: %s, sortCriterion: %s, from: %s, size: %s", - entityName, filters, sortCriterion, from, size)); + "Filtering Search documents entityName: %s, filters: %s, sortCriteria: %s, from: %s, size: %s", + entityName, filters, sortCriteria, from, size)); return esSearchDAO.filter( opContext.withSearchFlags( flags -> applyDefaultSearchFlags(flags, null, DEFAULT_SERVICE_SEARCH_FLAGS)), entityName, filters, - sortCriterion, + sortCriteria, from, size); } @@ -330,14 +330,14 @@ public ScrollResult fullTextScroll( @Nonnull List entities, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size) { log.debug( String.format( - "Scrolling Structured Search documents entities: %s, input: %s, postFilters: %s, sortCriterion: %s, scrollId: %s, size: %s", - entities, input, postFilters, sortCriterion, scrollId, size)); + "Scrolling Structured Search documents entities: %s, input: %s, postFilters: %s, sortCriteria: %s, scrollId: %s, size: %s", + entities, input, postFilters, sortCriteria, scrollId, size)); return esSearchDAO.scroll( opContext.withSearchFlags( @@ -347,7 +347,7 @@ public ScrollResult fullTextScroll( entities, input, postFilters, - sortCriterion, + sortCriteria, scrollId, keepAlive, size); @@ -360,14 +360,14 @@ public ScrollResult structuredScroll( @Nonnull List entities, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size) { log.debug( String.format( - "Scrolling FullText Search documents entities: %s, input: %s, postFilters: %s, sortCriterion: %s, scrollId: %s, size: %s", - entities, input, postFilters, sortCriterion, scrollId, size)); + "Scrolling FullText Search documents entities: %s, input: %s, postFilters: %s, sortCriteria: %s, scrollId: %s, size: %s", + entities, input, postFilters, sortCriteria, scrollId, size)); return esSearchDAO.scroll( opContext.withSearchFlags( @@ -377,7 +377,7 @@ public ScrollResult structuredScroll( entities, input, postFilters, - sortCriterion, + sortCriteria, scrollId, keepAlive, size); @@ -400,7 +400,7 @@ public ExplainResponse explain( @Nonnull String documentId, @Nonnull String entityName, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size, @@ -413,7 +413,7 @@ public ExplainResponse explain( documentId, entityName, postFilters, - sortCriterion, + sortCriteria, scrollId, keepAlive, size, diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/query/ESSearchDAO.java b/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/query/ESSearchDAO.java index b537a39634027..cb342794aff58 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/query/ESSearchDAO.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/query/ESSearchDAO.java @@ -228,7 +228,7 @@ private ScrollResult executeAndExtract( * @param input the search input text * @param postFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param from index to start the search from * @param size the number of search hits to return * @param facets list of facets we want aggregations for @@ -241,7 +241,7 @@ public SearchResult search( @Nonnull List entityNames, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size, @Nullable List facets) { @@ -257,7 +257,7 @@ public SearchResult search( final SearchRequest searchRequest = SearchRequestHandler.getBuilder(entitySpecs, searchConfiguration, customSearchConfiguration) .getSearchRequest( - opContext, finalInput, transformedFilters, sortCriterion, from, size, facets); + opContext, finalInput, transformedFilters, sortCriteria, from, size, facets); searchRequest.indices( entityNames.stream().map(indexConvention::getEntityIndexName).toArray(String[]::new)); searchRequestTimer.stop(); @@ -270,7 +270,7 @@ public SearchResult search( * * @param filters the request map with fields and values to be applied as filters to the search * query - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param from index to start the search from * @param size number of search hits to return * @return a {@link SearchResult} that contains a list of filtered documents and related search @@ -281,7 +281,7 @@ public SearchResult filter( @Nonnull OperationContext opContext, @Nonnull String entityName, @Nullable Filter filters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size) { IndexConvention indexConvention = opContext.getSearchContext().getIndexConvention(); @@ -289,7 +289,7 @@ public SearchResult filter( Filter transformedFilters = transformFilterForEntities(filters, indexConvention); final SearchRequest searchRequest = SearchRequestHandler.getBuilder(entitySpec, searchConfiguration, customSearchConfiguration) - .getFilterRequest(opContext, transformedFilters, sortCriterion, from, size); + .getFilterRequest(opContext, transformedFilters, sortCriteria, from, size); searchRequest.indices(indexConvention.getIndexName(entitySpec)); return executeAndExtract( @@ -401,7 +401,7 @@ public Map aggregateByValue( * @param input the search input text * @param postFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param scrollId opaque scroll Id to convert to a PIT ID and Sort array to pass to ElasticSearch * @param keepAlive string representation of the time to keep a point in time alive * @param size the number of search hits to return @@ -414,7 +414,7 @@ public ScrollResult scroll( @Nonnull List entities, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size) { @@ -439,7 +439,7 @@ public ScrollResult scroll( transformedFilters, entitySpecs, finalInput, - sortCriterion, + sortCriteria, null); // PIT specifies indices in creation so it doesn't support specifying indices on the request, so @@ -462,7 +462,7 @@ private SearchRequest getScrollRequest( @Nullable Filter postFilters, List entitySpecs, String finalInput, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable List facets) { String pitId = null; Object[] sort = null; @@ -483,15 +483,7 @@ private SearchRequest getScrollRequest( return SearchRequestHandler.getBuilder( entitySpecs, searchConfiguration, customSearchConfiguration) .getSearchRequest( - opContext, - finalInput, - postFilters, - sortCriterion, - sort, - pitId, - keepAlive, - size, - facets); + opContext, finalInput, postFilters, sortCriteria, sort, pitId, keepAlive, size, facets); } public Optional raw( @@ -544,7 +536,7 @@ public ExplainResponse explain( @Nonnull String documentId, @Nonnull String entityName, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size, @@ -564,7 +556,7 @@ public ExplainResponse explain( transformedFilters, Collections.singletonList(entitySpec), finalQuery, - sortCriterion, + sortCriteria, facets); ; diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/query/request/SearchRequestHandler.java b/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/query/request/SearchRequestHandler.java index 66ad1e3be363f..6e4210de6ef80 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/query/request/SearchRequestHandler.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/query/request/SearchRequestHandler.java @@ -187,7 +187,7 @@ public SearchRequest getSearchRequest( @Nonnull OperationContext opContext, @Nonnull String input, @Nullable Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size, @Nullable List facets) { @@ -213,7 +213,7 @@ public SearchRequest getSearchRequest( if (Boolean.FALSE.equals(searchFlags.isSkipHighlighting())) { searchSourceBuilder.highlighter(highlights); } - ESUtils.buildSortOrder(searchSourceBuilder, sortCriterion, entitySpecs); + ESUtils.buildSortOrder(searchSourceBuilder, sortCriteria, entitySpecs); if (Boolean.TRUE.equals(searchFlags.isGetSuggestions())) { ESUtils.buildNameSuggestions(searchSourceBuilder, input); @@ -243,7 +243,7 @@ public SearchRequest getSearchRequest( @Nonnull OperationContext opContext, @Nonnull String input, @Nullable Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable Object[] sort, @Nullable String pitId, @Nullable String keepAlive, @@ -272,7 +272,7 @@ public SearchRequest getSearchRequest( if (Boolean.FALSE.equals(searchFlags.isSkipHighlighting())) { searchSourceBuilder.highlighter(highlights); } - ESUtils.buildSortOrder(searchSourceBuilder, sortCriterion, entitySpecs); + ESUtils.buildSortOrder(searchSourceBuilder, sortCriteria, entitySpecs); searchRequest.source(searchSourceBuilder); log.debug("Search request is: " + searchRequest); searchRequest.indicesOptions(null); @@ -285,7 +285,7 @@ public SearchRequest getSearchRequest( * to be applied to search results. * * @param filters {@link Filter} list of conditions with fields and values - * @param sortCriterion {@link SortCriterion} to be applied to the search results + * @param sortCriteria list of {@link SortCriterion} to be applied to the search results * @param from index to start the search from * @param size the number of search hits to return * @return {@link SearchRequest} that contains the filtered query @@ -294,7 +294,7 @@ public SearchRequest getSearchRequest( public SearchRequest getFilterRequest( @Nonnull OperationContext opContext, @Nullable Filter filters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size) { SearchRequest searchRequest = new SearchRequest(); @@ -303,7 +303,7 @@ public SearchRequest getFilterRequest( final SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(filterQuery); searchSourceBuilder.from(from).size(size); - ESUtils.buildSortOrder(searchSourceBuilder, sortCriterion, entitySpecs); + ESUtils.buildSortOrder(searchSourceBuilder, sortCriteria, entitySpecs); searchRequest.source(searchSourceBuilder); return searchRequest; diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/utils/ESUtils.java b/metadata-io/src/main/java/com/linkedin/metadata/search/utils/ESUtils.java index e299dde62b184..c4060bbb0928b 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/utils/ESUtils.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/utils/ESUtils.java @@ -299,17 +299,14 @@ public static String getElasticTypeForFieldType(SearchableAnnotation.FieldType f * * @param searchSourceBuilder {@link SearchSourceBuilder} that needs to be populated with sort * order - * @param sortCriterion {@link SortCriterion} to be applied to the search results + * @param sortCriteria list of {@link SortCriterion} to be applied to the search results */ public static void buildSortOrder( @Nonnull SearchSourceBuilder searchSourceBuilder, - @Nullable SortCriterion sortCriterion, + List sortCriteria, List entitySpecs) { buildSortOrder( - searchSourceBuilder, - sortCriterion == null ? List.of() : List.of(sortCriterion), - entitySpecs, - true); + searchSourceBuilder, sortCriteria == null ? List.of() : sortCriteria, entitySpecs, true); } /** @@ -321,20 +318,20 @@ public static void buildSortOrder( */ public static void buildSortOrder( @Nonnull SearchSourceBuilder searchSourceBuilder, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, List entitySpecs, boolean enableDefaultSort) { - if (sortCriterion.isEmpty() && enableDefaultSort) { + if (sortCriteria.isEmpty() && enableDefaultSort) { searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC)); } else { - for (SortCriterion sortCriteria : sortCriterion) { + for (SortCriterion sortCriterion : sortCriteria) { Optional fieldTypeForDefault = Optional.empty(); for (EntitySpec entitySpec : entitySpecs) { List fieldSpecs = entitySpec.getSearchableFieldSpecs(); for (SearchableFieldSpec fieldSpec : fieldSpecs) { SearchableAnnotation annotation = fieldSpec.getSearchableAnnotation(); - if (annotation.getFieldName().equals(sortCriteria.getField()) - || annotation.getFieldNameAliases().contains(sortCriteria.getField())) { + if (annotation.getFieldName().equals(sortCriterion.getField()) + || annotation.getFieldNameAliases().contains(sortCriterion.getField())) { fieldTypeForDefault = Optional.of(fieldSpec.getSearchableAnnotation().getFieldType()); break; } @@ -346,15 +343,15 @@ public static void buildSortOrder( if (fieldTypeForDefault.isEmpty() && !entitySpecs.isEmpty()) { log.warn( "Sort criterion field " - + sortCriteria.getField() + + sortCriterion.getField() + " was not found in any entity spec to be searched"); } final SortOrder esSortOrder = - (sortCriteria.getOrder() == com.linkedin.metadata.query.filter.SortOrder.ASCENDING) + (sortCriterion.getOrder() == com.linkedin.metadata.query.filter.SortOrder.ASCENDING) ? SortOrder.ASC : SortOrder.DESC; FieldSortBuilder sortBuilder = - new FieldSortBuilder(sortCriteria.getField()).order(esSortOrder); + new FieldSortBuilder(sortCriterion.getField()).order(esSortOrder); if (fieldTypeForDefault.isPresent()) { String esFieldtype = getElasticTypeForFieldType(fieldTypeForDefault.get()); if (esFieldtype != null) { @@ -365,8 +362,8 @@ public static void buildSortOrder( } } if (enableDefaultSort - && (sortCriterion.isEmpty() - || sortCriterion.stream() + && (sortCriteria.isEmpty() + || sortCriteria.stream() .noneMatch(c -> c.getField().equals(DEFAULT_SEARCH_RESULTS_SORT_BY_FIELD)))) { searchSourceBuilder.sort( new FieldSortBuilder(DEFAULT_SEARCH_RESULTS_SORT_BY_FIELD).order(SortOrder.ASC)); diff --git a/metadata-io/src/main/java/com/linkedin/metadata/timeseries/elastic/ElasticSearchTimeseriesAspectService.java b/metadata-io/src/main/java/com/linkedin/metadata/timeseries/elastic/ElasticSearchTimeseriesAspectService.java index ce4ff53eba91b..9b4d373d25d8f 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/timeseries/elastic/ElasticSearchTimeseriesAspectService.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/timeseries/elastic/ElasticSearchTimeseriesAspectService.java @@ -551,7 +551,7 @@ public TimeseriesScrollResult scrollAspects( @Nonnull String entityName, @Nonnull String aspectName, @Nullable Filter filter, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, @Nullable String scrollId, int count, @Nullable Long startTimeMillis, @@ -592,7 +592,7 @@ public TimeseriesScrollResult scrollAspects( entityName, aspectName, filterQueryBuilder, - sortCriterion, + sortCriteria, scrollId, count); int totalCount = (int) response.getHits().getTotalHits().value; @@ -615,7 +615,7 @@ private SearchResponse executeScrollSearchQuery( @Nonnull final String entityName, @Nonnull final String aspectName, @Nonnull final QueryBuilder query, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, @Nullable String scrollId, final int count) { @@ -631,7 +631,7 @@ private SearchResponse executeScrollSearchQuery( searchSourceBuilder.size(count); searchSourceBuilder.query(query); - ESUtils.buildSortOrder(searchSourceBuilder, sortCriterion, List.of(), false); + ESUtils.buildSortOrder(searchSourceBuilder, sortCriteria, List.of(), false); searchRequest.source(searchSourceBuilder); ESUtils.setSearchAfter(searchSourceBuilder, sort, null, null); diff --git a/metadata-io/src/test/java/com/linkedin/metadata/search/fixtures/SampleDataFixtureTestBase.java b/metadata-io/src/test/java/com/linkedin/metadata/search/fixtures/SampleDataFixtureTestBase.java index a3f6f39e6387c..7e434bf93329e 100644 --- a/metadata-io/src/test/java/com/linkedin/metadata/search/fixtures/SampleDataFixtureTestBase.java +++ b/metadata-io/src/test/java/com/linkedin/metadata/search/fixtures/SampleDataFixtureTestBase.java @@ -216,7 +216,7 @@ public void testGetSortOrder() { SearchSourceBuilder builder = new SearchSourceBuilder(); SortCriterion sortCriterion = new SortCriterion().setOrder(SortOrder.DESCENDING).setField(dateFieldName); - ESUtils.buildSortOrder(builder, sortCriterion, entitySpecs); + ESUtils.buildSortOrder(builder, Collections.singletonList(sortCriterion), entitySpecs); List> sorts = builder.sorts(); assertEquals(sorts.size(), 2); // sort by last modified and then by urn for (SortBuilder sort : sorts) { @@ -235,7 +235,7 @@ public void testGetSortOrder() { SearchSourceBuilder nameBuilder = new SearchSourceBuilder(); SortCriterion nameCriterion = new SortCriterion().setOrder(SortOrder.ASCENDING).setField(entityNameField); - ESUtils.buildSortOrder(nameBuilder, nameCriterion, entitySpecs); + ESUtils.buildSortOrder(nameBuilder, Collections.singletonList(nameCriterion), entitySpecs); sorts = nameBuilder.sorts(); assertEquals(sorts.size(), 2); for (SortBuilder sort : sorts) { @@ -1959,7 +1959,7 @@ public void testSortOrdering() { SEARCHABLE_ENTITIES, query, null, - criterion, + Collections.singletonList(criterion), 0, 100, null); diff --git a/metadata-service/openapi-entity-servlet/src/main/java/io/datahubproject/openapi/v2/delegates/EntityApiDelegateImpl.java b/metadata-service/openapi-entity-servlet/src/main/java/io/datahubproject/openapi/v2/delegates/EntityApiDelegateImpl.java index bd4d68834b9e8..b977d9e7f27d0 100644 --- a/metadata-service/openapi-entity-servlet/src/main/java/io/datahubproject/openapi/v2/delegates/EntityApiDelegateImpl.java +++ b/metadata-service/openapi-entity-servlet/src/main/java/io/datahubproject/openapi/v2/delegates/EntityApiDelegateImpl.java @@ -60,6 +60,7 @@ import io.datahubproject.openapi.util.OpenApiEntitiesUtil; import io.datahubproject.openapi.v1.entities.EntitiesController; import java.net.URISyntaxException; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -611,12 +612,18 @@ public ResponseEntity scroll( authentication, true); - // TODO multi-field sort - SortCriterion sortCriterion = new SortCriterion(); - sortCriterion.setField(Optional.ofNullable(sort).map(s -> s.get(0)).orElse("urn")); - sortCriterion.setOrder( - com.linkedin.metadata.query.filter.SortOrder.valueOf( - Optional.ofNullable(sortOrder).map(Enum::name).orElse("ASCENDING"))); + List sortCriteria = + Optional.ofNullable(sort).orElse(Collections.singletonList("urn")).stream() + .map( + sortField -> { + SortCriterion sortCriterion = new SortCriterion(); + sortCriterion.setField(sortField); + sortCriterion.setOrder( + com.linkedin.metadata.query.filter.SortOrder.valueOf( + Optional.ofNullable(sortOrder).map(Enum::name).orElse("ASCENDING"))); + return sortCriterion; + }) + .collect(Collectors.toList()); ScrollResult result = _searchService.scrollAcrossEntities( @@ -624,7 +631,7 @@ public ResponseEntity scroll( List.of(entitySpec.getName()), query, null, - sortCriterion, + sortCriteria, scrollId, null, count); diff --git a/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/controller/GenericEntitiesController.java b/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/controller/GenericEntitiesController.java index 6869f7bf58235..fda801eba0cba 100644 --- a/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/controller/GenericEntitiesController.java +++ b/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/controller/GenericEntitiesController.java @@ -55,6 +55,8 @@ import java.lang.reflect.InvocationTargetException; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -66,6 +68,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -140,6 +143,7 @@ public ResponseEntity getEntities( @RequestParam(value = "query", defaultValue = "*") String query, @RequestParam(value = "scrollId", required = false) String scrollId, @RequestParam(value = "sort", required = false, defaultValue = "urn") String sortField, + @RequestParam(value = "sortCriteria", required = false) List sortFields, @RequestParam(value = "sortOrder", required = false, defaultValue = "ASCENDING") String sortOrder, @RequestParam(value = "systemMetadata", required = false, defaultValue = "false") @@ -164,8 +168,15 @@ public ResponseEntity getEntities( authentication, true); - // TODO: support additional and multiple sort params - SortCriterion sortCriterion = SearchUtil.sortBy(sortField, SortOrder.valueOf(sortOrder)); + List sortCriteria; + if (!CollectionUtils.isEmpty(sortFields)) { + sortCriteria = new ArrayList<>(); + sortFields.forEach( + field -> sortCriteria.add(SearchUtil.sortBy(field, SortOrder.valueOf(sortOrder)))); + } else { + sortCriteria = + Collections.singletonList(SearchUtil.sortBy(sortField, SortOrder.valueOf(sortOrder))); + } ScrollResult result = searchService.scrollAcrossEntities( @@ -175,7 +186,7 @@ public ResponseEntity getEntities( List.of(entitySpec.getName()), query, null, - sortCriterion, + sortCriteria, scrollId, null, count); diff --git a/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/operations/elastic/OperationsController.java b/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/operations/elastic/OperationsController.java index f4437e71ba299..d5fedd5e348e3 100644 --- a/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/operations/elastic/OperationsController.java +++ b/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/operations/elastic/OperationsController.java @@ -204,12 +204,12 @@ public ResponseEntity explainSearchQuery( @Nullable Filter filters, @Parameter( - name = "sortCriterion", + name = "sortCriteria", required = false, description = "Criterion to sort results on.") - @RequestParam("sortCriterion") + @RequestParam("sortCriteria") @Nullable - SortCriterion sortCriterion, + List sortCriteria, @Parameter( name = "searchFlags", required = false, @@ -248,7 +248,7 @@ public ResponseEntity explainSearchQuery( documentId, entityName, filters, - sortCriterion, + sortCriteria, scrollId, keepAlive, size, diff --git a/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/v2/controller/TimeseriesController.java b/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/v2/controller/TimeseriesController.java index 1c404006d97a4..8a41ed57c4a8a 100644 --- a/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/v2/controller/TimeseriesController.java +++ b/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/v2/controller/TimeseriesController.java @@ -86,7 +86,7 @@ public ResponseEntity> getAspects( throw new IllegalArgumentException("Only timeseries aspects are supported."); } - List sortCriterion = + List sortCriteria = List.of( SearchUtil.sortBy("timestampMillis", SortOrder.DESCENDING), SearchUtil.sortBy("messageId", SortOrder.DESCENDING)); @@ -97,7 +97,7 @@ public ResponseEntity> getAspects( entityName, aspectName, null, - sortCriterion, + sortCriteria, scrollId, count, startTimeMillis, diff --git a/metadata-service/restli-api/src/main/idl/com.linkedin.entity.entities.restspec.json b/metadata-service/restli-api/src/main/idl/com.linkedin.entity.entities.restspec.json index fe53b43ccd1da..935a429383928 100644 --- a/metadata-service/restli-api/src/main/idl/com.linkedin.entity.entities.restspec.json +++ b/metadata-service/restli-api/src/main/idl/com.linkedin.entity.entities.restspec.json @@ -199,6 +199,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "start", "type" : "int" @@ -248,6 +252,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "start", "type" : "int" @@ -288,6 +296,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "scrollId", "type" : "string", @@ -333,6 +345,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "scrollId", "type" : "string", @@ -374,6 +390,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "start", "type" : "int" @@ -411,6 +431,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "start", "type" : "int" @@ -452,6 +476,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "start", "type" : "int" diff --git a/metadata-service/restli-api/src/main/snapshot/com.linkedin.entity.entities.snapshot.json b/metadata-service/restli-api/src/main/snapshot/com.linkedin.entity.entities.snapshot.json index 5dcedfecf99ca..04a5ab99a300c 100644 --- a/metadata-service/restli-api/src/main/snapshot/com.linkedin.entity.entities.snapshot.json +++ b/metadata-service/restli-api/src/main/snapshot/com.linkedin.entity.entities.snapshot.json @@ -6649,6 +6649,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "start", "type" : "int" @@ -6698,6 +6702,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "start", "type" : "int" @@ -6738,6 +6746,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "scrollId", "type" : "string", @@ -6783,6 +6795,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "scrollId", "type" : "string", @@ -6824,6 +6840,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "start", "type" : "int" @@ -6861,6 +6881,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "start", "type" : "int" @@ -6902,6 +6926,10 @@ "name" : "sort", "type" : "com.linkedin.metadata.query.filter.SortCriterion", "optional" : true + }, { + "name" : "sortCriteria", + "type" : "{ \"type\" : \"array\", \"items\" : \"com.linkedin.metadata.query.filter.SortCriterion\" }", + "optional" : true }, { "name" : "start", "type" : "int" diff --git a/metadata-service/restli-client-api/src/main/java/com/linkedin/entity/client/EntityClient.java b/metadata-service/restli-client-api/src/main/java/com/linkedin/entity/client/EntityClient.java index a7980d0d5c99f..252621e0b0cad 100644 --- a/metadata-service/restli-client-api/src/main/java/com/linkedin/entity/client/EntityClient.java +++ b/metadata-service/restli-client-api/src/main/java/com/linkedin/entity/client/EntityClient.java @@ -234,7 +234,7 @@ ListResult list( * * @param input search query * @param filter search filters - * @param sortCriterion sort criterion + * @param sortCriteria sort criteria * @param start start offset for search results * @param count max number of search results requested * @return Snapshot key @@ -245,7 +245,7 @@ SearchResult search( @Nonnull String entity, @Nonnull String input, @Nullable Filter filter, - SortCriterion sortCriterion, + List sortCriteria, int start, int count) throws RemoteInvocationException; @@ -269,7 +269,7 @@ SearchResult searchAcrossEntities( @Nullable Filter filter, int start, int count, - @Nullable SortCriterion sortCriterion) + List sortCriteria) throws RemoteInvocationException; /** @@ -291,7 +291,7 @@ SearchResult searchAcrossEntities( @Nullable Filter filter, int start, int count, - @Nullable SortCriterion sortCriterion, + List sortCriteria, List facets) throws RemoteInvocationException; @@ -327,7 +327,7 @@ ScrollResult scrollAcrossEntities( * @param input the search input text * @param maxHops the max number of hops away to search for. If null, searches all hops. * @param filter the request map with fields and values as filters to be applied to search hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param start index to start the search from * @param count the number of search hits to return * @return a {@link SearchResult} that contains a list of matched documents and related search @@ -341,7 +341,7 @@ LineageSearchResult searchAcrossLineage( @Nonnull String input, @Nullable Integer maxHops, @Nullable Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int start, int count) throws RemoteInvocationException; @@ -355,7 +355,7 @@ LineageSearchResult searchAcrossLineage( * @param input the search input text * @param maxHops the max number of hops away to search for. If null, searches all hops. * @param filter the request map with fields and values as filters to be applied to search hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param scrollId opaque scroll ID indicating offset * @param keepAlive string representation of time to keep point in time alive, ex: 5m * @param count the number of search hits to return of roundtrips for UI visualizations. @@ -371,7 +371,7 @@ LineageScrollResult scrollAcrossLineage( @Nonnull String input, @Nullable Integer maxHops, @Nullable Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nonnull String keepAlive, int count) @@ -425,7 +425,7 @@ void deleteEntityReferences(@Nonnull OperationContext opContext, @Nonnull final * * @param entity filter entity * @param filter search filters - * @param sortCriterion sort criterion + * @param sortCriteria sort criteria * @param start start offset for search results * @param count max number of search results requested * @return a set of {@link SearchResult}s @@ -435,7 +435,7 @@ SearchResult filter( @Nonnull OperationContext opContext, @Nonnull String entity, @Nonnull Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int start, int count) throws RemoteInvocationException; diff --git a/metadata-service/restli-client/src/main/java/com/linkedin/entity/client/RestliEntityClient.java b/metadata-service/restli-client/src/main/java/com/linkedin/entity/client/RestliEntityClient.java index fe1ca571efea5..25097ee311cdb 100644 --- a/metadata-service/restli-client/src/main/java/com/linkedin/entity/client/RestliEntityClient.java +++ b/metadata-service/restli-client/src/main/java/com/linkedin/entity/client/RestliEntityClient.java @@ -62,6 +62,7 @@ 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.query.filter.SortCriterionArray; import com.linkedin.metadata.search.LineageScrollResult; import com.linkedin.metadata.search.LineageSearchResult; import com.linkedin.metadata.search.ScrollResult; @@ -98,6 +99,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.NotImplementedException; +import org.opensearch.core.common.util.CollectionUtils; @Slf4j public class RestliEntityClient extends BaseClient implements EntityClient { @@ -589,7 +591,7 @@ public ListResult list( * * @param input search query * @param filter search filters - * @param sortCriterion sort criterion + * @param sortCriteria sort criteria * @param start start offset for search results * @param count max number of search results requested * @return Snapshot key @@ -602,7 +604,7 @@ public SearchResult search( @Nonnull String entity, @Nonnull String input, @Nullable Filter filter, - SortCriterion sortCriterion, + List sortCriteria, int start, int count) throws RemoteInvocationException { @@ -620,8 +622,9 @@ public SearchResult search( requestBuilder.filterParam(filter); } - if (sortCriterion != null) { - requestBuilder.sortParam(sortCriterion); + if (!CollectionUtils.isEmpty(sortCriteria)) { + requestBuilder.sortParam(sortCriteria.get(0)); + requestBuilder.sortCriteriaParam(new SortCriterionArray(sortCriteria)); } if (searchFlags != null) { @@ -643,10 +646,10 @@ public SearchResult searchAcrossEntities( @Nullable Filter filter, int start, int count, - @Nullable SortCriterion sortCriterion) + List sortCriteria) throws RemoteInvocationException { return searchAcrossEntities( - opContext, entities, input, filter, start, count, sortCriterion, null); + opContext, entities, input, filter, start, count, sortCriteria, null); } /** @@ -670,7 +673,7 @@ public SearchResult searchAcrossEntities( @Nullable Filter filter, int start, int count, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable List facets) throws RemoteInvocationException { @@ -692,8 +695,9 @@ public SearchResult searchAcrossEntities( requestBuilder.searchFlagsParam(searchFlags); } - if (sortCriterion != null) { - requestBuilder.sortParam(sortCriterion); + if (!CollectionUtils.isEmpty(sortCriteria)) { + requestBuilder.sortParam(sortCriteria.get(0)); + requestBuilder.sortCriteriaParam(new SortCriterionArray(sortCriteria)); } return sendClientRequest(requestBuilder, opContext.getAuthentication()).getEntity(); @@ -743,7 +747,7 @@ public LineageSearchResult searchAcrossLineage( @Nonnull String input, @Nullable Integer maxHops, @Nullable Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int start, int count) throws RemoteInvocationException { @@ -770,6 +774,12 @@ public LineageSearchResult searchAcrossLineage( if (lineageFlags.getEndTimeMillis() != null) { requestBuilder.endTimeMillisParam(lineageFlags.getEndTimeMillis()); } + + if (!CollectionUtils.isEmpty(sortCriteria)) { + requestBuilder.sortParam(sortCriteria.get(0)); + requestBuilder.sortCriteriaParam(new SortCriterionArray(sortCriteria)); + } + requestBuilder.searchFlagsParam(opContext.getSearchContext().getSearchFlags()); return sendClientRequest(requestBuilder, opContext.getAuthentication()).getEntity(); @@ -785,7 +795,7 @@ public LineageScrollResult scrollAcrossLineage( @Nonnull String input, @Nullable Integer maxHops, @Nullable Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nonnull String keepAlive, int count) @@ -815,6 +825,12 @@ public LineageScrollResult scrollAcrossLineage( if (lineageFlags.getEndTimeMillis() != null) { requestBuilder.endTimeMillisParam(lineageFlags.getEndTimeMillis()); } + + if (!CollectionUtils.isEmpty(sortCriteria)) { + requestBuilder.sortParam(sortCriteria.get(0)); + requestBuilder.sortCriteriaParam(new SortCriterionArray(sortCriteria)); + } + requestBuilder.searchFlagsParam(opContext.getSearchContext().getSearchFlags()); return sendClientRequest(requestBuilder, opContext.getAuthentication()).getEntity(); @@ -903,7 +919,7 @@ public SearchResult filter( @Nonnull OperationContext opContext, @Nonnull String entity, @Nonnull Filter filter, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int start, int count) throws RemoteInvocationException { @@ -914,8 +930,9 @@ public SearchResult filter( .filterParam(filter) .startParam(start) .countParam(count); - if (sortCriterion != null) { - requestBuilder.sortParam(sortCriterion); + if (!CollectionUtils.isEmpty(sortCriteria)) { + requestBuilder.sortParam(sortCriteria.get(0)); + requestBuilder.sortCriteriaParam(new SortCriterionArray(sortCriteria)); } return sendClientRequest(requestBuilder, opContext.getAuthentication()).getEntity(); } diff --git a/metadata-service/restli-servlet-impl/build.gradle b/metadata-service/restli-servlet-impl/build.gradle index c1484f00efe59..6b68abfe7fb15 100644 --- a/metadata-service/restli-servlet-impl/build.gradle +++ b/metadata-service/restli-servlet-impl/build.gradle @@ -106,3 +106,6 @@ pegasus.main.idlOptions.addIdlItem([ ]) ext.apiProject = project(':metadata-service:restli-api') + +spotlessJava.dependsOn generateTestDataTemplate +spotlessJava.dependsOn generateIntegTestDataTemplate diff --git a/metadata-service/restli-servlet-impl/src/main/java/com/linkedin/metadata/resources/entity/EntityResource.java b/metadata-service/restli-servlet-impl/src/main/java/com/linkedin/metadata/resources/entity/EntityResource.java index 4ad668d0b1054..484e9653f8790 100644 --- a/metadata-service/restli-servlet-impl/src/main/java/com/linkedin/metadata/resources/entity/EntityResource.java +++ b/metadata-service/restli-servlet-impl/src/main/java/com/linkedin/metadata/resources/entity/EntityResource.java @@ -378,6 +378,7 @@ public Task search( @ActionParam(PARAM_INPUT) @Nonnull String input, @ActionParam(PARAM_FILTER) @Optional @Nullable Filter filter, @ActionParam(PARAM_SORT) @Optional @Nullable SortCriterion sortCriterion, + @ActionParam(PARAM_SORT_CRITERIA) @Optional @Nullable SortCriterion[] sortCriteria, @ActionParam(PARAM_START) int start, @ActionParam(PARAM_COUNT) int count, @Optional @Deprecated @Nullable @ActionParam(PARAM_FULLTEXT) Boolean fulltext, @@ -397,6 +398,8 @@ public Task search( RequestContext.builder().buildRestli(ACTION_SEARCH, entityName), authorizer, auth, true) .withSearchFlags(flags -> searchFlags != null ? searchFlags : new SearchFlags().setFulltext(Boolean.TRUE.equals(fulltext))); + List sortCriterionList = getSortCriteria(sortCriteria, sortCriterion); + log.info("GET SEARCH RESULTS for {} with query {}", entityName, input); // TODO - change it to use _searchService once we are confident on it's latency return RestliUtil.toTask( @@ -405,7 +408,7 @@ public Task search( // This API is not used by the frontend for search bars so we default to structured result = entitySearchService.search(opContext, - List.of(entityName), input, filter, sortCriterion, start, count); + List.of(entityName), input, filter, sortCriterionList, start, count); if (!isAPIAuthorizedResult( auth, @@ -428,6 +431,7 @@ public Task searchAcrossEntities( @ActionParam(PARAM_INPUT) @Nonnull String input, @ActionParam(PARAM_FILTER) @Optional @Nullable Filter filter, @ActionParam(PARAM_SORT) @Optional @Nullable SortCriterion sortCriterion, + @ActionParam(PARAM_SORT_CRITERIA) @Optional @Nullable SortCriterion[] sortCriteria, @ActionParam(PARAM_START) int start, @ActionParam(PARAM_COUNT) int count, @ActionParam(PARAM_SEARCH_FLAGS) @Optional SearchFlags searchFlags) { @@ -447,10 +451,12 @@ public Task searchAcrossEntities( HttpStatus.S_403_FORBIDDEN, "User is unauthorized to search."); } + List sortCriterionList = getSortCriteria(sortCriteria, sortCriterion); + log.info("GET SEARCH RESULTS ACROSS ENTITIES for {} with query {}", entityList, input); return RestliUtil.toTask( () -> { - SearchResult result = searchService.searchAcrossEntities(opContext, entityList, input, filter, sortCriterion, start, count); + SearchResult result = searchService.searchAcrossEntities(opContext, entityList, input, filter, sortCriterionList, start, count); if (!isAPIAuthorizedResult( auth, authorizer, @@ -463,6 +469,18 @@ public Task searchAcrossEntities( }); } + private List getSortCriteria(@Nullable SortCriterion[] sortCriteria, @Nullable SortCriterion sortCriterion) { + List sortCriterionList; + if (sortCriteria != null) { + sortCriterionList = Arrays.asList(sortCriteria); + } else if (sortCriterion != null) { + sortCriterionList = Collections.singletonList(sortCriterion); + } else { + sortCriterionList = Collections.emptyList(); + } + return sortCriterionList; + } + @Action(name = ACTION_SCROLL_ACROSS_ENTITIES) @Nonnull @WithSpan @@ -471,6 +489,7 @@ public Task scrollAcrossEntities( @ActionParam(PARAM_INPUT) @Nonnull String input, @ActionParam(PARAM_FILTER) @Optional @Nullable Filter filter, @ActionParam(PARAM_SORT) @Optional @Nullable SortCriterion sortCriterion, + @ActionParam(PARAM_SORT_CRITERIA) @Optional @Nullable SortCriterion[] sortCriteria, @ActionParam(PARAM_SCROLL_ID) @Optional @Nullable String scrollId, @ActionParam(PARAM_KEEP_ALIVE) String keepAlive, @ActionParam(PARAM_COUNT) int count, @@ -490,6 +509,8 @@ public Task scrollAcrossEntities( HttpStatus.S_403_FORBIDDEN, "User is unauthorized to search."); } + List sortCriterionList = getSortCriteria(sortCriteria, sortCriterion); + log.info( "GET SCROLL RESULTS ACROSS ENTITIES for {} with query {} and scroll ID: {}", entityList, @@ -503,7 +524,7 @@ public Task scrollAcrossEntities( entityList, input, filter, - sortCriterion, + sortCriterionList, scrollId, keepAlive, count); @@ -531,6 +552,7 @@ public Task searchAcrossLineage( @ActionParam(PARAM_MAX_HOPS) @Optional @Nullable Integer maxHops, @ActionParam(PARAM_FILTER) @Optional @Nullable Filter filter, @ActionParam(PARAM_SORT) @Optional @Nullable SortCriterion sortCriterion, + @ActionParam(PARAM_SORT_CRITERIA) @Optional @Nullable SortCriterion[] sortCriteria, @ActionParam(PARAM_START) int start, @ActionParam(PARAM_COUNT) int count, @ActionParam(PARAM_START_TIME_MILLIS) @Optional @Nullable Long startTimeMillis, @@ -546,6 +568,8 @@ public Task searchAcrossLineage( HttpStatus.S_403_FORBIDDEN, "User is unauthorized to search."); } + List sortCriterionList = getSortCriteria(sortCriteria, sortCriterion); + OperationContext opContext = OperationContext.asSession( systemOperationContext, RequestContext.builder().buildRestli(ACTION_SEARCH_ACROSS_LINEAGE, entities), authorizer, auth, true) .withSearchFlags(flags -> (searchFlags != null ? searchFlags : new SearchFlags().setFulltext(true)) @@ -570,7 +594,7 @@ public Task searchAcrossLineage( input, maxHops, filter, - sortCriterion, + sortCriterionList, start, count), entityService), @@ -588,6 +612,7 @@ public Task scrollAcrossLineage( @ActionParam(PARAM_MAX_HOPS) @Optional @Nullable Integer maxHops, @ActionParam(PARAM_FILTER) @Optional @Nullable Filter filter, @ActionParam(PARAM_SORT) @Optional @Nullable SortCriterion sortCriterion, + @ActionParam(PARAM_SORT_CRITERIA) @Optional @Nullable SortCriterion[] sortCriteria, @ActionParam(PARAM_SCROLL_ID) @Optional @Nullable String scrollId, @ActionParam(PARAM_KEEP_ALIVE) String keepAlive, @ActionParam(PARAM_COUNT) int count, @@ -622,6 +647,8 @@ public Task scrollAcrossLineage( entityList, input); + List sortCriterionList = getSortCriteria(sortCriteria, sortCriterion); + return RestliUtil.toTask( () -> validateLineageScrollResult(opContext, @@ -633,7 +660,7 @@ public Task scrollAcrossLineage( input, maxHops, filter, - sortCriterion, + sortCriterionList, scrollId, keepAlive, count), @@ -648,6 +675,7 @@ public Task list( @ActionParam(PARAM_ENTITY) @Nonnull String entityName, @ActionParam(PARAM_FILTER) @Optional @Nullable Filter filter, @ActionParam(PARAM_SORT) @Optional @Nullable SortCriterion sortCriterion, + @ActionParam(PARAM_SORT_CRITERIA) @Optional @Nullable SortCriterion[] sortCriteria, @ActionParam(PARAM_START) int start, @ActionParam(PARAM_COUNT) int count) { @@ -664,10 +692,12 @@ public Task list( systemOperationContext, RequestContext.builder().buildRestli(ACTION_LIST, entityName), authorizer, auth, true) .withSearchFlags(flags -> new SearchFlags().setFulltext(false)); + List sortCriterionList = getSortCriteria(sortCriteria, sortCriterion); + log.info("GET LIST RESULTS for {} with filter {}", entityName, filter); return RestliUtil.toTask( () -> { - SearchResult result = entitySearchService.filter(opContext, entityName, filter, sortCriterion, start, count); + SearchResult result = entitySearchService.filter(opContext, entityName, filter, sortCriterionList, start, count); if (!AuthUtil.isAPIAuthorizedResult( auth, authorizer, @@ -1159,6 +1189,7 @@ public Task filter( @ActionParam(PARAM_ENTITY) @Nonnull String entityName, @ActionParam(PARAM_FILTER) Filter filter, @ActionParam(PARAM_SORT) @Optional @Nullable SortCriterion sortCriterion, + @ActionParam(PARAM_SORT_CRITERIA) @Optional @Nullable SortCriterion[] sortCriteria, @ActionParam(PARAM_START) int start, @ActionParam(PARAM_COUNT) int count) { @@ -1172,10 +1203,13 @@ public Task filter( } OperationContext opContext = OperationContext.asSession( systemOperationContext, RequestContext.builder().buildRestli(ACTION_FILTER, entityName), authorizer, auth, true); + + List sortCriterionList = getSortCriteria(sortCriteria, sortCriterion); + log.info("FILTER RESULTS for {} with filter {}", entityName, filter); return RestliUtil.toTask( () -> { - SearchResult result = entitySearchService.filter(opContext.withSearchFlags(flags -> flags.setFulltext(true)), entityName, filter, sortCriterion, start, count); + SearchResult result = entitySearchService.filter(opContext.withSearchFlags(flags -> flags.setFulltext(true)), entityName, filter, sortCriterionList, start, count); if (!isAPIAuthorizedResult( auth, authorizer, diff --git a/metadata-service/restli-servlet-impl/src/main/java/com/linkedin/metadata/resources/restli/RestliConstants.java b/metadata-service/restli-servlet-impl/src/main/java/com/linkedin/metadata/resources/restli/RestliConstants.java index af6efb1ad8093..ef79a404c2145 100644 --- a/metadata-service/restli-servlet-impl/src/main/java/com/linkedin/metadata/resources/restli/RestliConstants.java +++ b/metadata-service/restli-servlet-impl/src/main/java/com/linkedin/metadata/resources/restli/RestliConstants.java @@ -24,6 +24,7 @@ private RestliConstants() {} public static final String PARAM_FILTER = "filter"; public static final String PARAM_GROUP = "group"; public static final String PARAM_SORT = "sort"; + public static final String PARAM_SORT_CRITERIA = "sortCriteria"; public static final String PARAM_QUERY = "query"; public static final String PARAM_FIELD = "field"; public static final String PARAM_PATH = "path"; diff --git a/metadata-service/restli-servlet-impl/src/test/java/mock/MockTimeseriesAspectService.java b/metadata-service/restli-servlet-impl/src/test/java/mock/MockTimeseriesAspectService.java index aaf90d279e0bd..7ed183e975f3b 100644 --- a/metadata-service/restli-servlet-impl/src/test/java/mock/MockTimeseriesAspectService.java +++ b/metadata-service/restli-servlet-impl/src/test/java/mock/MockTimeseriesAspectService.java @@ -137,7 +137,7 @@ public TimeseriesScrollResult scrollAspects( @Nonnull String entityName, @Nonnull String aspectName, @Nullable Filter filter, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, @Nullable String scrollId, int count, @Nullable Long startTimeMillis, diff --git a/metadata-service/services/src/main/java/com/linkedin/metadata/search/EntitySearchService.java b/metadata-service/services/src/main/java/com/linkedin/metadata/search/EntitySearchService.java index a3db4b029b68b..1b32ddc7c3ecb 100644 --- a/metadata-service/services/src/main/java/com/linkedin/metadata/search/EntitySearchService.java +++ b/metadata-service/services/src/main/java/com/linkedin/metadata/search/EntitySearchService.java @@ -80,7 +80,7 @@ void appendRunId( * @param input the search input text * @param postFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param from index to start the search from * @param size the number of search hits to return * @return a {@link SearchResult} that contains a list of matched documents and related search @@ -92,7 +92,7 @@ SearchResult search( @Nonnull List entityNames, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size); @@ -108,7 +108,7 @@ SearchResult search( * @param input the search input text * @param postFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param from index to start the search from * @param size the number of search hits to return * @param facets list of facets we want aggregations for @@ -121,7 +121,7 @@ SearchResult search( @Nonnull List entityNames, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size, @Nullable List facets); @@ -132,7 +132,7 @@ SearchResult search( * @param entityName name of the entity * @param filters the request map with fields and values to be applied as filters to the search * query - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param from index to start the search from * @param size number of search hits to return * @return a {@link SearchResult} that contains a list of filtered documents and related search @@ -143,7 +143,7 @@ SearchResult filter( @Nonnull OperationContext opContext, @Nonnull String entityName, @Nullable Filter filters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, int from, int size); @@ -265,7 +265,7 @@ List getBrowsePaths( * @param input the search input text * @param postFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param scrollId opaque scroll identifier to pass to search service * @param size the number of search hits to return * @return a {@link ScrollResult} that contains a list of matched documents and related search @@ -277,7 +277,7 @@ ScrollResult fullTextScroll( @Nonnull List entities, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size); @@ -290,7 +290,7 @@ ScrollResult fullTextScroll( * @param input the search input text * @param postFilters the request map with fields and values as filters to be applied to search * hits - * @param sortCriterion {@link SortCriterion} to be applied to search results + * @param sortCriteria list of {@link SortCriterion} to be applied to search results * @param scrollId opaque scroll identifier to pass to search service * @param size the number of search hits to return * @return a {@link ScrollResult} that contains a list of matched documents and related search @@ -302,7 +302,7 @@ ScrollResult structuredScroll( @Nonnull List entities, @Nonnull String input, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size); @@ -316,7 +316,7 @@ ExplainResponse explain( @Nonnull String documentId, @Nonnull String entityName, @Nullable Filter postFilters, - @Nullable SortCriterion sortCriterion, + List sortCriteria, @Nullable String scrollId, @Nullable String keepAlive, int size, diff --git a/metadata-service/services/src/main/java/com/linkedin/metadata/timeseries/TimeseriesAspectService.java b/metadata-service/services/src/main/java/com/linkedin/metadata/timeseries/TimeseriesAspectService.java index 6b1f484ac0a51..68c82f0ef2e0d 100644 --- a/metadata-service/services/src/main/java/com/linkedin/metadata/timeseries/TimeseriesAspectService.java +++ b/metadata-service/services/src/main/java/com/linkedin/metadata/timeseries/TimeseriesAspectService.java @@ -226,7 +226,7 @@ TimeseriesScrollResult scrollAspects( @Nonnull final String entityName, @Nonnull final String aspectName, @Nullable Filter filter, - @Nonnull List sortCriterion, + @Nonnull List sortCriteria, @Nullable String scrollId, int count, @Nullable Long startTimeMillis, From 7f06f6b1bb18b949a26f4bad180af4be20e62640 Mon Sep 17 00:00:00 2001 From: RyanHolstien Date: Tue, 25 Jun 2024 12:36:00 -0500 Subject: [PATCH 2/7] fix test --- .../resolvers/search/SearchAcrossEntitiesResolverTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolverTest.java index 770effa85ae1a..30d6f2dc6f283 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossEntitiesResolverTest.java @@ -438,7 +438,7 @@ public static void testApplyViewErrorFetchingView() throws Exception { Mockito.anyInt(), Mockito.anyInt(), Mockito.eq(Collections.emptyList()), - Mockito.eq(null))) + Mockito.eq(Collections.emptyList()))) .thenThrow(new RemoteInvocationException()); final SearchAcrossEntitiesResolver resolver = @@ -485,7 +485,7 @@ private static EntityClient initMockEntityClient( Mockito.eq(filter), Mockito.eq(start), Mockito.eq(limit), - Mockito.eq(null))) + Mockito.eq(Collections.emptyList()))) .thenReturn(result); return client; } From 79e6fe243efec85d87361f1906630e4cf51a66c4 Mon Sep 17 00:00:00 2001 From: RyanHolstien Date: Tue, 25 Jun 2024 13:15:30 -0500 Subject: [PATCH 3/7] make test less flakey --- .../java/com/linkedin/metadata/graph/GraphServiceTestBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metadata-io/src/test/java/com/linkedin/metadata/graph/GraphServiceTestBase.java b/metadata-io/src/test/java/com/linkedin/metadata/graph/GraphServiceTestBase.java index 1aebc48153bbe..d3e554c95fe3a 100644 --- a/metadata-io/src/test/java/com/linkedin/metadata/graph/GraphServiceTestBase.java +++ b/metadata-io/src/test/java/com/linkedin/metadata/graph/GraphServiceTestBase.java @@ -2191,7 +2191,7 @@ public void testHighlyConnectedGraphWalk() throws Exception { relationships.stream() .flatMap(relationship -> relationship.getDegrees().stream()) .reduce(0, Math::max); - assertTrue(maxDegree > 1); + assertTrue(maxDegree >= 1); EntityLineageResult lineageResultMulti = getGraphService(true) From 4616f7fae0db6cd2aec303ac79c027bd6fdfdca8 Mon Sep 17 00:00:00 2001 From: RyanHolstien Date: Wed, 7 Aug 2024 13:53:44 -0500 Subject: [PATCH 4/7] missing import --- .../openapi/operations/elastic/OperationsController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/operations/elastic/OperationsController.java b/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/operations/elastic/OperationsController.java index 1e2ddcf9ec9d7..ea72bac73edf3 100644 --- a/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/operations/elastic/OperationsController.java +++ b/metadata-service/openapi-servlet/src/main/java/io/datahubproject/openapi/operations/elastic/OperationsController.java @@ -20,6 +20,7 @@ import com.linkedin.metadata.entity.restoreindices.RestoreIndicesResult; import com.linkedin.metadata.query.SearchFlags; import com.linkedin.metadata.query.filter.Filter; +import com.linkedin.metadata.query.filter.SortCriterion; import com.linkedin.metadata.search.EntitySearchService; import com.linkedin.metadata.systemmetadata.SystemMetadataService; import com.linkedin.metadata.timeseries.TimeseriesAspectService; From 378a325521a47730b185c679e70985c76303dc95 Mon Sep 17 00:00:00 2001 From: RyanHolstien Date: Wed, 7 Aug 2024 14:35:52 -0500 Subject: [PATCH 5/7] fix test --- .../openapi/v3/controller/EntityControllerTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/metadata-service/openapi-servlet/src/test/java/io/datahubproject/openapi/v3/controller/EntityControllerTest.java b/metadata-service/openapi-servlet/src/test/java/io/datahubproject/openapi/v3/controller/EntityControllerTest.java index 3c7e93621f5cc..55afc3ef65479 100644 --- a/metadata-service/openapi-servlet/src/test/java/io/datahubproject/openapi/v3/controller/EntityControllerTest.java +++ b/metadata-service/openapi-servlet/src/test/java/io/datahubproject/openapi/v3/controller/EntityControllerTest.java @@ -37,6 +37,7 @@ import io.datahubproject.metadata.context.OperationContext; import io.datahubproject.openapi.config.SpringWebConfig; import io.datahubproject.test.metadata.context.TestOperationContexts; +import java.util.Collections; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; @@ -95,7 +96,7 @@ public void testSearchOrderPreserved() throws Exception { eq(List.of("dataset")), anyString(), nullable(Filter.class), - eq(SearchUtil.sortBy("urn", SortOrder.valueOf("ASCENDING"))), + eq(Collections.singletonList(SearchUtil.sortBy("urn", SortOrder.valueOf("ASCENDING")))), nullable(String.class), nullable(String.class), anyInt())) @@ -113,7 +114,7 @@ public void testSearchOrderPreserved() throws Exception { eq(List.of("dataset")), anyString(), nullable(Filter.class), - eq(SearchUtil.sortBy("urn", SortOrder.valueOf("DESCENDING"))), + eq(Collections.singletonList(SearchUtil.sortBy("urn", SortOrder.valueOf("DESCENDING")))), nullable(String.class), nullable(String.class), anyInt())) From 22567fe0fa3a0452b09d892e9eebf997ae6fa358 Mon Sep 17 00:00:00 2001 From: RyanHolstien Date: Fri, 9 Aug 2024 12:55:43 -0500 Subject: [PATCH 6/7] spotless --- .../openapi/v3/controller/EntityControllerTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/metadata-service/openapi-servlet/src/test/java/io/datahubproject/openapi/v3/controller/EntityControllerTest.java b/metadata-service/openapi-servlet/src/test/java/io/datahubproject/openapi/v3/controller/EntityControllerTest.java index 55afc3ef65479..60425fc7e756e 100644 --- a/metadata-service/openapi-servlet/src/test/java/io/datahubproject/openapi/v3/controller/EntityControllerTest.java +++ b/metadata-service/openapi-servlet/src/test/java/io/datahubproject/openapi/v3/controller/EntityControllerTest.java @@ -114,7 +114,9 @@ public void testSearchOrderPreserved() throws Exception { eq(List.of("dataset")), anyString(), nullable(Filter.class), - eq(Collections.singletonList(SearchUtil.sortBy("urn", SortOrder.valueOf("DESCENDING")))), + eq( + Collections.singletonList( + SearchUtil.sortBy("urn", SortOrder.valueOf("DESCENDING")))), nullable(String.class), nullable(String.class), anyInt())) From bc6a7b77007daec1eef1ea86fd6b70def59be78e Mon Sep 17 00:00:00 2001 From: RyanHolstien Date: Fri, 9 Aug 2024 14:43:38 -0500 Subject: [PATCH 7/7] fix lightning tests --- .../java/com/linkedin/metadata/search/LineageSearchService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/LineageSearchService.java b/metadata-io/src/main/java/com/linkedin/metadata/search/LineageSearchService.java index df38813781386..d07882963e281 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/LineageSearchService.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/LineageSearchService.java @@ -318,7 +318,7 @@ boolean canDoLightning( return (lineageRelationships.size() > cacheConfiguration.getLightningThreshold()) && input.equals("*") && simpleFilters - && CollectionUtils.isNotEmpty(sortCriteria); + && CollectionUtils.isEmpty(sortCriteria); } @VisibleForTesting