mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-23 12:32:10 +00:00
Make the new client the default.
Original Pull Request #2208 Closes #2159
This commit is contained in:
parent
81e2613669
commit
094e79d601
6
pom.xml
6
pom.xml
@ -22,11 +22,14 @@
|
||||
<elasticsearch-rhlc>7.17.4</elasticsearch-rhlc>
|
||||
<!-- version of the new ElasticsearchClient -->
|
||||
<elasticsearch-java>8.2.3</elasticsearch-java>
|
||||
|
||||
<log4j>2.17.2</log4j>
|
||||
<netty>4.1.65.Final</netty>
|
||||
|
||||
<springdata.commons>3.0.0-SNAPSHOT</springdata.commons>
|
||||
<testcontainers>1.16.2</testcontainers>
|
||||
<blockhound-junit>1.0.6.RELEASE</blockhound-junit>
|
||||
|
||||
<java-module-name>spring.data.elasticsearch</java-module-name>
|
||||
|
||||
<!--
|
||||
@ -137,11 +140,12 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Elasticsearch RestHighLevelClient, will be removed probably in SDE 5 -->
|
||||
<!-- optional Elasticsearch RestHighLevelClient, deprecated in SDE 5.0 -->
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||
<version>${elasticsearch-rhlc}</version>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
|
@ -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 <<elasticsearch.clients.rest,high-level REST client>>.
|
||||
Support for upcoming versions of Elasticsearch is being tracked and general compatibility should be given assuming
|
||||
the usage of the <<elasticsearch.operations,ElasticsearchOperations interface>>.
|
||||
|
@ -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 <<elasticsearch.operations>> and <<elasticsearch.repositories>>.
|
||||
|
||||
[[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
|
||||
<<elasticsearch-migration-guide-4.4-5.0.old-client>> 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<IndexResponse> 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<Header>` 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].
|
||||
|
||||
|
@ -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. <<repositories.custom-implementations>> can be used instead.
|
||||
Currently native queries must be used to query the data, so there is no support from standard repository methods. <<repositories.custom-implementations>> 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<Statement> 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);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
@ -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]
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>co.elastic.clients</groupId>
|
||||
<artifactId>elasticsearch-java</artifactId>
|
||||
<version>7.17.3</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-client</artifactId> <!-- is Apache 2-->
|
||||
<version>7.17.3</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
====
|
||||
|
||||
When using Spring Boot, it is necessary to set the following property in the _pom.xml_.
|
||||
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
<properties>
|
||||
<jakarta-json.version>2.0.1</jakarta-json.version>
|
||||
</properties>
|
||||
----
|
||||
====
|
||||
|
||||
==== 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]
|
||||
----
|
||||
<!-- include the RHLC, specify version explicitly -->
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||
<version>7.17.4</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
----
|
||||
====
|
||||
|
||||
Make sure to specify the version 7.17.4 explicitly, otherwise maven will resolve to 8.2.3, and this does not exist.
|
||||
|
@ -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<SampleEntity> sampleEntities = operations.searchForPage(searchQuery, SampleEntity.class, index);
|
||||
SearchHits<SampleEntity> 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<SampleEntity> stream = elasticsearchTemplate.searchForStream(searchQuery, SampleEntity.class, index);
|
||||
SearchHitsIterator<SampleEntity> stream = elasticsearchOperations.searchForStream(searchQuery, SampleEntity.class,
|
||||
index);
|
||||
|
||||
List<SampleEntity> 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<SampleEntity> scroll = template.searchScrollStart(1000, searchQuery, SampleEntity.class, index);
|
||||
SearchScrollHits<SampleEntity> scroll = template.searchScrollStart(1000, query, SampleEntity.class, index);
|
||||
|
||||
String scrollId = scroll.getScrollId();
|
||||
List<SampleEntity> sampleEntities = new ArrayList<>();
|
||||
|
@ -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
|
||||
|
@ -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 <<elasticsearch.clients.rest>>.
|
||||
|
||||
.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 <<elasticsearch.clients.rest>>.
|
||||
<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<Person> 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<Person> searchHits = operations.search(query, Person.class);
|
||||
----
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
* <code>\</code>. 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> SearchScrollHits<T> searchScrollStart(long scrollTimeInMillis, Query query, Class<T> clazz,
|
||||
public <T> SearchScrollHits<T> searchScrollStart(long scrollTimeInMillis, Query query, Class<T> clazz,
|
||||
IndexCoordinates index) {
|
||||
|
||||
Assert.notNull(query, "query must not be null");
|
||||
@ -345,7 +345,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> SearchScrollHits<T> searchScrollContinue(String scrollId, long scrollTimeInMillis, Class<T> clazz,
|
||||
public <T> SearchScrollHits<T> searchScrollContinue(String scrollId, long scrollTimeInMillis, Class<T> 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<String> scrollIds) {
|
||||
public void searchScrollClear(List<String> scrollIds) {
|
||||
|
||||
Assert.notNull(scrollIds, "scrollIds must not be null");
|
||||
|
||||
|
@ -89,11 +89,6 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeQueryBuilder withFilter(@Nullable Query filter) {
|
||||
this.filter = filter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeQueryBuilder withQuery(Function<Query.Builder, ObjectBuilder<Query>> fn) {
|
||||
|
||||
Assert.notNull(fn, "fn must not be null");
|
||||
@ -101,6 +96,18 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
|
||||
return withQuery(fn.apply(new Query.Builder()).build());
|
||||
}
|
||||
|
||||
public NativeQueryBuilder withFilter(@Nullable Query filter) {
|
||||
this.filter = filter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeQueryBuilder withFilter(Function<Query.Builder, ObjectBuilder<Query>> 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");
|
||||
|
@ -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
|
||||
) //
|
||||
);
|
||||
|
@ -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 <T> SearchScrollHits<T> searchScrollStart(long scrollTimeInMillis, Query query, Class<T> clazz,
|
||||
abstract public <T> SearchScrollHits<T> searchScrollStart(long scrollTimeInMillis, Query query, Class<T> clazz,
|
||||
IndexCoordinates index);
|
||||
|
||||
/*
|
||||
* internal use only, not for public API
|
||||
*/
|
||||
abstract protected <T> SearchScrollHits<T> searchScrollContinue(String scrollId, long scrollTimeInMillis,
|
||||
Class<T> clazz, IndexCoordinates index);
|
||||
abstract public <T> SearchScrollHits<T> searchScrollContinue(String scrollId, long scrollTimeInMillis, Class<T> 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<String> scrollIds);
|
||||
abstract public void searchScrollClear(List<String> scrollIds);
|
||||
|
||||
// endregion
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
version.spring-data-elasticsearch=${project.version}
|
||||
version.elasticsearch-client=${elasticsearch-rhlc}
|
||||
version.elasticsearch-client=${elasticsearch-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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user