Skip to content

[elc] add support for sorting results by SortOptions to NativeQuery #2264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.springframework.data.elasticsearch.client.elc;

import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.search.FieldCollapse;
Expand All @@ -26,7 +27,6 @@
import java.util.Map;

import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.RescorerQuery;
import org.springframework.data.elasticsearch.core.query.ScriptedField;
import org.springframework.lang.Nullable;

Expand All @@ -35,6 +35,7 @@
* Elasticsearch Client library.
*
* @author Peter-Josef Meisch
* @author Sascha Woo
* @since 4.4
*/
public class NativeQuery extends BaseQuery {
Expand All @@ -46,6 +47,7 @@ public class NativeQuery extends BaseQuery {
@Nullable private Suggester suggester;
@Nullable private FieldCollapse fieldCollapse;
private List<ScriptedField> scriptedFields = Collections.emptyList();
private List<SortOptions> sortOptions = Collections.emptyList();

public NativeQuery(NativeQueryBuilder builder) {
super(builder);
Expand All @@ -55,6 +57,7 @@ public NativeQuery(NativeQueryBuilder builder) {
this.suggester = builder.getSuggester();
this.fieldCollapse = builder.getFieldCollapse();
this.scriptedFields = builder.getScriptedFields();
this.sortOptions = builder.getSortOptions();
}

public NativeQuery(@Nullable Query query) {
Expand Down Expand Up @@ -92,4 +95,8 @@ public FieldCollapse getFieldCollapse() {
public List<ScriptedField> getScriptedFields() {
return scriptedFields;
}

public List<SortOptions> getSortOptions() {
return sortOptions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,29 @@
*/
package org.springframework.data.elasticsearch.client.elc;

import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.search.FieldCollapse;
import co.elastic.clients.elasticsearch.core.search.Suggester;
import co.elastic.clients.util.ObjectBuilder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import org.springframework.data.elasticsearch.core.query.BaseQueryBuilder;
import org.springframework.data.elasticsearch.core.query.RescorerQuery;
import org.springframework.data.elasticsearch.core.query.ScriptedField;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
* @author Peter-Josef Meisch
* @author Sascha Woo
* @since 4.4
*/
public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQueryBuilder> {
Expand All @@ -45,7 +48,10 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
@Nullable private Suggester suggester;
@Nullable private FieldCollapse fieldCollapse;
private final List<ScriptedField> scriptedFields = new ArrayList<>();
public NativeQueryBuilder() {}
private List<SortOptions> sortOptions = new ArrayList<>();

public NativeQueryBuilder() {
}

@Nullable
public Query getQuery() {
Expand Down Expand Up @@ -75,6 +81,10 @@ public List<ScriptedField> getScriptedFields() {
return scriptedFields;
}

public List<SortOptions> getSortOptions() {
return sortOptions;
}

public NativeQueryBuilder withQuery(Query query) {

Assert.notNull(query, "query must not be null");
Expand Down Expand Up @@ -129,6 +139,34 @@ public NativeQueryBuilder withScriptedField(ScriptedField scriptedField) {
return this;
}

public NativeQueryBuilder withSort(List<SortOptions> values) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we name them withSortOptions()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no strong opinion on this, but the BaseQueryBuilder also had a method withSort and the SearchRequest.Builder has a method called sort.


Assert.notEmpty(values, "values must not be empty");
sortOptions.clear();
sortOptions.addAll(values);

return this;
}

public NativeQueryBuilder withSort(SortOptions value, SortOptions... values) {

Assert.notNull(value, "value must not be null");
sortOptions.add(value);
if (values.length > 0) {
sortOptions.addAll(Arrays.asList(values));
}

return this;
}

public NativeQueryBuilder withSort(Function<SortOptions.Builder, ObjectBuilder<SortOptions>> fn) {

Assert.notNull(fn, "fn must not be null");
withSort(fn.apply(new SortOptions.Builder()).build());

return this;
}

public NativeQuery build() {
return new NativeQuery(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
* Class to create Elasticsearch request and request builders.
*
* @author Peter-Josef Meisch
* @author Sascha Woo
* @since 4.4
*/
class RequestConverter {
Expand Down Expand Up @@ -1405,7 +1406,7 @@ private void prepareNativeSearch(NativeQuery query, SearchRequest.Builder builde
builder //
.suggest(query.getSuggester()) //
.collapse(query.getFieldCollapse()) //
;
.sort(query.getSortOptions());

if (!isEmpty(query.getAggregations())) {
builder.aggregations(query.getAggregations());
Expand All @@ -1424,7 +1425,7 @@ private void prepareNativeSearch(NativeQuery query, MultisearchBody.Builder buil
builder //
.suggest(query.getSuggester()) //
.collapse(query.getFieldCollapse()) //
;
.sort(query.getSortOptions());

if (!isEmpty(query.getAggregations())) {
builder.aggregations(query.getAggregations());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,34 @@
*/
package org.springframework.data.elasticsearch.core;

import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.elasticsearch.client.elc.QueryBuilders.*;
import static org.springframework.data.elasticsearch.utils.IndexBuilder.*;

import co.elastic.clients.elasticsearch._types.SortOptionsBuilders;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.FunctionBoostMode;
import co.elastic.clients.elasticsearch._types.query_dsl.FunctionScoreMode;
import co.elastic.clients.elasticsearch.core.search.FieldCollapse;
import co.elastic.clients.json.JsonData;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.elasticsearch.ELCQueries;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.BaseQueryBuilder;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilterBuilder;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.RescorerQuery;
import org.springframework.data.elasticsearch.core.query.ScriptData;
Expand All @@ -45,6 +54,7 @@

/**
* @author Farid Faoudi
* @author Sascha Woo
* @since 4.4
*/
@ContextConfiguration(classes = { ElasticsearchELCIntegrationTests.Config.class })
Expand All @@ -60,6 +70,33 @@ IndexNameProvider indexNameProvider() {
}
}

@Test // #2263
public void shouldSortResultsBySortOptions() {

List<IndexQuery> indexQueries = new ArrayList<>();

indexQueries.add(buildIndex(SampleEntity.builder().id("1").message("ab xz").build()));
indexQueries.add(buildIndex(SampleEntity.builder().id("2").message("bc").build()));
indexQueries.add(buildIndex(SampleEntity.builder().id("3").message("ac xz hi").build()));

operations.bulkIndex(indexQueries, IndexCoordinates.of(indexNameProvider.indexName()));

NativeQuery query = NativeQuery.builder()
.withSort(b -> b.field(fb -> fb.field("message").order(SortOrder.Asc))).build();

SearchHits<SampleEntity> searchHits = operations.search(query, SampleEntity.class,
IndexCoordinates.of(indexNameProvider.indexName()));

assertThat(searchHits.getSearchHits()) //
.satisfiesExactly(e -> {
assertThat(e.getId()).isEqualTo("1");
}, e -> {
assertThat(e.getId()).isEqualTo("3");
}, e -> {
assertThat(e.getId()).isEqualTo("2");
});
}

@Override
public boolean newElasticsearchClient() {
return true;
Expand Down