diff --git a/pom.xml b/pom.xml index 9a461c297..b48d4489e 100644 --- a/pom.xml +++ b/pom.xml @@ -22,11 +22,14 @@ 7.17.4 8.2.3 + 2.17.2 4.1.65.Final + 3.0.0-SNAPSHOT 1.16.2 1.0.6.RELEASE + spring.data.elasticsearch + org.elasticsearch.client elasticsearch-rest-high-level-client ${elasticsearch-rhlc} + true commons-logging diff --git a/src/main/asciidoc/preface.adoc b/src/main/asciidoc/preface.adoc index 2adb3beae..fef63b845 100644 --- a/src/main/asciidoc/preface.adoc +++ b/src/main/asciidoc/preface.adoc @@ -49,4 +49,5 @@ built and tested. | Ingallsfootnote:oom[] | 2.1.xfootnote:oom[] | 2.4.0 | 4.3.25 | 1.5.x |=== -Support for upcoming versions of Elasticsearch is being tracked and general compatibility should be given assuming the usage of the <>. +Support for upcoming versions of Elasticsearch is being tracked and general compatibility should be given assuming +the usage of the <>. diff --git a/src/main/asciidoc/reference/elasticsearch-clients.adoc b/src/main/asciidoc/reference/elasticsearch-clients.adoc index f4e56419f..aa79e0a9c 100644 --- a/src/main/asciidoc/reference/elasticsearch-clients.adoc +++ b/src/main/asciidoc/reference/elasticsearch-clients.adoc @@ -6,15 +6,104 @@ This chapter illustrates configuration and usage of supported Elasticsearch clie Spring Data Elasticsearch operates upon an Elasticsearch client that is connected to a single Elasticsearch node or a cluster. Although the Elasticsearch Client can be used to work with the cluster, applications using Spring Data Elasticsearch normally use the higher level abstractions of <> and <>. -[[elasticsearch.clients.rest]] -== High Level REST Client +[[elasticsearch.clients.restclient]] +== Imperative Rest Client -The Java High Level REST Client is the default client of Elasticsearch, it is configured like shown: +To use the imperative (non-reactive) client, a configuration bean must be configured like this: -.High Level REST Client ==== [source,java] ---- +import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration; + +@Configuration +public class MyClientConfig extends ElasticsearchConfiguration { + + @Override + public ClientConfiguration clientConfiguration() { + return ClientConfiguration.builder() // + .connectedTo("localhost:9200") // + .build(); + } +} + +// ... + +@Autowired +ElasticsearchOperations operations; <.> + +@Autowired +ElasticsearchClient elasticsearchClient; <.> + +@Autowired +RestClient restClient; <.> +---- +the following can be injected: + +<.> an implementation of `ElasticsearchOperations` +<.> the `co.elastic.clients.elasticsearch.ElasticsearchClient` that is used. This is new Elasticsearch client +implementation. +<.> the low level `RestClient` from the Elasticsearch libraries +==== + +Basically one should just use the `ElasticsearchOperations` to interact with the Elasticsearch cluster. When using +repositories, this instance is used under the hood as well. + +[[elasticsearch.clients.reactiverestclient]] +== Reactive Rest Client + +When working with the reactive stack, the configuration must be derived from a different class: + +==== +[source,java] +---- +import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchConfiguration; + +@Configuration +public class MyClientConfig extends ElasticsearchConfiguration { + + @Override + public ClientConfiguration clientConfiguration() { + return ClientConfiguration.builder() // + .connectedTo("localhost:9200") // + .build(); + } +} + +// ... + +@Autowired +ReactiveElasticsearchOperations operations; <.> + +@Autowired +ReactiveElasticsearchClient elasticsearchClient; <.> + +@Autowired +RestClient restClient; <.> +---- +the following can be injected: + +<.> an implementation of `ElasticsearchOperations` +<.> the `org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient` that is used. This is based +on the new Elasticsearch client implementation. +<.> the low level `RestClient` from the Elasticsearch libraries +==== + +Basically one should just use the `ReactiveElasticsearchOperations` to interact with the Elasticsearch cluster. When +using repositories, this instance is used under the hood as well. + +[[elasticsearch.clients.resthighlevelclient]] +== High Level REST Client (deprecated) + +The Java RestHighLevelClient is deprecated, but still can be configured like shown (read +<> as well): + +.RestHighLevelClient +==== +[source,java] +---- +import org.springframework.data.elasticsearch.client.erhlc.AbstractElasticsearchConfiguration; + @Configuration public class RestClientConfig extends AbstractElasticsearchConfiguration { @@ -53,16 +142,21 @@ IndexResponse response = highLevelClient.index(request,RequestOptions.DEFAULT); ==== [[elasticsearch.clients.reactive]] -== Reactive Client +== Reactive Client (deprecated) -The `ReactiveElasticsearchClient` is a non official driver based on `WebClient`. +The `org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient` is a non official driver based on `WebClient`. It uses the request/response objects provided by the Elasticsearch core project. Calls are directly operated on the reactive stack, **not** wrapping async (thread pool bound) responses into reactive types. -.Reactive REST Client +This was the first reactive implementation Spring Data Elasticsearch provided, but now is deprecated in favour of the `org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient` +which uses the functionality offered by the new Elasticsearch client libraries. + +.Reactive REST Client (deprecated) ==== [source,java] ---- +import org.springframework.data.elasticsearch.client.erhlc.AbstractReactiveElasticsearchConfiguration; + @Configuration public class ReactiveRestClientConfig extends AbstractReactiveElasticsearchConfiguration { @@ -89,8 +183,6 @@ Mono response = client.index(request -> <.> Use the builder to provide cluster addresses, set default `HttpHeaders` or enable SSL. ==== -NOTE: The ReactiveClient response, especially for search operations, is bound to the `from` (offset) & `size` (limit) options of the request. - [[elasticsearch.clients.configuration]] == Client Configuration @@ -118,12 +210,7 @@ ClientConfiguration clientConfiguration = ClientConfiguration.builder() return headers; }) .withClientConfigurer( <.> - ReactiveRestClients.WebClientConfigurationCallback.from(webClient -> { - // ... - return webClient; - })) - .withClientConfigurer( <.> - RestClients.RestClientConfigurationCallback.from(clientBuilder -> { + ElasticsearchClients.ElasticsearchClientConfigurationCallback.from(clientBuilder -> { // ... return clientBuilder; })) @@ -144,8 +231,7 @@ Default is 5 sec. <.> Optionally set headers. <.> Add basic authentication. <.> A `Supplier
` function can be specified which is called every time before a request is sent to Elasticsearch - here, as an example, the current time is written in a header. -<.> for reactive setup a function configuring the `WebClient` -<.> for non-reactive setup a function configuring the REST client +<.> a function configuring the low level REST client (the same for the imperative and reactive stack) ==== IMPORTANT: Adding a Header supplier as shown in above example allows to inject headers that may change over the time, like authentication JWT tokens. @@ -153,7 +239,7 @@ If this is used in the reactive setup, the supplier function *must not* block! === Elasticsearch 7 compatibility headers -When using Spring Data Elasticsearch 4 - which uses the Elasticsearch 7 client libraries - and accessing an Elasticsearch cluster that is running on version 8, it is necessary to set the compatibility headers +When using the deprecated `RestHighLevelClient` and accessing an Elasticsearch cluster that is running on version 8, it is necessary to set the compatibility headers https://www.elastic.co/guide/en/elasticsearch/reference/8.0/rest-api-compatibility.html[see Elasticsearch documentation]. diff --git a/src/main/asciidoc/reference/elasticsearch-join-types.adoc b/src/main/asciidoc/reference/elasticsearch-join-types.adoc index d588ee278..2af07748a 100644 --- a/src/main/asciidoc/reference/elasticsearch-join-types.adoc +++ b/src/main/asciidoc/reference/elasticsearch-join-types.adoc @@ -211,7 +211,7 @@ void init() { == Retrieving data -Currently native search queries must be used to query the data, so there is no support from standard repository methods. <> can be used instead. +Currently native queries must be used to query the data, so there is no support from standard repository methods. <> can be used instead. The following code shows as an example how to retrieve all entries that have a _vote_ (which must be _answers_, because only answers can have a vote) using an `ElasticsearchOperations` instance: @@ -219,11 +219,17 @@ The following code shows as an example how to retrieve all entries that have a _ [source,java] ---- SearchHits hasVotes() { - NativeSearchQuery query = new NativeSearchQueryBuilder() - .withQuery(hasChildQuery("vote", matchAllQuery(), ScoreMode.None)) - .build(); - return operations.search(query, Statement.class); + Query query = NativeQuery.builder() + .withQuery(co.elastic.clients.elasticsearch._types.query_dsl.Query.of(qb -> qb // + .hasChild(hc -> hc + .queryName("vote") // + .query(matchAllQueryAsQuery()) // + .scoreMode(ChildScoreMode.None)// + ))) + .build(); + + return operations.search(query, Statement.class); } ---- ==== diff --git a/src/main/asciidoc/reference/elasticsearch-migration-guide-4.4-5.0.adoc b/src/main/asciidoc/reference/elasticsearch-migration-guide-4.4-5.0.adoc index d914eb812..d4549f488 100644 --- a/src/main/asciidoc/reference/elasticsearch-migration-guide-4.4-5.0.adoc +++ b/src/main/asciidoc/reference/elasticsearch-migration-guide-4.4-5.0.adoc @@ -32,6 +32,11 @@ using the old deprecated Elasticsearch libraries, code using the new Elasticsear independent of the client implementation. Also the reactive implementation that was provided up to now has been moved here, as this implementation contains code that was copied and adapted from Elasticsearch libraries. +If you are using `ElasticsearchRestTemplate` directly and not the `ElasticsearchOperations` interface you'll need to +adjust your imports as well. + +When working with the `NativeSearchQuery` class, you'll need to switch to the `NativeQuery` class, which can take a +`Query` instance comign from the new Elasticsearch client libraries. You'll find plenty of examples in the test code. [[elasticsearch-migration-guide-4.4-5.0.new-clients]] == New Elasticsearch client @@ -39,58 +44,7 @@ here, as this implementation contains code that was copied and adapted from Elas Spring Data Elasticsearch now uses the new `ElasticsearchClient` and has deprecated the use of the previous `RestHighLevelClient`. -=== How to use the new client - -In order to use the new client the following steps are necessary: - -==== Add dependencies - -The dependencies for the new Elasticsearch client are still optional in Spring Data Elasticsearch so they need to be added explicitly: - -==== -[source,xml] ----- - - - co.elastic.clients - elasticsearch-java - 7.17.3 - - - commons-logging - commons-logging - - - - - org.elasticsearch.client - elasticsearch-rest-client - 7.17.3 - - - commons-logging - commons-logging - - - - ----- -==== - -When using Spring Boot, it is necessary to set the following property in the _pom.xml_. - -==== -[source,xml] ----- - - 2.0.1 - ----- -==== - -==== New configuration classes - -===== Imperative style +=== Imperative style configuration To configure Spring Data Elasticsearch to use the new client, it is necessary to create a configuration bean that derives from `org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration`: @@ -118,7 +72,7 @@ With this configuration, the following beans will be available in the Spring app * an `ElasticsearchClient` bean, this is the new client that uses the `RestClient` * an `ElasticsearchOperations` bean, available with the bean names _elasticsearchOperations_ and _elasticsearchTemplate_, this uses the `ElasticsearchClient` -===== Reactive style +=== Reactive style configuration To use the new client in a reactive environment the only difference is the class from which to derive the configuration: @@ -143,3 +97,29 @@ With this configuration, the following beans will be available in the Spring app * a `RestClient` bean, that is the configured low level `RestClient` that is used by the Elasticsearch client * an `ReactiveElasticsearchClient` bean, this is the new reactive client that uses the `RestClient` * an `ReactiveElasticsearchOperations` bean, available with the bean names _reactiveElasticsearchOperations_ and _reactiveElasticsearchTemplate_, this uses the `ReactiveElasticsearchClient` + +[[elasticsearch-migration-guide-4.4-5.0.old-client]] +=== Still want to use the old client? + +The old deprecated `RestHighLevelClient` can still be used, but you will need to add the dependency explicitly to +your application as Spring Data Elasticsearch does not pull it in automatically anymore: + +==== +[source,xml] +---- + + + org.elasticsearch.client + elasticsearch-rest-high-level-client + 7.17.4 + + + commons-logging + commons-logging + + + +---- +==== + +Make sure to specify the version 7.17.4 explicitly, otherwise maven will resolve to 8.2.3, and this does not exist. diff --git a/src/main/asciidoc/reference/elasticsearch-misc.adoc b/src/main/asciidoc/reference/elasticsearch-misc.adoc index eb2899d7c..1ea9ae680 100644 --- a/src/main/asciidoc/reference/elasticsearch-misc.adoc +++ b/src/main/asciidoc/reference/elasticsearch-misc.adoc @@ -87,12 +87,19 @@ private ElasticsearchOperations operations; IndexCoordinates index = IndexCoordinates.of("sample-index"); -SearchQuery searchQuery = new NativeSearchQueryBuilder() - .withQuery(matchAllQuery()) - .withFilter(boolFilter().must(termFilter("id", documentId))) - .build(); +Query query = NativeQuery.builder() + .withQuery(q -> q + .matchAll(ma -> ma)) + .withFilter( q -> q + .bool(b -> b + .must(m -> m + .term(t -> t + .field("id") + .value(documentId)) + ))) + .build(); -Page sampleEntities = operations.searchForPage(searchQuery, SampleEntity.class, index); +SearchHits sampleEntities = operations.search(query, SampleEntity.class, index); ---- ==== @@ -107,13 +114,15 @@ This is internally used by Spring Data Elasticsearch to provide the implementati ---- IndexCoordinates index = IndexCoordinates.of("sample-index"); -SearchQuery searchQuery = new NativeSearchQueryBuilder() - .withQuery(matchAllQuery()) - .withFields("message") - .withPageable(PageRequest.of(0, 10)) - .build(); +Query searchQuery = NativeQuery.builder() + .withQuery(q -> q + .matchAll(ma -> ma)) + .withFields("message") + .withPageable(PageRequest.of(0, 10)) + .build(); -SearchHitsIterator stream = elasticsearchTemplate.searchForStream(searchQuery, SampleEntity.class, index); +SearchHitsIterator stream = elasticsearchOperations.searchForStream(searchQuery, SampleEntity.class, +index); List sampleEntities = new ArrayList<>(); while (stream.hasNext()) { @@ -124,23 +133,28 @@ stream.close(); ---- ==== -There are no methods in the `SearchOperations` API to access the scroll id, if it should be necessary to access this, the following methods of the `ElasticsearchRestTemplate` can be used: +There are no methods in the `SearchOperations` API to access the scroll id, if it should be necessary to access this, +the following methods of the `AbstractElasticsearchTemplate` can be used (this is the base implementation for the +different `ElasticsearchOperations` implementations: ==== [source,java] ---- -@Autowired ElasticsearchRestTemplate template; +@Autowired ElasticsearchOperations operations; + +AbstractElasticsearchTemplate template = (AbstractElasticsearchTemplate)operations; IndexCoordinates index = IndexCoordinates.of("sample-index"); -SearchQuery searchQuery = new NativeSearchQueryBuilder() - .withQuery(matchAllQuery()) - .withFields("message") - .withPageable(PageRequest.of(0, 10)) - .build(); +Query query = NativeQuery.builder() + .withQuery(q -> q + .matchAll(ma -> ma)) + .withFields("message") + .withPageable(PageRequest.of(0, 10)) + .build(); -SearchScrollHits scroll = template.searchScrollStart(1000, searchQuery, SampleEntity.class, index); +SearchScrollHits scroll = template.searchScrollStart(1000, query, SampleEntity.class, index); String scrollId = scroll.getScrollId(); List sampleEntities = new ArrayList<>(); diff --git a/src/main/asciidoc/reference/elasticsearch-new.adoc b/src/main/asciidoc/reference/elasticsearch-new.adoc index 8149fdd6f..859e98468 100644 --- a/src/main/asciidoc/reference/elasticsearch-new.adoc +++ b/src/main/asciidoc/reference/elasticsearch-new.adoc @@ -6,6 +6,7 @@ * Upgrade to Java 17 baseline * Upgrade to Spring Framework 6 +* Use the new Elasticsearch client library [[new-features.4-4-0]] == New in Spring Data Elasticsearch 4.4 diff --git a/src/main/asciidoc/reference/elasticsearch-operations.adoc b/src/main/asciidoc/reference/elasticsearch-operations.adoc index 589bf758d..c2b8fb2de 100644 --- a/src/main/asciidoc/reference/elasticsearch-operations.adoc +++ b/src/main/asciidoc/reference/elasticsearch-operations.adoc @@ -30,36 +30,10 @@ There is support for automatic creation of indices and writing the mappings when ==== -[[elasticsearch.operations.resttemplate]] -== ElasticsearchRestTemplate - -The `ElasticsearchRestTemplate` is an implementation of the `ElasticsearchOperations` interface using the <>. - -.ElasticsearchRestTemplate configuration -==== -[source,java] ----- -@Configuration -public class RestClientConfig extends AbstractElasticsearchConfiguration { - @Override - public RestHighLevelClient elasticsearchClient() { <1> - return RestClients.create(ClientConfiguration.localhost()).rest(); - } - - // no special bean creation needed <2> -} ----- - -<1> Setting up the <>. -<2> The base class `AbstractElasticsearchConfiguration` already provides the `elasticsearchTemplate` bean. -==== - [[elasticsearch.operations.usage]] == Usage examples -As both `ElasticsearchTemplate` and `ElasticsearchRestTemplate` implement the `ElasticsearchOperations` interface, the code to use them is not different. The example shows how to use an injected `ElasticsearchOperations` instance in a Spring REST controller. -The decision, if this is using the `TransportClient` or the `RestClient` is made by providing the corresponding Bean with one of the configurations shown above. .ElasticsearchOperations usage ==== @@ -150,7 +124,7 @@ An Iterator returned by the streaming functions of the `SearchOperations` interf [[elasticsearch.operations.queries]] == Queries -Almost all of the methods defined in the `SearchOperations` and `ReactiveSearchOperations` interface take a `Query` parameter that defines the query to execute for searching. `Query` is an interface and Spring Data Elasticsearch provides three implementations: `CriteriaQuery`, `StringQuery` and `NativeSearchQuery`. +Almost all of the methods defined in the `SearchOperations` and `ReactiveSearchOperations` interface take a `Query` parameter that defines the query to execute for searching. `Query` is an interface and Spring Data Elasticsearch provides three implementations: `CriteriaQuery`, `StringQuery` and `NativeQuery`. [[elasticsearch.operations.criteriaquery]] === CriteriaQuery @@ -238,21 +212,28 @@ SearchHits searchHits = operations.search(query, Person.class); Using `StringQuery` may be appropriate if you already have an Elasticsearch query to use. -[[elasticsearch.operations.nativesearchquery]] -=== NativeSearchQuery +[[elasticsearch.operations.nativequery]] +=== NativeQuery -`NativeSearchQuery` is the class to use when you have a complex query, or a query that cannot be expressed by using the `Criteria` API, for example when building queries and using aggregates. -It allows to use all the different `QueryBuilder` implementations from the Elasticsearch library therefore named "native". +`NativeQuery` is the class to use when you have a complex query, or a query that cannot be expressed by using the `Criteria` API, for example when building queries and using aggregates. +It allows to use all the different `co.elastic.clients.elasticsearch._types.query_dsl.Query` implementations from the Elasticsearch library therefore named "native". The following code shows how to search for persons with a given firstname and for the found documents have a terms aggregation that counts the number of occurences of the lastnames for these persons: ==== [source,java] ---- -Query query = new NativeSearchQueryBuilder() - .addAggregation(terms("lastnames").field("lastname").size(10)) // - .withQuery(QueryBuilders.matchQuery("firstname", firstName)) - .build(); +Query query = NativeQuery.builder() + .withAggregation("lastNames", Aggregation.of(a -> a + .terms(ta -> ta.field("last-name").size(10)))) + .withQuery(q -> q + .match(m -> m + .field("firstName") + .query(firstName) + ) + ) + .withPageable(pageable) + .build(); SearchHits searchHits = operations.search(query, Person.class); ---- diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/Aggregation.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/Aggregation.java index 3be50a227..2cf808497 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/Aggregation.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/Aggregation.java @@ -19,7 +19,7 @@ import co.elastic.clients.elasticsearch._types.aggregations.Aggregate; /** * Class to combine an Elasticsearch {@link co.elastic.clients.elasticsearch._types.aggregations.Aggregate} with its - * name. Necessary as the Elasticsearch Aggregate does not know i"s name. + * name. Necessary as the Elasticsearch Aggregate does not know its name. * * @author Peter-Josef Meisch * @since 4.4 diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/CriteriaQueryProcessor.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/CriteriaQueryProcessor.java index 79ced58d4..c736fec08 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/CriteriaQueryProcessor.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/CriteriaQueryProcessor.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import org.apache.lucene.queryparser.flexible.standard.QueryParserUtil; import org.springframework.data.elasticsearch.annotations.FieldType; import org.springframework.data.elasticsearch.core.query.Criteria; import org.springframework.data.elasticsearch.core.query.Field; @@ -184,7 +183,7 @@ class CriteriaQueryProcessor { Criteria.OperationKey key = entry.getKey(); Object value = key.hasValue() ? entry.getValue() : null; - String searchText = value != null ? QueryParserUtil.escape(value.toString()) : "UNKNOWN_VALUE"; + String searchText = value != null ? escape(value.toString()) : "UNKNOWN_VALUE"; Query.Builder queryBuilder = new Query.Builder(); switch (key) { @@ -358,11 +357,32 @@ class CriteriaQueryProcessor { sb.append(' '); } sb.append('"'); - sb.append(QueryParserUtil.escape(item.toString())); + sb.append(escape(item.toString())); sb.append('"'); } } return sb.toString(); } + + /** + * Returns a String where those characters that TextParser expects to be escaped are escaped by a preceding + * \. Copied from Apachae 2 licensed org.apache.lucene.queryparser.flexible.standard.QueryParserUtil + * class + */ + public static String escape(String s) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + // These characters are part of the query syntax and must be escaped + if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':' || c == '^' || c == '[' + || c == ']' || c == '\"' || c == '{' || c == '}' || c == '~' || c == '*' || c == '?' || c == '|' || c == '&' + || c == '/') { + sb.append('\\'); + } + sb.append(c); + } + return sb.toString(); + } + } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java index 99fc7a4ba..55968deea 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java @@ -332,7 +332,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate { } @Override - protected SearchScrollHits searchScrollStart(long scrollTimeInMillis, Query query, Class clazz, + public SearchScrollHits searchScrollStart(long scrollTimeInMillis, Query query, Class clazz, IndexCoordinates index) { Assert.notNull(query, "query must not be null"); @@ -345,7 +345,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate { } @Override - protected SearchScrollHits searchScrollContinue(String scrollId, long scrollTimeInMillis, Class clazz, + public SearchScrollHits searchScrollContinue(String scrollId, long scrollTimeInMillis, Class clazz, IndexCoordinates index) { Assert.notNull(scrollId, "scrollId must not be null"); @@ -368,7 +368,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate { } @Override - protected void searchScrollClear(List scrollIds) { + public void searchScrollClear(List scrollIds) { Assert.notNull(scrollIds, "scrollIds must not be null"); diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/NativeQueryBuilder.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/NativeQueryBuilder.java index ff0e79dc0..de207c740 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/NativeQueryBuilder.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/NativeQueryBuilder.java @@ -89,11 +89,6 @@ public class NativeQueryBuilder extends BaseQueryBuilder> fn) { Assert.notNull(fn, "fn must not be null"); @@ -101,6 +96,18 @@ public class NativeQueryBuilder extends BaseQueryBuilder> fn) { + + Assert.notNull(fn, "fn must not be null"); + + return withFilter(fn.apply(new Query.Builder()).build()); + } + public NativeQueryBuilder withAggregation(String name, Aggregation aggregation) { Assert.notNull(name, "name must not be null"); diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java index 0202f9870..67ac9a63e 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java @@ -32,7 +32,16 @@ import co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType; import co.elastic.clients.elasticsearch._types.mapping.TypeMapping; import co.elastic.clients.elasticsearch._types.query_dsl.Like; import co.elastic.clients.elasticsearch.cluster.HealthRequest; -import co.elastic.clients.elasticsearch.core.*; +import co.elastic.clients.elasticsearch.core.BulkRequest; +import co.elastic.clients.elasticsearch.core.DeleteByQueryRequest; +import co.elastic.clients.elasticsearch.core.DeleteRequest; +import co.elastic.clients.elasticsearch.core.GetRequest; +import co.elastic.clients.elasticsearch.core.IndexRequest; +import co.elastic.clients.elasticsearch.core.MgetRequest; +import co.elastic.clients.elasticsearch.core.MsearchRequest; +import co.elastic.clients.elasticsearch.core.SearchRequest; +import co.elastic.clients.elasticsearch.core.UpdateByQueryRequest; +import co.elastic.clients.elasticsearch.core.UpdateRequest; import co.elastic.clients.elasticsearch.core.bulk.BulkOperation; import co.elastic.clients.elasticsearch.core.bulk.CreateOperation; import co.elastic.clients.elasticsearch.core.bulk.IndexOperation; @@ -42,7 +51,6 @@ import co.elastic.clients.elasticsearch.core.search.Highlight; import co.elastic.clients.elasticsearch.core.search.Rescore; import co.elastic.clients.elasticsearch.core.search.SourceConfig; import co.elastic.clients.elasticsearch.indices.*; -import co.elastic.clients.elasticsearch.indices.ExistsRequest; import co.elastic.clients.elasticsearch.indices.update_aliases.Action; import co.elastic.clients.json.JsonData; import co.elastic.clients.json.JsonpDeserializer; @@ -1022,8 +1030,6 @@ class RequestConverter { Assert.notNull(query, "query must not be null"); Assert.notNull(indexCoordinates, "indexCoordinates must not be null"); - elasticsearchConverter.updateQuery(query, clazz); - SearchRequest.Builder builder = new SearchRequest.Builder(); prepareSearchRequest(query, clazz, indexCoordinates, builder, forCount, useScroll); @@ -1052,8 +1058,7 @@ class RequestConverter { ) // .body(bb -> bb // .query(getQuery(param.query, param.clazz))// - .seqNoPrimaryTerm(persistentEntity.hasSeqNoPrimaryTermProperty()) - .version(true) + .seqNoPrimaryTerm(persistentEntity.hasSeqNoPrimaryTermProperty()).version(true) // todo #2156 add remaining flags for body ) // ); diff --git a/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java index d1dae04b3..f47474a87 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java @@ -417,29 +417,17 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper return search(query, clazz, getIndexCoordinatesFor(clazz)); } - /* - * internal use only, not for public API - */ - abstract protected SearchScrollHits searchScrollStart(long scrollTimeInMillis, Query query, Class clazz, + abstract public SearchScrollHits searchScrollStart(long scrollTimeInMillis, Query query, Class clazz, IndexCoordinates index); - /* - * internal use only, not for public API - */ - abstract protected SearchScrollHits searchScrollContinue(String scrollId, long scrollTimeInMillis, - Class clazz, IndexCoordinates index); + abstract public SearchScrollHits searchScrollContinue(String scrollId, long scrollTimeInMillis, Class clazz, + IndexCoordinates index); - /* - * internal use only, not for public API - */ - protected void searchScrollClear(String scrollId) { + public void searchScrollClear(String scrollId) { searchScrollClear(Collections.singletonList(scrollId)); } - /* - * internal use only, not for public API - */ - abstract protected void searchScrollClear(List scrollIds); + abstract public void searchScrollClear(List scrollIds); // endregion diff --git a/src/main/resources/versions.properties b/src/main/resources/versions.properties index 782d47e5b..68e79e0d7 100644 --- a/src/main/resources/versions.properties +++ b/src/main/resources/versions.properties @@ -1,2 +1,2 @@ version.spring-data-elasticsearch=${project.version} -version.elasticsearch-client=${elasticsearch-rhlc} +version.elasticsearch-client=${elasticsearch-java} diff --git a/src/test/java/org/springframework/data/elasticsearch/client/elc/DevTests.java b/src/test/java/org/springframework/data/elasticsearch/client/elc/DevTests.java index 07ba20822..ae7b737de 100644 --- a/src/test/java/org/springframework/data/elasticsearch/client/elc/DevTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/client/elc/DevTests.java @@ -87,29 +87,29 @@ public class DevTests { ElasticsearchClient client = imperativeElasticsearchClient; -String index = "testindex"; + String index = "testindex"; -var p = new Product("p1", 42.0); + var p = new Product("p1", 42.0); -client.index(ir -> ir // - .index(index)// - .document(p)); + client.index(ir -> ir // + .index(index)// + .document(p)); -client.indices().flush(f -> f.index(index)); + client.indices().flush(f -> f.index(index)); -RuntimeField runtimeField = RuntimeField.of(rf -> rf // - .type(RuntimeFieldType.Double) // - .script(Script.of(s -> s // - .inline(i -> i. // - source("emit(doc['price'].value * 1.19)") // - ) // - )) // -); // + RuntimeField runtimeField = RuntimeField.of(rf -> rf // + .type(RuntimeFieldType.Double) // + .script(Script.of(s -> s // + .inline(i -> i. // + source("emit(doc['price'].value * 1.19)") // + ) // + )) // + ); // -client.search(sr -> sr // - .index(index) // - .runtimeMappings("priceWithTax", Collections.singletonList(runtimeField)), // - Person.class); // + client.search(sr -> sr // + .index(index) // + .runtimeMappings("priceWithTax", Collections.singletonList(runtimeField)), // + Person.class); // } static class ReactiveClient {