Skip to content

Commit 36f0907

Browse files
authored
DATAES-866 - Implement suggest query in reactive client.
Original PR: spring-projects#483
1 parent 7cd871a commit 36f0907

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-0
lines changed

src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
import org.elasticsearch.search.SearchHit;
9797
import org.elasticsearch.search.SearchHits;
9898
import org.elasticsearch.search.aggregations.Aggregation;
99+
import org.elasticsearch.search.suggest.Suggest;
99100
import org.reactivestreams.Publisher;
100101

101102
import org.springframework.data.elasticsearch.client.ClientConfiguration;
@@ -132,6 +133,7 @@
132133
* @author Henrique Amaral
133134
* @author Roman Puchkovskiy
134135
* @author Russell Parry
136+
* @author Thomas Geese
135137
* @since 3.2
136138
* @see ClientConfiguration
137139
* @see ReactiveRestClients
@@ -890,6 +892,12 @@ private static ElasticsearchException getElasticsearchException(String content,
890892
}
891893
}
892894

895+
@Override
896+
public Flux<Suggest> suggest(HttpHeaders headers, SearchRequest searchRequest) {
897+
return sendRequest(searchRequest, requestCreator.search(), SearchResponse.class, headers) //
898+
.map(SearchResponse::getSuggest);
899+
}
900+
893901
private static void buildExceptionMessages(StringBuilder sb, Throwable t) {
894902

895903
sb.append(t.getMessage());

src/main/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClient.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
5353
import org.elasticsearch.search.SearchHit;
5454
import org.elasticsearch.search.aggregations.Aggregation;
55+
import org.elasticsearch.search.suggest.Suggest;
5556
import org.springframework.data.elasticsearch.client.ClientConfiguration;
5657
import org.springframework.data.elasticsearch.client.ElasticsearchHost;
5758
import org.springframework.http.HttpHeaders;
@@ -67,6 +68,7 @@
6768
* @author Mark Paluch
6869
* @author Peter-Josef Meisch
6970
* @author Henrique Amaral
71+
* @author Thomas Geese
7072
* @since 3.2
7173
* @see ClientConfiguration
7274
* @see ReactiveRestClients
@@ -417,6 +419,27 @@ default Flux<SearchHit> search(SearchRequest searchRequest) {
417419
*/
418420
Flux<SearchHit> search(HttpHeaders headers, SearchRequest searchRequest);
419421

422+
/**
423+
* Execute the given {@link SearchRequest} against the {@literal search} API.
424+
*
425+
* @param searchRequest must not be {@literal null}.
426+
* @return the {@link Flux} emitting {@link Suggest suggestions} one by one.
427+
* @since 4.1
428+
*/
429+
default Flux<Suggest> suggest(SearchRequest searchRequest) {
430+
return suggest(HttpHeaders.EMPTY, searchRequest);
431+
}
432+
433+
/**
434+
* Execute the given {@link SearchRequest} against the {@literal search} API.
435+
*
436+
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
437+
* @param searchRequest must not be {@literal null}.
438+
* @return the {@link Flux} emitting {@link Suggest suggestions} one by one.
439+
* @since 4.1
440+
*/
441+
Flux<Suggest> suggest(HttpHeaders headers, SearchRequest searchRequest);
442+
420443
/**
421444
* Execute the given {@link SearchRequest} with aggregations against the {@literal search} API.
422445
*

src/main/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchTemplate.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import org.elasticsearch.index.reindex.BulkByScrollResponse;
4242
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
4343
import org.elasticsearch.search.aggregations.Aggregation;
44+
import org.elasticsearch.search.suggest.Suggest;
45+
import org.elasticsearch.search.suggest.SuggestBuilder;
4446
import org.reactivestreams.Publisher;
4547
import org.slf4j.Logger;
4648
import org.slf4j.LoggerFactory;
@@ -90,6 +92,7 @@
9092
* @author Aleksei Arsenev
9193
* @author Roman Puchkovskiy
9294
* @author Russell Parry
95+
* @author Thomas Geese
9396
* @since 3.2
9497
*/
9598
public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOperations, ApplicationContextAware {
@@ -640,6 +643,23 @@ public Flux<Aggregation> aggregate(Query query, Class<?> entityType, IndexCoordi
640643
return doAggregate(query, entityType, index);
641644
}
642645

646+
@Override
647+
public Flux<Suggest> suggest(SuggestBuilder suggestion, Class<?> entityType) {
648+
return suggest(suggestion, getIndexCoordinatesFor(entityType));
649+
}
650+
651+
@Override
652+
public Flux<Suggest> suggest(SuggestBuilder suggestion, IndexCoordinates index) {
653+
return doSuggest(suggestion, index);
654+
}
655+
656+
private Flux<Suggest> doSuggest(SuggestBuilder suggestion, IndexCoordinates index) {
657+
return Flux.defer(() -> {
658+
SearchRequest request = requestFactory.searchRequest(suggestion, index);
659+
return Flux.from(execute(client -> client.suggest(request)));
660+
});
661+
}
662+
643663
private Flux<Aggregation> doAggregate(Query query, Class<?> entityType, IndexCoordinates index) {
644664
return Flux.defer(() -> {
645665
SearchRequest request = requestFactory.searchRequest(query, entityType, index);

src/main/java/org/springframework/data/elasticsearch/core/ReactiveSearchOperations.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
import org.elasticsearch.index.query.QueryBuilders;
2222
import org.elasticsearch.search.aggregations.Aggregation;
23+
import org.elasticsearch.search.suggest.Suggest;
24+
import org.elasticsearch.search.suggest.SuggestBuilder;
2325
import org.springframework.data.domain.Pageable;
2426
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
2527
import org.springframework.data.elasticsearch.core.query.Query;
@@ -32,6 +34,7 @@
3234
*
3335
* @author Peter-Josef Meisch
3436
* @author Russell Parry
37+
* @author Thomas Geese
3538
* @since 4.0
3639
*/
3740
public interface ReactiveSearchOperations {
@@ -206,4 +209,22 @@ default <T> Flux<SearchHit<T>> search(Query query, Class<T> entityType, IndexCoo
206209
* @since 4.0
207210
*/
208211
Flux<Aggregation> aggregate(Query query, Class<?> entityType, IndexCoordinates index);
212+
213+
/**
214+
* Does a suggest query
215+
*
216+
* @param suggestion the query
217+
* @param entityType must not be {@literal null}.
218+
* @return the suggest response
219+
*/
220+
Flux<Suggest> suggest(SuggestBuilder suggestion, Class<?> entityType);
221+
222+
/**
223+
* Does a suggest query
224+
*
225+
* @param suggestion the query
226+
* @param index the index to run the query against
227+
* @return the suggest response
228+
*/
229+
Flux<Suggest> suggest(SuggestBuilder suggestion, IndexCoordinates index);
209230
}

src/test/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClientTests.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
import org.elasticsearch.search.aggregations.AggregationBuilders;
5454
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
5555
import org.elasticsearch.search.builder.SearchSourceBuilder;
56+
import org.elasticsearch.search.suggest.SuggestBuilder;
57+
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
5658
import org.junit.jupiter.api.AfterEach;
5759
import org.junit.jupiter.api.BeforeEach;
5860
import org.junit.jupiter.api.Test;
@@ -71,6 +73,7 @@
7173
* @author Peter-Josef Meisch
7274
* @author Henrique Amaral
7375
* @author Russell Parry
76+
* @author Thomas Geese
7477
*/
7578
@SpringIntegrationTest
7679
@ContextConfiguration(classes = { ElasticsearchRestTemplateConfiguration.class })
@@ -681,6 +684,32 @@ public void aggregateReturnsAggregationResults() throws IOException {
681684
.expectNextMatches(aggregation -> aggregation.getType().equals(StringTerms.NAME)).verifyComplete();
682685
}
683686

687+
@Test // DATAES-866
688+
public void suggestReturnsSuggestionResults() throws IOException {
689+
syncClient.indices().create(new CreateIndexRequest(INDEX_I), RequestOptions.DEFAULT);
690+
Map<String, Object> jsonMap = Collections.singletonMap("properties",
691+
Collections.singletonMap("firstname", Collections.singletonMap("type", "completion")));
692+
syncClient.indices().putMapping(new PutMappingRequest(INDEX_I).source(jsonMap), RequestOptions.DEFAULT);
693+
694+
addSourceDocument().ofType(TYPE_I).to(INDEX_I);
695+
696+
SuggestBuilder suggestBuilder = new SuggestBuilder().addSuggestion(
697+
"firstname",
698+
new CompletionSuggestionBuilder("firstname").prefix("ch")
699+
);
700+
701+
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
702+
searchSourceBuilder.suggest(suggestBuilder);
703+
704+
SearchRequest request = new SearchRequest(INDEX_I) //
705+
.source(searchSourceBuilder);
706+
707+
client
708+
.suggest(request).as(StepVerifier::create).expectNextMatches(suggestions -> suggestions
709+
.getSuggestion("firstname").getEntries().get(0).getOptions().get(0).getText().string().equals("chade"))
710+
.verifyComplete();
711+
}
712+
684713
private AddToIndexOfType addSourceDocument() {
685714
return add(DOC_SOURCE);
686715
}

0 commit comments

Comments
 (0)