Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9667d10933 | |||
| 008074118a | |||
| 94b0d04d70 | |||
| 6f9f12e348 | |||
| 1b4ec95616 | |||
| f409e3ced3 | |||
| d1b80ac7f4 | |||
| 3c264913b5 | |||
| e1d40ded31 | |||
| c824179773 | |||
| 10b43450d5 | |||
| 26e7d37a7a | |||
| 86fc1294d5 | |||
| 1f2dbb0505 | |||
| 2c9ff93d11 | |||
| da0e859d1f | |||
| 0abb2cd979 | |||
| c8c052c6ff | |||
| 8aa90425a7 | |||
| 1ad6542204 | |||
| 01474cd713 | |||
| d621431516 | |||
| 6faa70b0b2 | |||
| 0bcbc45373 | |||
| 79321965f8 | |||
| e1f81f0c42 | |||
| 983e0e552c | |||
| d9028609a8 | |||
| 3e2b114c5d | |||
| 6662e29aa5 | |||
| 0b9cfca28f | |||
| f985e1efe5 | |||
| 8f6fca5b43 | |||
| 0471b54d3b | |||
| 1302c14920 | |||
| 66894a5b0e | |||
| 00c99852fa | |||
| 4152378d32 | |||
| 3fca4e8be3 | |||
| 91f3393abc | |||
| eee009fc18 | |||
| e394464724 | |||
| 47815a69fb | |||
| 01ca42fd2e | |||
| 604c88b6a4 | |||
| ed05313b17 | |||
| 822843a93a | |||
| 7f7731acdc | |||
| a0ee571cc7 | |||
| 5bbccbf9d0 | |||
| 19af94f87e | |||
| 71a3e24096 | |||
| 23eacd4d4b | |||
| 56bda34666 | |||
| 76ba2324a2 | |||
| 4c217fa9c4 | |||
| 003213d4b0 | |||
| 85d52014dc | |||
| 786e0928ed | |||
| ef6f091d6b | |||
| 9ff829a829 | |||
| 30f32b6bbe | |||
| 8ce113a083 | |||
| 262781c0a0 | |||
| ffe8293365 |
@@ -3,7 +3,7 @@ name: CI Build
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ main, 'issue/**' ]
|
||||
branches: [ 5.5.x, 'issue/5.5.x/**' ]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
@@ -11,17 +11,17 @@ jobs:
|
||||
build-java:
|
||||
strategy:
|
||||
matrix:
|
||||
java-version: [ base, main ]
|
||||
java-version: [ base, next ]
|
||||
name: Build project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Setup Java and Maven
|
||||
uses: spring-projects/spring-data-build/actions/setup-maven@main
|
||||
uses: spring-projects/spring-data-build/actions/setup-maven@3.5.x
|
||||
with:
|
||||
java-version: ${{ matrix.java-version }}
|
||||
develocity-access-key: '${{ secrets.DEVELOCITY_ACCESS_KEY }}'
|
||||
- name: Build
|
||||
uses: spring-projects/spring-data-build/actions/maven-build@main
|
||||
uses: spring-projects/spring-data-build/actions/maven-build@3.5.x
|
||||
env:
|
||||
TESTCONTAINERS_REUSE_ENABLE: true
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# GitHub Actions to automate GitHub issues for Spring Data Project Management
|
||||
|
||||
name: Spring Data GitHub Issues
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited, reopened]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_target:
|
||||
types: [opened, edited, reopened]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
Inbox:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request == null && !contains(join(github.event.issue.labels.*.name, ', '), 'dependency-upgrade') && !contains(github.event.issue.title, 'Release ')
|
||||
steps:
|
||||
- name: Create or Update Issue Card
|
||||
uses: actions/add-to-project@v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/spring-projects/projects/25
|
||||
github-token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
|
||||
Pull-Request:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request != null
|
||||
steps:
|
||||
- name: Create or Update Pull Request Card
|
||||
uses: actions/add-to-project@v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/spring-projects/projects/25
|
||||
github-token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
|
||||
Feedback-Provided:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'spring-projects' && github.event_name == 'issue_comment' && github.event.action == 'created' && github.actor != 'spring-projects-issues' && github.event.pull_request == null && github.event.issue.state == 'open' && contains(toJSON(github.event.issue.labels), 'waiting-for-feedback')
|
||||
steps:
|
||||
- name: Update Project Card
|
||||
uses: actions/add-to-project@v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/spring-projects/projects/25
|
||||
github-token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
|
||||
@@ -3,7 +3,7 @@ name: Snapshots
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ main, 'issue/**' ]
|
||||
branches: [ 5.5.x, 'issue/5.5.x/**' ]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
@@ -15,11 +15,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Setup Java and Maven
|
||||
uses: spring-projects/spring-data-build/actions/setup-maven@main
|
||||
uses: spring-projects/spring-data-build/actions/setup-maven@3.5.x
|
||||
with:
|
||||
develocity-access-key: '${{ secrets.DEVELOCITY_ACCESS_KEY }}'
|
||||
- name: Deploy to Artifactory
|
||||
uses: spring-projects/spring-data-build/actions/maven-artifactory-deploy@main
|
||||
uses: spring-projects/spring-data-build/actions/maven-artifactory-deploy@3.5.x
|
||||
env:
|
||||
TESTCONTAINERS_REUSE_ENABLE: true
|
||||
with:
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#Thu Jul 17 13:59:56 CEST 2025
|
||||
#Thu Jul 17 14:00:55 CEST 2025
|
||||
wrapperUrl=https\://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
|
||||
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>6.1.0-SNAPSHOT</version>
|
||||
<version>5.5.10</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
<version>3.5.10</version>
|
||||
</parent>
|
||||
|
||||
<name>Spring Data Elasticsearch</name>
|
||||
@@ -18,16 +18,16 @@
|
||||
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
|
||||
|
||||
<properties>
|
||||
<springdata.commons>4.1.0-SNAPSHOT</springdata.commons>
|
||||
<springdata.commons>3.5.10</springdata.commons>
|
||||
|
||||
<!-- version of the ElasticsearchClient -->
|
||||
<elasticsearch-java>9.4.1</elasticsearch-java>
|
||||
<elasticsearch-rest-client>9.4.1</elasticsearch-rest-client>
|
||||
<elasticsearch-java>8.18.8</elasticsearch-java>
|
||||
|
||||
<hoverfly>0.20.2</hoverfly>
|
||||
<log4j>2.25.4</log4j>
|
||||
<hoverfly>0.19.0</hoverfly>
|
||||
<log4j>2.23.1</log4j>
|
||||
<jsonassert>1.5.3</jsonassert>
|
||||
<wiremock>3.9.2</wiremock>
|
||||
<testcontainers>1.20.0</testcontainers>
|
||||
<wiremock>3.9.1</wiremock>
|
||||
|
||||
<java-module-name>spring.data.elasticsearch</java-module-name>
|
||||
|
||||
@@ -91,27 +91,6 @@
|
||||
<url>https://github.com/spring-projects/spring-data-elasticsearch/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.19.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.20.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- Spring -->
|
||||
@@ -157,52 +136,30 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- the old RestCLient is an optional dependency for user that still want to use it-->
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-client</artifactId>
|
||||
<version>${elasticsearch-rest-client}</version>
|
||||
<version>${elasticsearch-java}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.querydsl</groupId>
|
||||
<artifactId>querydsl-core</artifactId>
|
||||
<version>${querydsl}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson JSON Mapper -->
|
||||
<dependency>
|
||||
<groupId>tools.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tools.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Version 2 to use with the legacy RestClient -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- CDI -->
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.interceptor</groupId>
|
||||
<artifactId>javax.interceptor-api</artifactId>
|
||||
@@ -276,14 +233,6 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>26.0.2-1</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
@@ -335,6 +284,21 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Upgrade xbean to 4.5 to prevent incompatibilities due to ASM versions -->
|
||||
<dependency>
|
||||
<groupId>org.apache.xbean</groupId>
|
||||
<artifactId>xbean-asm5-shaded</artifactId>
|
||||
<version>4.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
@@ -344,7 +308,16 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers-elasticsearch</artifactId>
|
||||
<artifactId>elasticsearch</artifactId>
|
||||
<version>${testcontainers}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!--we need Murmur3Hash in a test, before 5.2 we had it from the old Elasticsearch dependency -->
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.15</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -355,13 +328,7 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-observation-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
@@ -499,20 +466,8 @@
|
||||
</profiles>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestone</id>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
|
||||
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -17,7 +17,7 @@ content:
|
||||
- url: https://github.com/spring-projects/spring-data-commons
|
||||
# Refname matching:
|
||||
# https://docs.antora.org/antora/latest/playbook/content-refname-matching/
|
||||
branches: [ main ]
|
||||
branches: [ main, 3.4.x, 3.3.x ]
|
||||
start_path: src/main/antora
|
||||
asciidoc:
|
||||
attributes:
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
*** xref:migration-guides/migration-guide-5.2-5.3.adoc[]
|
||||
*** xref:migration-guides/migration-guide-5.3-5.4.adoc[]
|
||||
*** xref:migration-guides/migration-guide-5.4-5.5.adoc[]
|
||||
*** xref:migration-guides/migration-guide-5.5-6.0.adoc[]
|
||||
|
||||
|
||||
* xref:elasticsearch.adoc[]
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Spring Data support for Elasticsearch contains a wide range of features:
|
||||
|
||||
* Spring configuration support for various xref:elasticsearch/clients.adoc[Elasticsearch clients].
|
||||
* The xref:elasticsearch/template.adoc[`ElasticsearchTemplate` and `ReactiveElasticsearchTemplate`] helper classes that provide object mapping between Elasticsearch index operations and POJOs.
|
||||
* The xref:elasticsearch/template.adoc[`ElasticsearchTemplate` and `ReactiveElasticsearchTemplate`] helper classes that provide object mapping between ES index operations and POJOs.
|
||||
* xref:elasticsearch/template.adoc#exception-translation[Exception translation] into Spring's portable {springDocsUrl}data-access.html#dao-exceptions[Data Access Exception Hierarchy].
|
||||
* Feature rich xref:elasticsearch/object-mapping.adoc[object mapping] integrated with _Spring's_ {springDocsUrl}core.html#core-convert[Conversion Service].
|
||||
* xref:elasticsearch/object-mapping.adoc#elasticsearch.mapping.meta-model.annotations[Annotation-based mapping] metadata that is extensible to support other metadata formats.
|
||||
|
||||
@@ -10,7 +10,7 @@ In order for the auditing code to be able to decide whether an entity instance i
|
||||
----
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
public interface Persistable<ID> {
|
||||
@Nullable
|
||||
@@ -81,5 +81,5 @@ class MyConfiguration {
|
||||
}
|
||||
----
|
||||
|
||||
If your code contains more than one `AuditorAware` bean for different types, you must provide the name of the bean to use as an argument to the `auditorAwareRef` parameter of the
|
||||
`@EnableElasticsearchAuditing` annotation.
|
||||
If your code contains more than one `AuditorAware` bean for different types, you must provide the name of the bean to use as an argument to the `auditorAwareRef` parameter of the
|
||||
`@EnableElasticsearchAuditing` annotation.
|
||||
|
||||
@@ -6,10 +6,10 @@ This chapter illustrates configuration and usage of supported Elasticsearch clie
|
||||
Spring Data Elasticsearch operates upon an Elasticsearch client (provided by Elasticsearch client libraries) that is connected to a single Elasticsearch node or a cluster.
|
||||
Although the Elasticsearch Client can be used directly to work with the cluster, applications using Spring Data Elasticsearch normally use the higher level abstractions of xref:elasticsearch/template.adoc[Elasticsearch Operations] and xref:elasticsearch/repositories/elasticsearch-repositories.adoc[Elasticsearch Repositories].
|
||||
|
||||
[[elasticsearch.clients.rest5client]]
|
||||
== Imperative Rest5Client
|
||||
[[elasticsearch.clients.restclient]]
|
||||
== Imperative Rest Client
|
||||
|
||||
To use the imperative (non-reactive) Rest5Client - the default client provided by the Elasticsearch Java client library from version 9 on -, a configuration bean must be configured like this:
|
||||
To use the imperative (non-reactive) client, a configuration bean must be configured like this:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
@@ -31,7 +31,7 @@ public class MyClientConfig extends ElasticsearchConfiguration {
|
||||
<.> for a detailed description of the builder methods see xref:elasticsearch/clients.adoc#elasticsearch.clients.configuration[Client Configuration]
|
||||
====
|
||||
|
||||
The javadoc:org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration[] class allows further configuration by overriding for example the `jsonpMapper()` or `transportOptions()` methods.
|
||||
The javadoc:org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration[]] class allows further configuration by overriding for example the `jsonpMapper()` or `transportOptions()` methods.
|
||||
|
||||
|
||||
The following beans can then be injected in other Spring components:
|
||||
@@ -39,85 +39,7 @@ The following beans can then be injected in other Spring components:
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@Autowired
|
||||
ElasticsearchOperations operations; <.>
|
||||
|
||||
@Autowired
|
||||
ElasticsearchClient elasticsearchClient; <.>
|
||||
|
||||
@Autowired
|
||||
Rest5Client rest5Client; <.>
|
||||
|
||||
@Autowired
|
||||
JsonpMapper jsonpMapper; <.>
|
||||
----
|
||||
|
||||
<.> an implementation of javadoc:org.springframework.data.elasticsearch.core.ElasticsearchOperations[]
|
||||
<.> the `co.elastic.clients.elasticsearch.ElasticsearchClient` that is used.
|
||||
<.> the low level `Rest5Client` from the Elasticsearch libraries
|
||||
<.> the `JsonpMapper` user by the Elasticsearch `Transport`
|
||||
====
|
||||
|
||||
Basically one should just use the javadoc:org.springframework.data.elasticsearch.core.ElasticsearchOperations[] to interact with the Elasticsearch cluster.
|
||||
When using repositories, this instance is used under the hood as well.
|
||||
|
||||
[[elasticsearch.clients.restclient]]
|
||||
== Deprecated Imperative RestClient
|
||||
|
||||
To use the imperative (non-reactive) RestClient - deprecated since version 6 - , the following dependency needs to be added, adapt the correct version. The exclusion is needed in a Spring Boot application:
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-client</artifactId>
|
||||
<version>${elasticsearch-client.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
----
|
||||
====
|
||||
|
||||
The configuration bean must then be configured like this:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchLegacyRestClientConfiguration;
|
||||
|
||||
@Configuration
|
||||
public class MyClientConfig extends ElasticsearchLegacyRestClientConfiguration {
|
||||
|
||||
@Override
|
||||
public ClientConfiguration clientConfiguration() {
|
||||
return ClientConfiguration.builder() <.>
|
||||
.connectedTo("localhost:9200")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
<.> for a detailed description of the builder methods see xref:elasticsearch/clients.adoc#elasticsearch.clients.configuration[Client Configuration]
|
||||
====
|
||||
|
||||
The javadoc:org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration[] class allows further configuration by overriding for example the `jsonpMapper()` or `transportOptions()` methods.
|
||||
|
||||
|
||||
The following beans can then be injected in other Spring components:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@Autowired
|
||||
import org.springframework.beans.factory.annotation.Autowired;@Autowired
|
||||
ElasticsearchOperations operations; <.>
|
||||
|
||||
@Autowired
|
||||
@@ -139,8 +61,8 @@ JsonpMapper jsonpMapper; <.>
|
||||
Basically one should just use the javadoc:org.springframework.data.elasticsearch.core.ElasticsearchOperations[] to interact with the Elasticsearch cluster.
|
||||
When using repositories, this instance is used under the hood as well.
|
||||
|
||||
[[elasticsearch.clients.reactiverest5client]]
|
||||
== Reactive Rest5Client
|
||||
[[elasticsearch.clients.reactiverestclient]]
|
||||
== Reactive Rest Client
|
||||
|
||||
When working with the reactive stack, the configuration must be derived from a different class:
|
||||
|
||||
@@ -171,69 +93,6 @@ The following beans can then be injected in other Spring components:
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@Autowired
|
||||
ReactiveElasticsearchOperations operations; <.>
|
||||
|
||||
@Autowired
|
||||
ReactiveElasticsearchClient elasticsearchClient; <.>
|
||||
|
||||
@Autowired
|
||||
Rest5Client rest5Client; <.>
|
||||
|
||||
@Autowired
|
||||
JsonpMapper jsonpMapper; <.>
|
||||
----
|
||||
|
||||
the following can be injected:
|
||||
|
||||
<.> an implementation of javadoc:org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations[]
|
||||
<.> the `org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient` that is used.
|
||||
This is a reactive implementation based on the Elasticsearch client implementation.
|
||||
<.> the low level `RestClient` from the Elasticsearch libraries
|
||||
<.> the `JsonpMapper` user by the Elasticsearch `Transport`
|
||||
====
|
||||
|
||||
Basically one should just use the javadoc:org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations[] to interact with the Elasticsearch cluster.
|
||||
When using repositories, this instance is used under the hood as well.
|
||||
|
||||
[[elasticsearch.clients.reactiverestclient]]
|
||||
== Deprecated Reactive RestClient
|
||||
|
||||
See the section above for the imperative code to use the deprecated RestClient for the necessary dependencies to include.
|
||||
|
||||
When working with the reactive stack, the configuration must be derived from a different class:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchLegacyRestClientConfiguration;
|
||||
|
||||
@Configuration
|
||||
public class MyClientConfig extends ReactiveElasticsearchLegacyRestClientConfiguration {
|
||||
|
||||
@Override
|
||||
public ClientConfiguration clientConfiguration() {
|
||||
return ClientConfiguration.builder() <.>
|
||||
.connectedTo("localhost:9200")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
<.> for a detailed description of the builder methods see xref:elasticsearch/clients.adoc#elasticsearch.clients.configuration[Client Configuration]
|
||||
====
|
||||
|
||||
The javadoc:org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchConfiguration[] class allows further configuration by overriding for example the `jsonpMapper()` or `transportOptions()` methods.
|
||||
|
||||
The following beans can then be injected in other Spring components:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@Autowired
|
||||
ReactiveElasticsearchOperations operations; <.>
|
||||
|
||||
@@ -302,7 +161,7 @@ ClientConfiguration clientConfiguration = ClientConfiguration.builder()
|
||||
|
||||
<.> Define default headers, if they need to be customized
|
||||
<.> Use the builder to provide cluster addresses, set default `HttpHeaders` or enable SSL.
|
||||
<.> Optionally enable SSL.There exist overloads of this function that can take a `SSLContext` or as an alternative the fingerprint of the certificate as it is output by Elasticsearch on startup (since version 8).
|
||||
<.> Optionally enable SSL.There exist overloads of this function that can take a `SSLContext` or as an alternative the fingerprint of the certificate as it is output by Elasticsearch 8 on startup.
|
||||
<.> Optionally set a proxy.
|
||||
<.> Optionally set a path prefix, mostly used when different clusters a behind some reverse proxy.
|
||||
<.> Set the connection timeout.
|
||||
@@ -324,25 +183,8 @@ In the case this is not enough, the user can add callback functions by using the
|
||||
|
||||
The following callbacks are provided:
|
||||
|
||||
[[elasticsearch.clients.configuration.callbacks.rest5]]
|
||||
==== Configuration of the low level Elasticsearch `Rest5Client`:
|
||||
|
||||
This callback provides a `org.elasticsearch.client.RestClientBuilder` that can be used to configure the Elasticsearch
|
||||
`Rest5Client`:
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
ClientConfiguration.builder()
|
||||
.connectedTo("localhost:9200", "localhost:9291")
|
||||
.withClientConfigurer(Rest5Clients.ElasticsearchRest5ClientConfigurationCallback.from(restClientBuilder -> {
|
||||
// configure the Elasticsearch Rest5Client
|
||||
return restClientBuilder;
|
||||
}))
|
||||
.build();
|
||||
----
|
||||
====
|
||||
[[elasticsearch.clients.configuration.callbacks.rest]]
|
||||
==== Configuration of the deprecated low level Elasticsearch `RestClient`:
|
||||
==== Configuration of the low level Elasticsearch `RestClient`:
|
||||
|
||||
This callback provides a `org.elasticsearch.client.RestClientBuilder` that can be used to configure the Elasticsearch
|
||||
`RestClient`:
|
||||
@@ -351,7 +193,7 @@ This callback provides a `org.elasticsearch.client.RestClientBuilder` that can b
|
||||
----
|
||||
ClientConfiguration.builder()
|
||||
.connectedTo("localhost:9200", "localhost:9291")
|
||||
.withClientConfigurer(RestClients.ElasticsearchRestClientConfigurationCallback.from(restClientBuilder -> {
|
||||
.withClientConfigurer(ElasticsearchClients.ElasticsearchRestClientConfigurationCallback.from(restClientBuilder -> {
|
||||
// configure the Elasticsearch RestClient
|
||||
return restClientBuilder;
|
||||
}))
|
||||
@@ -359,29 +201,10 @@ ClientConfiguration.builder()
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.clients.configurationcallbacks.httpasync5]]
|
||||
==== Configuration of the HttpAsyncClient used by the low level Elasticsearch `Rest5Client`:
|
||||
|
||||
This callback provides a `org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder` to configure the HttpClient that is
|
||||
used by the `Rest5Client`.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
ClientConfiguration.builder()
|
||||
.connectedTo("localhost:9200", "localhost:9291")
|
||||
.withClientConfigurer(Rest5Clients.ElasticsearchHttpClientConfigurationCallback.from(httpAsyncClientBuilder -> {
|
||||
// configure the HttpAsyncClient
|
||||
return httpAsyncClientBuilder;
|
||||
}))
|
||||
.build();
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.clients.configurationcallbacks.httpasync]]
|
||||
==== Configuration of the HttpAsyncClient used by the deprecated low level Elasticsearch `RestClient`:
|
||||
==== Configuration of the HttpAsyncClient used by the low level Elasticsearch `RestClient`:
|
||||
|
||||
This callback provides a `org.apache.http.impl.nio.client.HttpAsyncClientBuilder` to configure the HttpClient that is
|
||||
This callback provides a `org.apache.http.impl.nio.client.HttpAsyncClientBuilder` to configure the HttpCLient that is
|
||||
used by the `RestClient`.
|
||||
|
||||
====
|
||||
@@ -389,7 +212,7 @@ used by the `RestClient`.
|
||||
----
|
||||
ClientConfiguration.builder()
|
||||
.connectedTo("localhost:9200", "localhost:9291")
|
||||
.withClientConfigurer(RestClients.ElasticsearchHttpClientConfigurationCallback.from(httpAsyncClientBuilder -> {
|
||||
.withClientConfigurer(ElasticsearchClients.ElasticsearchHttpClientConfigurationCallback.from(httpAsyncClientBuilder -> {
|
||||
// configure the HttpAsyncClient
|
||||
return httpAsyncClientBuilder;
|
||||
}))
|
||||
@@ -397,92 +220,15 @@ ClientConfiguration.builder()
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.clients.configurationcallbacks.connectionconfig]]
|
||||
==== Configuration of the ConnectionConfig used by the low level Elasticsearch `Rest5Client`:
|
||||
|
||||
This callback provides a `org.apache.hc.client5.http.config.ConnectionConfig` to configure the connection that is
|
||||
used by the `Rest5Client`.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
ClientConfiguration.builder()
|
||||
.connectedTo("localhost:9200", "localhost:9291")
|
||||
.withClientConfigurer(Rest5Clients.ElasticsearchConnectionConfigurationCallback.from(connectionConfigBuilder -> {
|
||||
// configure the connection
|
||||
return connectionConfigBuilder;
|
||||
}))
|
||||
.build();
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.clients.configurationcallbacks.connectioncmanager]]
|
||||
==== Configuration of the ConnectionManager used by the low level Elasticsearch `Rest5Client`:
|
||||
|
||||
This callback provides a `org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder` to configure the connection manager that is
|
||||
used by the `Rest5Client`.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
ClientConfiguration.builder()
|
||||
.connectedTo("localhost:9200", "localhost:9291")
|
||||
.withClientConfigurer(Rest5Clients.ElasticsearchConnectionManagerCallback.from(connectionManagerBuilder -> {
|
||||
// configure the connection manager
|
||||
return connectionManagerBuilder;
|
||||
}))
|
||||
.build();
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.clients.configurationcallbacks.requestconfig]]
|
||||
==== Configuration of the RequestConfig used by the low level Elasticsearch `Rest5Client`:
|
||||
|
||||
This callback provides a `org.apache.hc.client5.http.config.RequestConfig` to configure the RequestConfig that is
|
||||
used by the `Rest5Client`.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
ClientConfiguration.builder()
|
||||
.connectedTo("localhost:9200", "localhost:9291")
|
||||
.withClientConfigurer(Rest5Clients.ElasticsearchRequestConfigCallback.from(requestConfigBuilder -> {
|
||||
// configure the request config
|
||||
return requestConfigBuilder;
|
||||
}))
|
||||
.build();
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.clients.logging]]
|
||||
== Client Logging
|
||||
|
||||
To see what is actually sent to and received from the server `Request` / `Response` logging on the transport level needs to be turned on as outlined in the snippet below.
|
||||
This can be enabled in the Elasticsearch client by setting the level of the `co.elastic.clients.transport.rest5_client.low_level.Request` package to "trace" (see
|
||||
https://www.elastic.co/docs/reference/elasticsearch/clients/java/transport/rest5-client/usage/logging)
|
||||
This can be enabled in the Elasticsearch client by setting the level of the `tracer` package to "trace" (see
|
||||
https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/java-rest-low-usage-logging.html)
|
||||
|
||||
.Enable transport layer logging
|
||||
[tabs]
|
||||
======
|
||||
XML::
|
||||
+
|
||||
[source,xml]
|
||||
----
|
||||
<logger name="co.elastic.clients.transport.rest5_client.low_level.Request" level="trace"/>
|
||||
<logger name="tracer" level="trace"/>
|
||||
----
|
||||
|
||||
yml::
|
||||
+
|
||||
[source,yml]
|
||||
----
|
||||
logging.level:
|
||||
co.elastic.clients.transport.rest5_client.low_level.Request: trace
|
||||
----
|
||||
|
||||
ini::
|
||||
+
|
||||
[source,ini]
|
||||
----
|
||||
logging.level.co.elastic.clients.transport.rest5_client.low_level.Request=trace
|
||||
----
|
||||
======
|
||||
|
||||
@@ -1,24 +1,6 @@
|
||||
[[new-features]]
|
||||
= What's new
|
||||
|
||||
[[new-features.6-1-0]]
|
||||
== New in Spring Data Elasticsearch 6.1
|
||||
|
||||
* Upgrade to Elasticsearch 9.4.1
|
||||
* Add support to use `IndexCoordinates` as repository query parameter
|
||||
* Add support for includeNamedQueriesScore in Query
|
||||
* Add support for Micrometer observation.
|
||||
|
||||
[[new-features.6-0-0]]
|
||||
== New in Spring Data Elasticsearch 6.0
|
||||
|
||||
* Upgrade to Spring 7
|
||||
* Switch to jspecify nullability annotations
|
||||
* Upgrade to Elasticsearch 9.2.1
|
||||
* Use the new Elasticsearch Rest5Client as default
|
||||
* Add support for SpEL expressions in the `settingPath` parameter of the `@Setting` annotation
|
||||
|
||||
|
||||
[[new-features.5-5-0]]
|
||||
== New in Spring Data Elasticsearch 5.5
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ When creating Elasticsearch indices with Spring Data Elasticsearch different ind
|
||||
The following arguments are available:
|
||||
|
||||
* `useServerConfiguration` does not send any settings parameters, so the Elasticsearch server configuration determines them.
|
||||
* `settingPath` refers to a JSON file defining the settings that must be resolvable in the classpath, it is possible to use a SpEL expression here
|
||||
* `settingPath` refers to a JSON file defining the settings that must be resolvable in the classpath
|
||||
* `shards` the number of shards to use, defaults to _1_
|
||||
* `replicas` the number of replicas, defaults to _1_
|
||||
* `refreshIntervall`, defaults to _"1s"_
|
||||
|
||||
@@ -20,12 +20,12 @@ Whereas the birthdate is fix, the age depends on the time when a query is issued
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.ScriptedField;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
@@ -6,11 +6,9 @@ The following table shows the Elasticsearch and Spring versions that are used by
|
||||
[cols="^,^,^,^",options="header"]
|
||||
|===
|
||||
| Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework
|
||||
| 2026.0 | 6.1.x | 9.4.1 | 7.0.x
|
||||
| 2025.1 | 6.0.x | 9.2.2 | 7.0.x
|
||||
| 2025.0 | 5.5.xfootnote:oom[Out of maintenance] | 8.18.1 | 6.2.x
|
||||
| 2024.1 | 5.4.xfootnote:oom[] | 8.15.5 | 6.1.x
|
||||
| 2024.0 | 5.3.xfootnote:oom[] | 8.13.4 | 6.1.x
|
||||
| 2025.0 | 5.5.x | 8.18.8 | 6.2.x
|
||||
| 2024.1 | 5.4.x | 8.15.5 | 6.1.x
|
||||
| 2024.0 | 5.3.xfootnote:oom[Out of maintenance] | 8.13.4 | 6.1.x
|
||||
| 2023.1 (Vaughan) | 5.2.xfootnote:oom[] | 8.11.1 | 6.1.x
|
||||
| 2023.0 (Ullmann) | 5.1.xfootnote:oom[] | 8.7.1 | 6.0.x
|
||||
| 2022.0 (Turing) | 5.0.xfootnote:oom[] | 8.5.3 | 6.0.x
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
[[elasticsearch-migration-guide-5.5-6.0]]
|
||||
= Upgrading from 5.5.x to 6.0.x
|
||||
|
||||
This section describes breaking changes from version 5.5.x to 6.0.x and how removed features can be replaced by new introduced features.
|
||||
|
||||
[[elasticsearch-migration-guide-5.5-6.0.breaking-changes]]
|
||||
== Breaking Changes
|
||||
|
||||
From version 6.0 on, Spring Data Elasticsearch uses the Elasticsearch 9 libraries and as default the new `Rest5Client` provided by these libraries. It is still possible to use the old `RestClient`, check xref:elasticsearch/clients.adoc[Elasticsearch clients] for information. The configuration callbacks for this `RestClient` have been moved from `org.springframework.data.elasticsearch.client.elc.ElasticsearchClients` to the `org.springframework.data.elasticsearch.client.elc.rest_client.RestClients` class.
|
||||
|
||||
In the `org.springframework.data.elasticsearch.core.query.UpdateQuery` class the type of the two fields `ifSeqNo` and `ifPrimaryTerm` has changed from `Integer` to `Long` to align with the normal query and the underlying Elasticsearch client.
|
||||
|
||||
[[elasticsearch-migration-guide-5.5-6.0.deprecations]]
|
||||
== Deprecations
|
||||
|
||||
All the code using the old `RestClient` has been moved to the `org.springframework.data.elasticsearch.client.elc.rest_client` package and has been deprecated. Users should switch to the classes from the `org.springframework.data.elasticsearch.client.elc.rest5_client` package.
|
||||
|
||||
|
||||
=== Removals
|
||||
|
||||
The `org.springframework.data.elasticsearch.core.query.ScriptType` enum has been removed. To distinguish between an inline and a stored script set the appropriate values in the `org.springframework.data.elasticsearch.core.query.ScriptData` record.
|
||||
|
||||
These methods have been removed because the Elasticsearch Client 9 does not support them anymore:
|
||||
```
|
||||
org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchIndicesClient.unfreeze(UnfreezeRequest)
|
||||
org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchIndicesClient.unfreeze(Function<UnfreezeRequest.Builder, ObjectBuilder<UnfreezeRequest>>)
|
||||
```
|
||||
@@ -1,13 +1,4 @@
|
||||
[[elasticsearch.projections]]
|
||||
= Projections
|
||||
|
||||
[[elasticsearch.projections.limitations]]
|
||||
== Spring Data Elasticsearch Projection Limitations
|
||||
|
||||
This chapter is pulled in from the Spring Data Commons documentation, but does not apply to Spring Data Elasticsearch.
|
||||
|
||||
IMPORTANT: Interface-based projections are not supported in Spring Data Elasticsearch repository query methods.
|
||||
|
||||
To limit the fields returned from Elasticsearch, use the xref:elasticsearch/repositories/elasticsearch-repositories.adoc#elasticsearch.repositories.annotations.sourcefilters[`@SourceFilters`] annotation on your repository methods instead.
|
||||
|
||||
include::{commons}@data-commons::page$repositories/projections.adoc[leveloffset=+1]
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Illia Ulianov
|
||||
@@ -43,6 +42,6 @@ public class BulkFailureException extends DataRetrievalFailureException {
|
||||
* @author Illia Ulianov
|
||||
* @since 5.2
|
||||
*/
|
||||
public record FailureDetails(Integer status, @Nullable String errorMessage) {
|
||||
public record FailureDetails(Integer status, String errorMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Object describing an Elasticsearch error
|
||||
@@ -26,9 +26,10 @@ import org.jspecify.annotations.Nullable;
|
||||
* @since 4.4
|
||||
*/
|
||||
public class ElasticsearchErrorCause {
|
||||
@Nullable private final String type;
|
||||
@Nullable
|
||||
private final String type;
|
||||
|
||||
@Nullable private final String reason;
|
||||
private final String reason;
|
||||
|
||||
@Nullable private final String stackTrace;
|
||||
|
||||
@@ -38,7 +39,7 @@ public class ElasticsearchErrorCause {
|
||||
|
||||
private final List<ElasticsearchErrorCause> suppressed;
|
||||
|
||||
public ElasticsearchErrorCause(@Nullable String type, @Nullable String reason, @Nullable String stackTrace,
|
||||
public ElasticsearchErrorCause(@Nullable String type, String reason, @Nullable String stackTrace,
|
||||
@Nullable ElasticsearchErrorCause causedBy, List<ElasticsearchErrorCause> rootCause,
|
||||
List<ElasticsearchErrorCause> suppressed) {
|
||||
this.type = type;
|
||||
@@ -54,7 +55,7 @@ public class ElasticsearchErrorCause {
|
||||
return type;
|
||||
}
|
||||
|
||||
public @Nullable String getReason() {
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.dao.UncategorizedDataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
|
||||
@@ -107,15 +107,17 @@ public @interface Document {
|
||||
*/
|
||||
Alias[] aliases() default {};
|
||||
|
||||
/**
|
||||
* Note: the enum value FORCE, which was introduced in 4.4 has been removed
|
||||
* again by Elasticsearch.
|
||||
/**
|
||||
* @since 4.3
|
||||
*/
|
||||
enum VersionType {
|
||||
INTERNAL("internal"), //
|
||||
EXTERNAL("external"), //
|
||||
EXTERNAL_GTE("external_gte"); //
|
||||
EXTERNAL_GTE("external_gte"), //
|
||||
/**
|
||||
* @since 4.4
|
||||
*/
|
||||
FORCE("force");
|
||||
|
||||
private final String esName;
|
||||
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2022-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ package org.springframework.data.elasticsearch.aot;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.data.core.ReactiveWrappers;
|
||||
import org.springframework.data.util.ReactiveWrappers;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
|
||||
+1
-1
@@ -19,7 +19,6 @@ import static org.springframework.data.elasticsearch.aot.ElasticsearchAotPredica
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
@@ -33,6 +32,7 @@ import org.springframework.data.elasticsearch.core.event.ReactiveAfterConvertCal
|
||||
import org.springframework.data.elasticsearch.core.event.ReactiveAfterLoadCallback;
|
||||
import org.springframework.data.elasticsearch.core.event.ReactiveAfterSaveCallback;
|
||||
import org.springframework.data.elasticsearch.core.event.ReactiveBeforeConvertCallback;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2022-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.elasticsearch.aot;
|
||||
|
||||
+2
-8
@@ -25,8 +25,8 @@ import java.util.function.Supplier;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.support.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Configuration interface exposing common client configuration properties for Elasticsearch clients.
|
||||
@@ -127,16 +127,10 @@ public interface ClientConfiguration {
|
||||
Optional<String> getCaFingerprint();
|
||||
|
||||
/**
|
||||
* Returns the {@link HostnameVerifier} to use. Must be {@link Optional#empty()} if not configured.
|
||||
* Cannot be used with the Rest5Client used from Elasticsearch 9 on as the underlying Apache http components 5 does not offer a way
|
||||
* to set this. Users that need a hostname verifier must integrate this in a SSLContext.
|
||||
* Returning a value here is ignored in this case
|
||||
* Returns the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if not configured.
|
||||
*
|
||||
* @return the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if not configured.
|
||||
* @deprecated since 6.0
|
||||
*/
|
||||
// todo #3117 document this
|
||||
@Deprecated(since = "6.0", forRemoval=true)
|
||||
Optional<HostnameVerifier> getHostNameVerifier();
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -25,11 +25,11 @@ import java.util.function.Supplier;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithRequiredEndpoint;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder;
|
||||
import org.springframework.data.elasticsearch.support.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -24,8 +24,9 @@ import java.util.function.Supplier;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
|
||||
import org.springframework.data.elasticsearch.support.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Default {@link ClientConfiguration} implementation.
|
||||
|
||||
+3
-3
@@ -17,10 +17,10 @@ package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.core.query.StringQuery;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* An abstract class that serves as a base for query processors. It provides a common interface and basic functionality
|
||||
@@ -38,8 +38,8 @@ public abstract class AbstractQueryProcessor {
|
||||
* @param queryConverter correct mapped field names and the values to the converted values.
|
||||
* @return an Elasticsearch {@literal query}.
|
||||
*/
|
||||
|
||||
static co.elastic.clients.elasticsearch._types.query_dsl.@Nullable Query getEsQuery(@Nullable Query query,
|
||||
@Nullable
|
||||
static co.elastic.clients.elasticsearch._types.query_dsl.Query getEsQuery(@Nullable Query query,
|
||||
@Nullable Consumer<Query> queryConverter) {
|
||||
if (query == null) {
|
||||
return null;
|
||||
|
||||
+1
-1
@@ -31,13 +31,13 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.data.elasticsearch.core.query.Field;
|
||||
import org.springframework.data.elasticsearch.core.query.HasChildQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.HasParentQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.InnerHitsQuery;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import io.micrometer.common.KeyValues;
|
||||
|
||||
/**
|
||||
* Default {@link ElasticsearchObservationConvention} implementation.
|
||||
*
|
||||
* @author maryantocinn
|
||||
* @since 6.1
|
||||
*/
|
||||
public class DefaultElasticsearchObservationConvention implements ElasticsearchObservationConvention {
|
||||
|
||||
public static final DefaultElasticsearchObservationConvention INSTANCE = new DefaultElasticsearchObservationConvention();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return ElasticsearchObservation.ELASTICSEARCH_COMMAND_OBSERVATION.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextualName(ElasticsearchObservationContext context) {
|
||||
|
||||
String indexName = context.getIndexName();
|
||||
if (indexName != null) {
|
||||
return context.getOperationName().getValue() + " " + indexName;
|
||||
}
|
||||
return context.getOperationName().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyValues getLowCardinalityKeyValues(ElasticsearchObservationContext context) {
|
||||
|
||||
KeyValues keyValues = KeyValues.of(
|
||||
ElasticsearchObservation.LowCardinalityKeyNames.OPERATION.withValue(context.getOperationName().getValue()));
|
||||
|
||||
String indexName = context.getIndexName();
|
||||
if (indexName != null) {
|
||||
keyValues = keyValues.and(ElasticsearchObservation.LowCardinalityKeyNames.COLLECTION.withValue(indexName));
|
||||
}
|
||||
|
||||
return keyValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyValues getHighCardinalityKeyValues(ElasticsearchObservationContext context) {
|
||||
|
||||
Integer batchSize = context.getBatchSize();
|
||||
if (batchSize != null) {
|
||||
return KeyValues.of(
|
||||
ElasticsearchObservation.HighCardinalityKeyNames.BATCH_SIZE.withValue(String.valueOf(batchSize)));
|
||||
}
|
||||
|
||||
return KeyValues.empty();
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -34,7 +34,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.MultiGetItem;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.document.Explanation;
|
||||
@@ -42,6 +41,7 @@ import org.springframework.data.elasticsearch.core.document.NestedMetaData;
|
||||
import org.springframework.data.elasticsearch.core.document.SearchDocument;
|
||||
import org.springframework.data.elasticsearch.core.document.SearchDocumentAdapter;
|
||||
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -83,7 +83,7 @@ final class DocumentAdapters {
|
||||
|
||||
Explanation explanation = from(hit.explanation());
|
||||
|
||||
Map<String, Double> matchedQueries = hit.matchedQueries();
|
||||
List<String> matchedQueries = hit.matchedQueries();
|
||||
|
||||
Function<Map<String, JsonData>, EntityAsMap> fromFields = fields -> {
|
||||
StringBuilder sb = new StringBuilder("{");
|
||||
@@ -102,7 +102,7 @@ final class DocumentAdapters {
|
||||
|
||||
EntityAsMap hitFieldsAsMap = fromFields.apply(hit.fields());
|
||||
|
||||
Map<String, List<@Nullable Object>> documentFields = new LinkedHashMap<>();
|
||||
Map<String, List<Object>> documentFields = new LinkedHashMap<>();
|
||||
hitFieldsAsMap.forEach((key, value) -> {
|
||||
if (value instanceof List) {
|
||||
// noinspection unchecked
|
||||
@@ -160,7 +160,7 @@ final class DocumentAdapters {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Explanation from(co.elastic.clients.elasticsearch.core.explain.@Nullable Explanation explanation) {
|
||||
private static Explanation from(@Nullable co.elastic.clients.elasticsearch.core.explain.Explanation explanation) {
|
||||
|
||||
if (explanation == null) {
|
||||
return null;
|
||||
|
||||
+1
-1
@@ -22,8 +22,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.AggregationsContainer;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -19,12 +19,12 @@ import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.FactoryBeanNotInitializedException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
+177
-116
@@ -15,38 +15,44 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import static org.springframework.data.elasticsearch.client.elc.rest5_client.Rest5Clients.*;
|
||||
import static org.springframework.data.elasticsearch.client.elc.rest_client.RestClients.*;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.TransportOptions;
|
||||
import co.elastic.clients.transport.TransportUtils;
|
||||
import co.elastic.clients.transport.Version;
|
||||
import co.elastic.clients.transport.rest5_client.Rest5ClientOptions;
|
||||
import co.elastic.clients.transport.rest5_client.Rest5ClientTransport;
|
||||
import co.elastic.clients.transport.rest5_client.low_level.RequestOptions;
|
||||
import co.elastic.clients.transport.rest5_client.low_level.Rest5Client;
|
||||
import co.elastic.clients.transport.rest_client.RestClientOptions;
|
||||
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpRequestInterceptor;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.elasticsearch.client.RestClientBuilder;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.support.VersionInfo;
|
||||
import org.springframework.data.elasticsearch.support.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utility class to create the different Elasticsearch clients. The RestClient class is the one used in Elasticsearch
|
||||
* until version 9, it is still available, but it's use is deprecated. The Rest5Client class is the one that should be
|
||||
* used from Elasticsearch 9 on.
|
||||
* Utility class to create the different Elasticsearch clients
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.4
|
||||
@@ -113,32 +119,18 @@ public final class ElasticsearchClients {
|
||||
*
|
||||
* @param restClient the underlying {@link RestClient}
|
||||
* @return the {@link ReactiveElasticsearchClient}
|
||||
* @deprecated since 6.0, use the version with a Rest5Client.
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public static ReactiveElasticsearchClient createReactive(RestClient restClient) {
|
||||
return createReactive(restClient, null, DEFAULT_JSONP_MAPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReactiveElasticsearchClient}.
|
||||
*
|
||||
* @param rest5Client the underlying {@link RestClient}
|
||||
* @return the {@link ReactiveElasticsearchClient}
|
||||
*/
|
||||
public static ReactiveElasticsearchClient createReactive(Rest5Client rest5Client) {
|
||||
return createReactive(rest5Client, null, DEFAULT_JSONP_MAPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReactiveElasticsearchClient}.
|
||||
*
|
||||
* @param restClient the underlying {@link RestClient}
|
||||
* @param transportOptions options to be added to each request.
|
||||
* @return the {@link ReactiveElasticsearchClient}
|
||||
* @deprecated since 6.0, use the version with a Rest5Client.
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public static ReactiveElasticsearchClient createReactive(RestClient restClient,
|
||||
@Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) {
|
||||
|
||||
@@ -147,21 +139,6 @@ public final class ElasticsearchClients {
|
||||
var transport = getElasticsearchTransport(restClient, REACTIVE_CLIENT, transportOptions, jsonpMapper);
|
||||
return createReactive(transport);
|
||||
}
|
||||
/**
|
||||
* Creates a new {@link ReactiveElasticsearchClient}.
|
||||
*
|
||||
* @param rest5Client the underlying {@link RestClient}
|
||||
* @param transportOptions options to be added to each request.
|
||||
* @return the {@link ReactiveElasticsearchClient}
|
||||
*/
|
||||
public static ReactiveElasticsearchClient createReactive(Rest5Client rest5Client,
|
||||
@Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) {
|
||||
|
||||
Assert.notNull(rest5Client, "restClient must not be null");
|
||||
|
||||
var transport = getElasticsearchTransport(rest5Client, REACTIVE_CLIENT, transportOptions, jsonpMapper);
|
||||
return createReactive(transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReactiveElasticsearchClient} that uses the given {@link ElasticsearchTransport}.
|
||||
@@ -179,21 +156,17 @@ public final class ElasticsearchClients {
|
||||
|
||||
// region imperative client
|
||||
/**
|
||||
* Creates a new imperative {@link ElasticsearchClient}. This uses a RestClient, if the old RestClient is needed, this
|
||||
* must be created with the {@link org.springframework.data.elasticsearch.client.elc.rest_client.RestClients} class
|
||||
* and passed in as parameter.
|
||||
* Creates a new imperative {@link ElasticsearchClient}
|
||||
*
|
||||
* @param clientConfiguration configuration options, must not be {@literal null}.
|
||||
* @return the {@link ElasticsearchClient}
|
||||
*/
|
||||
public static ElasticsearchClient createImperative(ClientConfiguration clientConfiguration) {
|
||||
return createImperative(getRest5Client(clientConfiguration), null, DEFAULT_JSONP_MAPPER);
|
||||
return createImperative(getRestClient(clientConfiguration), null, DEFAULT_JSONP_MAPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new imperative {@link ElasticsearchClient}. This uses a RestClient, if the old RestClient is needed, this
|
||||
* must be created with the {@link org.springframework.data.elasticsearch.client.elc.rest_client.RestClients} class
|
||||
* and passed in as parameter.
|
||||
* Creates a new imperative {@link ElasticsearchClient}
|
||||
*
|
||||
* @param clientConfiguration configuration options, must not be {@literal null}.
|
||||
* @param transportOptions options to be added to each request.
|
||||
@@ -201,7 +174,7 @@ public final class ElasticsearchClients {
|
||||
*/
|
||||
public static ElasticsearchClient createImperative(ClientConfiguration clientConfiguration,
|
||||
TransportOptions transportOptions) {
|
||||
return createImperative(getRest5Client(clientConfiguration), transportOptions, DEFAULT_JSONP_MAPPER);
|
||||
return createImperative(getRestClient(clientConfiguration), transportOptions, DEFAULT_JSONP_MAPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,23 +182,11 @@ public final class ElasticsearchClients {
|
||||
*
|
||||
* @param restClient the RestClient to use
|
||||
* @return the {@link ElasticsearchClient}
|
||||
* @deprecated since 6.0, use the version with a Rest5Client.
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public static ElasticsearchClient createImperative(RestClient restClient) {
|
||||
return createImperative(restClient, null, DEFAULT_JSONP_MAPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new imperative {@link ElasticsearchClient}
|
||||
*
|
||||
* @param rest5Client the Rest5Client to use
|
||||
* @return the {@link ElasticsearchClient}
|
||||
*/
|
||||
public static ElasticsearchClient createImperative(Rest5Client rest5Client) {
|
||||
return createImperative(rest5Client, null, DEFAULT_JSONP_MAPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new imperative {@link ElasticsearchClient}
|
||||
*
|
||||
@@ -233,9 +194,7 @@ public final class ElasticsearchClients {
|
||||
* @param transportOptions options to be added to each request.
|
||||
* @param jsonpMapper the mapper for the transport to use
|
||||
* @return the {@link ElasticsearchClient}
|
||||
* @deprecated since 6.0, use the version with a Rest5Client.
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public static ElasticsearchClient createImperative(RestClient restClient, @Nullable TransportOptions transportOptions,
|
||||
JsonpMapper jsonpMapper) {
|
||||
|
||||
@@ -247,27 +206,6 @@ public final class ElasticsearchClients {
|
||||
return createImperative(transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new imperative {@link ElasticsearchClient}
|
||||
*
|
||||
* @param rest5Client the Rest5Client to use
|
||||
* @param transportOptions options to be added to each request.
|
||||
* @param jsonpMapper the mapper for the transport to use
|
||||
* @return the {@link ElasticsearchClient}
|
||||
* @since 6.0
|
||||
*/
|
||||
public static ElasticsearchClient createImperative(Rest5Client rest5Client,
|
||||
@Nullable TransportOptions transportOptions,
|
||||
JsonpMapper jsonpMapper) {
|
||||
|
||||
Assert.notNull(rest5Client, "restClient must not be null");
|
||||
|
||||
ElasticsearchTransport transport = getElasticsearchTransport(rest5Client, IMPERATIVE_CLIENT, transportOptions,
|
||||
jsonpMapper);
|
||||
|
||||
return createImperative(transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ElasticsearchClient} that uses the given {@link ElasticsearchTransport}.
|
||||
*
|
||||
@@ -282,6 +220,96 @@ public final class ElasticsearchClients {
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region low level RestClient
|
||||
private static RestClientOptions.Builder getRestClientOptionsBuilder(@Nullable TransportOptions transportOptions) {
|
||||
|
||||
if (transportOptions instanceof RestClientOptions restClientOptions) {
|
||||
return restClientOptions.toBuilder();
|
||||
}
|
||||
|
||||
var builder = new RestClientOptions.Builder(RequestOptions.DEFAULT.toBuilder());
|
||||
|
||||
if (transportOptions != null) {
|
||||
transportOptions.headers().forEach(header -> builder.addHeader(header.getKey(), header.getValue()));
|
||||
transportOptions.queryParameters().forEach(builder::setParameter);
|
||||
builder.onWarnings(transportOptions.onWarnings());
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a low level {@link RestClient} for the given configuration.
|
||||
*
|
||||
* @param clientConfiguration must not be {@literal null}
|
||||
* @return the {@link RestClient}
|
||||
*/
|
||||
public static RestClient getRestClient(ClientConfiguration clientConfiguration) {
|
||||
return getRestClientBuilder(clientConfiguration).build();
|
||||
}
|
||||
|
||||
private static RestClientBuilder getRestClientBuilder(ClientConfiguration clientConfiguration) {
|
||||
HttpHost[] httpHosts = formattedHosts(clientConfiguration.getEndpoints(), clientConfiguration.useSsl()).stream()
|
||||
.map(HttpHost::create).toArray(HttpHost[]::new);
|
||||
RestClientBuilder builder = RestClient.builder(httpHosts);
|
||||
|
||||
if (clientConfiguration.getPathPrefix() != null) {
|
||||
builder.setPathPrefix(clientConfiguration.getPathPrefix());
|
||||
}
|
||||
|
||||
HttpHeaders headers = clientConfiguration.getDefaultHeaders();
|
||||
|
||||
if (!headers.isEmpty()) {
|
||||
builder.setDefaultHeaders(toHeaderArray(headers));
|
||||
}
|
||||
|
||||
builder.setHttpClientConfigCallback(clientBuilder -> {
|
||||
if (clientConfiguration.getCaFingerprint().isPresent()) {
|
||||
clientBuilder
|
||||
.setSSLContext(TransportUtils.sslContextFromCaFingerprint(clientConfiguration.getCaFingerprint().get()));
|
||||
}
|
||||
clientConfiguration.getSslContext().ifPresent(clientBuilder::setSSLContext);
|
||||
clientConfiguration.getHostNameVerifier().ifPresent(clientBuilder::setSSLHostnameVerifier);
|
||||
clientBuilder.addInterceptorLast(new CustomHeaderInjector(clientConfiguration.getHeadersSupplier()));
|
||||
|
||||
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
|
||||
Duration connectTimeout = clientConfiguration.getConnectTimeout();
|
||||
|
||||
if (!connectTimeout.isNegative()) {
|
||||
requestConfigBuilder.setConnectTimeout(Math.toIntExact(connectTimeout.toMillis()));
|
||||
}
|
||||
|
||||
Duration socketTimeout = clientConfiguration.getSocketTimeout();
|
||||
|
||||
if (!socketTimeout.isNegative()) {
|
||||
requestConfigBuilder.setSocketTimeout(Math.toIntExact(socketTimeout.toMillis()));
|
||||
requestConfigBuilder.setConnectionRequestTimeout(Math.toIntExact(socketTimeout.toMillis()));
|
||||
}
|
||||
|
||||
clientBuilder.setDefaultRequestConfig(requestConfigBuilder.build());
|
||||
|
||||
clientConfiguration.getProxy().map(HttpHost::create).ifPresent(clientBuilder::setProxy);
|
||||
|
||||
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
|
||||
.getClientConfigurers()) {
|
||||
if (clientConfigurer instanceof ElasticsearchHttpClientConfigurationCallback restClientConfigurationCallback) {
|
||||
clientBuilder = restClientConfigurationCallback.configure(clientBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
return clientBuilder;
|
||||
});
|
||||
|
||||
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurationCallback : clientConfiguration
|
||||
.getClientConfigurers()) {
|
||||
if (clientConfigurationCallback instanceof ElasticsearchRestClientConfigurationCallback configurationCallback) {
|
||||
builder = configurationCallback.configure(builder);
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Elasticsearch transport
|
||||
/**
|
||||
* Creates an {@link ElasticsearchTransport} that will use the given client that additionally is customized with a
|
||||
@@ -292,9 +320,7 @@ public final class ElasticsearchClients {
|
||||
* @param transportOptions options for the transport
|
||||
* @param jsonpMapper mapper for the transport
|
||||
* @return ElasticsearchTransport
|
||||
* @deprecated since 6.0, use the version taking a Rest5Client
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public static ElasticsearchTransport getElasticsearchTransport(RestClient restClient, String clientType,
|
||||
@Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) {
|
||||
|
||||
@@ -303,7 +329,7 @@ public final class ElasticsearchClients {
|
||||
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
|
||||
|
||||
TransportOptions.Builder transportOptionsBuilder = transportOptions != null ? transportOptions.toBuilder()
|
||||
: new RestClientOptions(org.elasticsearch.client.RequestOptions.DEFAULT, false).toBuilder();
|
||||
: new RestClientOptions(RequestOptions.DEFAULT, false).toBuilder();
|
||||
|
||||
RestClientOptions.Builder restClientOptionsBuilder = getRestClientOptionsBuilder(transportOptions);
|
||||
|
||||
@@ -327,35 +353,70 @@ public final class ElasticsearchClients {
|
||||
|
||||
return new RestClientTransport(restClient, jsonpMapper, restClientOptionsBuilder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link ElasticsearchTransport} that will use the given client that additionally is customized with a
|
||||
* header to contain the clientType
|
||||
*
|
||||
* @param rest5Client the client to use
|
||||
* @param clientType the client type to pass in each request as header
|
||||
* @param transportOptions options for the transport
|
||||
* @param jsonpMapper mapper for the transport
|
||||
* @return ElasticsearchTransport
|
||||
*/
|
||||
public static ElasticsearchTransport getElasticsearchTransport(Rest5Client rest5Client, String clientType,
|
||||
@Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) {
|
||||
|
||||
Assert.notNull(rest5Client, "restClient must not be null");
|
||||
Assert.notNull(clientType, "clientType must not be null");
|
||||
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
|
||||
|
||||
TransportOptions.Builder transportOptionsBuilder = transportOptions != null ? transportOptions.toBuilder()
|
||||
: new Rest5ClientOptions(RequestOptions.DEFAULT, false).toBuilder();
|
||||
|
||||
Rest5ClientOptions.Builder rest5ClientOptionsBuilder = getRest5ClientOptionsBuilder(transportOptions);
|
||||
|
||||
rest5ClientOptionsBuilder.addHeader(X_SPRING_DATA_ELASTICSEARCH_CLIENT,
|
||||
VersionInfo.clientVersions() + " / " + clientType);
|
||||
|
||||
return new Rest5ClientTransport(rest5Client, jsonpMapper, rest5ClientOptionsBuilder.build());
|
||||
}
|
||||
// endregion
|
||||
|
||||
// todo #3117 remove and document that ElasticsearchHttpClientConfigurationCallback has been move to RestClients.
|
||||
private static List<String> formattedHosts(List<InetSocketAddress> hosts, boolean useSsl) {
|
||||
return hosts.stream().map(it -> (useSsl ? "https" : "http") + "://" + it.getHostString() + ':' + it.getPort())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static org.apache.http.Header[] toHeaderArray(HttpHeaders headers) {
|
||||
return headers.entrySet().stream() //
|
||||
.flatMap(entry -> entry.getValue().stream() //
|
||||
.map(value -> new BasicHeader(entry.getKey(), value))) //
|
||||
.toArray(org.apache.http.Header[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interceptor to inject custom supplied headers.
|
||||
*
|
||||
* @since 4.4
|
||||
*/
|
||||
private record CustomHeaderInjector(Supplier<HttpHeaders> headersSupplier) implements HttpRequestInterceptor {
|
||||
|
||||
@Override
|
||||
public void process(HttpRequest request, HttpContext context) {
|
||||
HttpHeaders httpHeaders = headersSupplier.get();
|
||||
|
||||
if (httpHeaders != null && !httpHeaders.isEmpty()) {
|
||||
Arrays.stream(toHeaderArray(httpHeaders)).forEach(request::addHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
|
||||
* the Elasticsearch RestClient's Http client with a {@link HttpAsyncClientBuilder}
|
||||
*
|
||||
* @since 4.4
|
||||
*/
|
||||
public interface ElasticsearchHttpClientConfigurationCallback
|
||||
extends ClientConfiguration.ClientConfigurationCallback<HttpAsyncClientBuilder> {
|
||||
|
||||
static ElasticsearchHttpClientConfigurationCallback from(
|
||||
Function<HttpAsyncClientBuilder, HttpAsyncClientBuilder> httpClientBuilderCallback) {
|
||||
|
||||
Assert.notNull(httpClientBuilderCallback, "httpClientBuilderCallback must not be null");
|
||||
|
||||
return httpClientBuilderCallback::apply;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
|
||||
* the RestClient client with a {@link RestClientBuilder}
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface ElasticsearchRestClientConfigurationCallback
|
||||
extends ClientConfiguration.ClientConfigurationCallback<RestClientBuilder> {
|
||||
|
||||
static ElasticsearchRestClientConfigurationCallback from(
|
||||
Function<RestClientBuilder, RestClientBuilder> restClientBuilderCallback) {
|
||||
|
||||
Assert.notNull(restClientBuilderCallback, "restClientBuilderCallback must not be null");
|
||||
|
||||
return restClientBuilderCallback::apply;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-23
@@ -17,29 +17,28 @@ package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.json.jackson.Jackson3JsonpMapper;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.TransportOptions;
|
||||
import co.elastic.clients.transport.rest5_client.Rest5ClientOptions;
|
||||
import co.elastic.clients.transport.rest5_client.low_level.RequestOptions;
|
||||
import co.elastic.clients.transport.rest5_client.low_level.Rest5Client;
|
||||
import tools.jackson.databind.cfg.JsonNodeFeature;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
import co.elastic.clients.transport.rest_client.RestClientOptions;
|
||||
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.client.elc.rest5_client.Rest5Clients;
|
||||
import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
/**
|
||||
* Base class for a @{@link org.springframework.context.annotation.Configuration} class to set up the Elasticsearch
|
||||
* connection using the Elasticsearch Client. This class exposes different parts of the setup as Spring beans. Deriving
|
||||
* classes must provide the {@link ClientConfiguration} to use. From Version 6.0 on, this class uses the new Rest5Client
|
||||
* from Elasticsearch 9. The old implementation using the RestClient is still available under the name
|
||||
* {@link ElasticsearchLegacyRestClientConfiguration}.
|
||||
* classes must provide the {@link ClientConfiguration} to use.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.4
|
||||
@@ -61,27 +60,27 @@ public abstract class ElasticsearchConfiguration extends ElasticsearchConfigurat
|
||||
* @return RestClient
|
||||
*/
|
||||
@Bean
|
||||
public Rest5Client elasticsearchRest5Client(ClientConfiguration clientConfiguration) {
|
||||
public RestClient elasticsearchRestClient(ClientConfiguration clientConfiguration) {
|
||||
|
||||
Assert.notNull(clientConfiguration, "clientConfiguration must not be null");
|
||||
|
||||
return Rest5Clients.getRest5Client(clientConfiguration);
|
||||
return ElasticsearchClients.getRestClient(clientConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the Elasticsearch transport to be used. The default implementation uses the {@link Rest5Client} bean and
|
||||
* Provides the Elasticsearch transport to be used. The default implementation uses the {@link RestClient} bean and
|
||||
* the {@link JsonpMapper} bean provided in this class.
|
||||
*
|
||||
* @return the {@link ElasticsearchTransport}
|
||||
* @since 5.2
|
||||
*/
|
||||
@Bean
|
||||
public ElasticsearchTransport elasticsearchTransport(Rest5Client rest5Client, JsonpMapper jsonpMapper) {
|
||||
public ElasticsearchTransport elasticsearchTransport(RestClient restClient, JsonpMapper jsonpMapper) {
|
||||
|
||||
Assert.notNull(rest5Client, "restClient must not be null");
|
||||
Assert.notNull(restClient, "restClient must not be null");
|
||||
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
|
||||
|
||||
return ElasticsearchClients.getElasticsearchTransport(rest5Client, ElasticsearchClients.IMPERATIVE_CLIENT,
|
||||
return ElasticsearchClients.getElasticsearchTransport(restClient, ElasticsearchClients.IMPERATIVE_CLIENT,
|
||||
transportOptions(), jsonpMapper);
|
||||
}
|
||||
|
||||
@@ -116,7 +115,7 @@ public abstract class ElasticsearchConfiguration extends ElasticsearchConfigurat
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the JsonpMapper bean that is used in the {@link #elasticsearchTransport(Rest5Client, JsonpMapper)} method.
|
||||
* Provides the JsonpMapper bean that is used in the {@link #elasticsearchTransport(RestClient, JsonpMapper)} method.
|
||||
*
|
||||
* @return the {@link JsonpMapper} to use
|
||||
* @since 5.2
|
||||
@@ -126,17 +125,16 @@ public abstract class ElasticsearchConfiguration extends ElasticsearchConfigurat
|
||||
// we need to create our own objectMapper that keeps null values in order to provide the storeNullValue
|
||||
// functionality. The one Elasticsearch would provide removes the nulls. We remove unwanted nulls before they get
|
||||
// into this mapper, so we can safely keep them here.
|
||||
JsonMapper jsonMapper = JsonMapper.builder()
|
||||
.enable(JsonNodeFeature.WRITE_NULL_PROPERTIES)
|
||||
.enable(JsonNodeFeature.READ_NULL_PROPERTIES)
|
||||
.build();
|
||||
return new Jackson3JsonpMapper(jsonMapper);
|
||||
var objectMapper = (new ObjectMapper())
|
||||
.configure(SerializationFeature.INDENT_OUTPUT, false)
|
||||
.setSerializationInclusion(JsonInclude.Include.ALWAYS);
|
||||
return new JacksonJsonpMapper(objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the options that should be added to every request. Must not be {@literal null}
|
||||
*/
|
||||
public TransportOptions transportOptions() {
|
||||
return new Rest5ClientOptions(RequestOptions.DEFAULT, false);
|
||||
return new RestClientOptions(RequestOptions.DEFAULT, false);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-13
@@ -24,7 +24,6 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.elasticsearch.client.ResponseException;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
@@ -34,7 +33,6 @@ import org.springframework.data.elasticsearch.NoSuchIndexException;
|
||||
import org.springframework.data.elasticsearch.ResourceNotFoundException;
|
||||
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.VersionConflictException;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Simple {@link PersistenceExceptionTranslator} for Elasticsearch. Convert the given runtime exception to an
|
||||
@@ -47,9 +45,6 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
public class ElasticsearchExceptionTranslator implements PersistenceExceptionTranslator {
|
||||
|
||||
public static final boolean LEGACY_RESTCLIENT_PRESENT = ClassUtils
|
||||
.isPresent("org.elasticsearch.client.ResponseException", ElasticsearchExceptionTranslator.class.getClassLoader());
|
||||
|
||||
private final JsonpMapper jsonpMapper;
|
||||
|
||||
public ElasticsearchExceptionTranslator(JsonpMapper jsonpMapper) {
|
||||
@@ -73,7 +68,7 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
|
||||
checkForConflictException(ex);
|
||||
|
||||
@@ -123,20 +118,15 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
|
||||
Integer status = null;
|
||||
String message = null;
|
||||
|
||||
if (LEGACY_RESTCLIENT_PRESENT && exception instanceof ResponseException responseException) {
|
||||
// this code is for the old RestClient
|
||||
if (exception instanceof ResponseException responseException) {
|
||||
status = responseException.getResponse().getStatusLine().getStatusCode();
|
||||
message = responseException.getMessage();
|
||||
} else if (exception instanceof ElasticsearchException elasticsearchException) {
|
||||
// using the RestClient throws this
|
||||
status = elasticsearchException.status();
|
||||
message = elasticsearchException.getMessage();
|
||||
} else if (exception.getCause() != null) {
|
||||
checkForConflictException(exception.getCause());
|
||||
}
|
||||
|
||||
if (status != null && message != null) {
|
||||
if (status == 409 && message.contains("version_conflict_engine_exception"))
|
||||
if (status == 409 && message.contains("type\":\"version_conflict_engine_exception"))
|
||||
if (message.contains("version conflict, required seqNo")) {
|
||||
throw new OptimisticLockingFailureException("Cannot index a document due to seq_no+primary_term conflict",
|
||||
exception);
|
||||
|
||||
-144
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.TransportOptions;
|
||||
import co.elastic.clients.transport.rest_client.RestClientOptions;
|
||||
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.client.elc.rest_client.RestClients;
|
||||
import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
/**
|
||||
* Base class for a @{@link org.springframework.context.annotation.Configuration} class to set up the Elasticsearch
|
||||
* connection using the Elasticsearch Client. This class exposes different parts of the setup as Spring beans. Deriving
|
||||
* classes must provide the {@link ClientConfiguration} to use. <br/>
|
||||
* This class uses the Elasticsearch RestClient which was replaced by the Rest5Client in Elasticsearch 9. It is still
|
||||
* available here but deprecated.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.4
|
||||
* @deprecated since 6.0, use {@link ElasticsearchConfiguration}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public abstract class ElasticsearchLegacyRestClientConfiguration extends ElasticsearchConfigurationSupport {
|
||||
|
||||
/**
|
||||
* Must be implemented by deriving classes to provide the {@link ClientConfiguration}.
|
||||
*
|
||||
* @return configuration, must not be {@literal null}
|
||||
*/
|
||||
@Bean(name = "elasticsearchClientConfiguration")
|
||||
public abstract ClientConfiguration clientConfiguration();
|
||||
|
||||
/**
|
||||
* Provides the underlying low level Elasticsearch RestClient.
|
||||
*
|
||||
* @param clientConfiguration configuration for the client, must not be {@literal null}
|
||||
* @return RestClient
|
||||
*/
|
||||
@Bean
|
||||
public RestClient elasticsearchRestClient(ClientConfiguration clientConfiguration) {
|
||||
|
||||
Assert.notNull(clientConfiguration, "clientConfiguration must not be null");
|
||||
|
||||
return RestClients.getRestClient(clientConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the Elasticsearch transport to be used. The default implementation uses the {@link RestClient} bean and
|
||||
* the {@link JsonpMapper} bean provided in this class.
|
||||
*
|
||||
* @return the {@link ElasticsearchTransport}
|
||||
* @since 5.2
|
||||
*/
|
||||
@Bean
|
||||
public ElasticsearchTransport elasticsearchTransport(RestClient restClient, JsonpMapper jsonpMapper) {
|
||||
|
||||
Assert.notNull(restClient, "restClient must not be null");
|
||||
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
|
||||
|
||||
return ElasticsearchClients.getElasticsearchTransport(restClient, ElasticsearchClients.IMPERATIVE_CLIENT,
|
||||
transportOptions(), jsonpMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the {@link ElasticsearchClient} to be used.
|
||||
*
|
||||
* @param transport the {@link ElasticsearchTransport} to use
|
||||
* @return ElasticsearchClient instance
|
||||
*/
|
||||
@Bean
|
||||
public ElasticsearchClient elasticsearchClient(ElasticsearchTransport transport) {
|
||||
|
||||
Assert.notNull(transport, "transport must not be null");
|
||||
|
||||
return ElasticsearchClients.createImperative(transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ElasticsearchOperations} implementation using an {@link ElasticsearchClient}.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
@Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" })
|
||||
public ElasticsearchOperations elasticsearchOperations(ElasticsearchConverter elasticsearchConverter,
|
||||
ElasticsearchClient elasticsearchClient) {
|
||||
|
||||
ElasticsearchTemplate template = new ElasticsearchTemplate(elasticsearchClient, elasticsearchConverter);
|
||||
template.setRefreshPolicy(refreshPolicy());
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the JsonpMapper bean that is used in the {@link #elasticsearchTransport(RestClient, JsonpMapper)} method.
|
||||
*
|
||||
* @return the {@link JsonpMapper} to use
|
||||
* @since 5.2
|
||||
*/
|
||||
@Bean
|
||||
public JsonpMapper jsonpMapper() {
|
||||
// we need to create our own objectMapper that keeps null values in order to provide the storeNullValue
|
||||
// functionality. The one Elasticsearch would provide removes the nulls. We remove unwanted nulls before they get
|
||||
// into this mapper, so we can safely keep them here.
|
||||
var objectMapper = (new ObjectMapper())
|
||||
.configure(SerializationFeature.INDENT_OUTPUT, false)
|
||||
.setSerializationInclusion(JsonInclude.Include.ALWAYS);
|
||||
return new JacksonJsonpMapper(objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the options that should be added to every request. Must not be {@literal null}
|
||||
*/
|
||||
public TransportOptions transportOptions() {
|
||||
return new RestClientOptions(RequestOptions.DEFAULT, false);
|
||||
}
|
||||
}
|
||||
-99
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import io.micrometer.common.docs.KeyName;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationConvention;
|
||||
import io.micrometer.observation.docs.ObservationDocumentation;
|
||||
|
||||
/**
|
||||
* {@link ObservationDocumentation} for Spring Data Elasticsearch template operations.
|
||||
*
|
||||
* @author maryantocinn
|
||||
* @since 6.1
|
||||
*/
|
||||
public enum ElasticsearchObservation implements ObservationDocumentation {
|
||||
|
||||
/**
|
||||
* Timer created around a Spring Data Elasticsearch template operation.
|
||||
*/
|
||||
ELASTICSEARCH_COMMAND_OBSERVATION {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "spring.data.elasticsearch.command";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ObservationConvention<? extends Observation.Context>> getDefaultConvention() {
|
||||
return DefaultElasticsearchObservationConvention.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyName[] getLowCardinalityKeyNames() {
|
||||
return LowCardinalityKeyNames.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyName[] getHighCardinalityKeyNames() {
|
||||
return HighCardinalityKeyNames.values();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Low cardinality key names for Spring Data Elasticsearch observations. These become metric dimensions and MUST be
|
||||
* present on every observation to satisfy backends like Prometheus that require consistent tag key sets.
|
||||
*/
|
||||
enum LowCardinalityKeyNames implements KeyName {
|
||||
|
||||
/**
|
||||
* The Spring Data operation being performed (e.g., save, search, delete, bulk).
|
||||
*/
|
||||
OPERATION {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "spring.data.operation";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The target collection (index) name. Only present when the operation targets a specific index.
|
||||
*/
|
||||
COLLECTION {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "spring.data.collection";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* High cardinality key names for Spring Data Elasticsearch observations. These appear only on traces/spans, not on
|
||||
* metrics, because their values are unbounded or optional per operation.
|
||||
*/
|
||||
enum HighCardinalityKeyNames implements KeyName {
|
||||
|
||||
/**
|
||||
* The number of operations included in a batch (bulk) request. Only present for bulk operations.
|
||||
*/
|
||||
BATCH_SIZE {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "spring.data.batch.size";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
|
||||
/**
|
||||
* {@link Observation.Context} for Spring Data Elasticsearch operations. One instance is created per observed operation.
|
||||
* It carries contextual data that conventions use to produce observation names and key-values.
|
||||
*
|
||||
* @author maryantocinn
|
||||
* @since 6.1
|
||||
*/
|
||||
public class ElasticsearchObservationContext extends Observation.Context {
|
||||
|
||||
private final ElasticsearchOperationName operationName;
|
||||
@Nullable private final IndexCoordinates indexCoordinates;
|
||||
@Nullable private Integer batchSize;
|
||||
|
||||
public ElasticsearchObservationContext(ElasticsearchOperationName operationName,
|
||||
@Nullable IndexCoordinates indexCoordinates) {
|
||||
this.operationName = operationName;
|
||||
this.indexCoordinates = indexCoordinates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Spring Data operation being performed.
|
||||
*/
|
||||
public ElasticsearchOperationName getOperationName() {
|
||||
return operationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the target index coordinates, or {@literal null} if the operation is not index-specific.
|
||||
*/
|
||||
@Nullable
|
||||
public IndexCoordinates getIndexCoordinates() {
|
||||
return indexCoordinates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the comma-joined index name(s), or {@literal null} if no index coordinates are set.
|
||||
*/
|
||||
@Nullable
|
||||
public String getIndexName() {
|
||||
return indexCoordinates != null ? String.join(",", indexCoordinates.getIndexNames()) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the batch size, or {@literal null} if not a batch operation.
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of operations included in a batch (bulk) request.
|
||||
*
|
||||
* @param batchSize the batch size, can be {@literal null}
|
||||
*/
|
||||
public void setBatchSize(@Nullable Integer batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationConvention;
|
||||
|
||||
/**
|
||||
* {@link ObservationConvention} for Spring Data Elasticsearch operations. Implement this interface and register it as a
|
||||
* bean to customize observation names and key-values.
|
||||
*
|
||||
* @author maryantocinn
|
||||
* @since 6.1
|
||||
*/
|
||||
public interface ElasticsearchObservationConvention extends ObservationConvention<ElasticsearchObservationContext> {
|
||||
|
||||
@Override
|
||||
default boolean supportsContext(Observation.Context context) {
|
||||
return context instanceof ElasticsearchObservationContext;
|
||||
}
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
/**
|
||||
* Enumeration of Spring Data Elasticsearch operation names used in observations.
|
||||
*
|
||||
* @author maryantocinn
|
||||
* @since 6.1
|
||||
*/
|
||||
public enum ElasticsearchOperationName {
|
||||
|
||||
SAVE("save"), //
|
||||
INDEX("index"), //
|
||||
GET("get"), //
|
||||
MULTI_GET("multiGet"), //
|
||||
EXISTS("exists"), //
|
||||
DELETE("delete"), //
|
||||
DELETE_BY_QUERY("deleteByQuery"), //
|
||||
BULK("bulk"), //
|
||||
UPDATE("update"), //
|
||||
UPDATE_BY_QUERY("updateByQuery"), //
|
||||
COUNT("count"), //
|
||||
SEARCH("search");
|
||||
|
||||
private final String value;
|
||||
|
||||
ElasticsearchOperationName(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the operation name as a string value used in observation key values.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
+57
-161
@@ -17,11 +17,29 @@ package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.elasticsearch._types.Time;
|
||||
import co.elastic.clients.elasticsearch.core.*;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
|
||||
import co.elastic.clients.elasticsearch.core.msearch.MultiSearchResponseItem;
|
||||
import co.elastic.clients.elasticsearch.core.search.ResponseBody;
|
||||
import co.elastic.clients.elasticsearch.sql.ElasticsearchSqlClient;
|
||||
import co.elastic.clients.elasticsearch.sql.QueryResponse;
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.transport.Version;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.elasticsearch.BulkFailureException;
|
||||
import org.springframework.data.elasticsearch.client.UnsupportedBackendOperation;
|
||||
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate;
|
||||
@@ -41,32 +59,9 @@ import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
|
||||
import org.springframework.data.elasticsearch.core.reindex.ReindexResponse;
|
||||
import org.springframework.data.elasticsearch.core.script.Script;
|
||||
import org.springframework.data.elasticsearch.core.sql.SqlResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.elasticsearch._types.Time;
|
||||
import co.elastic.clients.elasticsearch.core.*;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
|
||||
import co.elastic.clients.elasticsearch.core.msearch.MultiSearchResponseItem;
|
||||
import co.elastic.clients.elasticsearch.core.search.ResponseBody;
|
||||
import co.elastic.clients.elasticsearch.sql.ElasticsearchSqlClient;
|
||||
import co.elastic.clients.elasticsearch.sql.QueryResponse;
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.transport.Version;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
/**
|
||||
* Implementation of {@link org.springframework.data.elasticsearch.core.ElasticsearchOperations} using the new
|
||||
* Elasticsearch client.
|
||||
@@ -75,15 +70,12 @@ import io.micrometer.observation.ObservationRegistry;
|
||||
* @author Hamid Rahimi
|
||||
* @author Illia Ulianov
|
||||
* @author Haibo Liu
|
||||
* @author maryantocinn
|
||||
* @since 4.4
|
||||
*/
|
||||
public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
|
||||
private static final Log LOGGER = LogFactory.getLog(ElasticsearchTemplate.class);
|
||||
|
||||
@Nullable private ElasticsearchObservationConvention observationConvention;
|
||||
|
||||
private final ElasticsearchClient client;
|
||||
private final ElasticsearchSqlClient sqlClient;
|
||||
private final RequestConverter requestConverter;
|
||||
@@ -121,61 +113,6 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
protected AbstractElasticsearchTemplate doCopy() {
|
||||
return new ElasticsearchTemplate(client, elasticsearchConverter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeCopy(AbstractElasticsearchTemplate copy) {
|
||||
|
||||
if (copy instanceof ElasticsearchTemplate elasticsearchTemplate) {
|
||||
elasticsearchTemplate.observationConvention = this.observationConvention;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
|
||||
super.setApplicationContext(applicationContext);
|
||||
|
||||
if (observationRegistry == ObservationRegistry.NOOP) {
|
||||
applicationContext.getBeanProvider(ObservationRegistry.class).ifAvailable(this::setObservationRegistry);
|
||||
}
|
||||
|
||||
if (observationConvention == null) {
|
||||
applicationContext.getBeanProvider(ElasticsearchObservationConvention.class)
|
||||
.ifAvailable(this::setObservationConvention);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a custom {@link ElasticsearchObservationConvention} to override the default convention.
|
||||
*
|
||||
* @param observationConvention can be {@literal null}.
|
||||
* @since 6.1
|
||||
*/
|
||||
public void setObservationConvention(@Nullable ElasticsearchObservationConvention observationConvention) {
|
||||
this.observationConvention = observationConvention;
|
||||
}
|
||||
|
||||
private <T> T observe(ElasticsearchOperationName operationName, @Nullable IndexCoordinates index,
|
||||
Supplier<T> action) {
|
||||
Observation observation = createObservation(operationName, index, null);
|
||||
return observation.observe(action);
|
||||
}
|
||||
|
||||
private <T> T observe(ElasticsearchOperationName operationName, @Nullable IndexCoordinates index, int batchSize,
|
||||
Supplier<T> action) {
|
||||
Observation observation = createObservation(operationName, index, batchSize);
|
||||
return observation.observe(action);
|
||||
}
|
||||
|
||||
private Observation createObservation(ElasticsearchOperationName operationName, @Nullable IndexCoordinates index,
|
||||
@Nullable Integer batchSize) {
|
||||
|
||||
ElasticsearchObservationContext context = new ElasticsearchObservationContext(operationName, index);
|
||||
context.setBatchSize(batchSize);
|
||||
|
||||
return ElasticsearchObservation.ELASTICSEARCH_COMMAND_OBSERVATION.observation(observationConvention,
|
||||
DefaultElasticsearchObservationConvention.INSTANCE, () -> context, observationRegistry);
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region child templates
|
||||
@@ -200,45 +137,16 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
// endregion
|
||||
|
||||
// region document operations
|
||||
@Override
|
||||
public <T> T save(T entity, IndexCoordinates index) {
|
||||
return observe(ElasticsearchOperationName.SAVE, index, () -> super.save(entity, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String index(IndexQuery query, IndexCoordinates index) {
|
||||
return observe(ElasticsearchOperationName.INDEX, index, () -> super.index(query, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String id, IndexCoordinates index) {
|
||||
return observe(ElasticsearchOperationName.EXISTS, index, () -> super.exists(id, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String delete(String id, IndexCoordinates index) {
|
||||
return observe(ElasticsearchOperationName.DELETE, index, () -> super.delete(id, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IndexedObjectInformation> bulkOperation(List<?> queries, BulkOptions bulkOptions,
|
||||
IndexCoordinates index) {
|
||||
return observe(ElasticsearchOperationName.BULK, index, queries.size(),
|
||||
() -> super.bulkOperation(queries, bulkOptions, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T get(String id, Class<T> clazz, IndexCoordinates index) {
|
||||
|
||||
return observe(ElasticsearchOperationName.GET, index, () -> {
|
||||
GetRequest getRequest = requestConverter.documentGetRequest(elasticsearchConverter.convertId(id),
|
||||
routingResolver.getRouting(), index);
|
||||
GetResponse<EntityAsMap> getResponse = execute(client -> client.get(getRequest, EntityAsMap.class));
|
||||
GetRequest getRequest = requestConverter.documentGetRequest(elasticsearchConverter.convertId(id),
|
||||
routingResolver.getRouting(), index);
|
||||
GetResponse<EntityAsMap> getResponse = execute(client -> client.get(getRequest, EntityAsMap.class));
|
||||
|
||||
ReadDocumentCallback<T> callback = new ReadDocumentCallback<>(elasticsearchConverter, clazz, index);
|
||||
return callback.doWith(DocumentAdapters.from(getResponse));
|
||||
});
|
||||
ReadDocumentCallback<T> callback = new ReadDocumentCallback<>(elasticsearchConverter, clazz, index);
|
||||
return callback.doWith(DocumentAdapters.from(getResponse));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -247,17 +155,15 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
Assert.notNull(query, "query must not be null");
|
||||
Assert.notNull(clazz, "clazz must not be null");
|
||||
|
||||
return observe(ElasticsearchOperationName.MULTI_GET, index, () -> {
|
||||
MgetRequest request = requestConverter.documentMgetRequest(query, clazz, index);
|
||||
MgetResponse<EntityAsMap> result = execute(client -> client.mget(request, EntityAsMap.class));
|
||||
MgetRequest request = requestConverter.documentMgetRequest(query, clazz, index);
|
||||
MgetResponse<EntityAsMap> result = execute(client -> client.mget(request, EntityAsMap.class));
|
||||
|
||||
ReadDocumentCallback<T> callback = new ReadDocumentCallback<>(elasticsearchConverter, clazz, index);
|
||||
ReadDocumentCallback<T> callback = new ReadDocumentCallback<>(elasticsearchConverter, clazz, index);
|
||||
|
||||
return DocumentAdapters.from(result).stream() //
|
||||
.map(multiGetItem -> MultiGetItem.of( //
|
||||
multiGetItem.isFailed() ? null : callback.doWith(multiGetItem.getItem()), multiGetItem.getFailure())) //
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
return DocumentAdapters.from(result).stream() //
|
||||
.map(multiGetItem -> MultiGetItem.of( //
|
||||
multiGetItem.isFailed() ? null : callback.doWith(multiGetItem.getItem()), multiGetItem.getFailure())) //
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -279,26 +185,22 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
public ByQueryResponse delete(DeleteQuery query, Class<?> clazz, IndexCoordinates index) {
|
||||
Assert.notNull(query, "query must not be null");
|
||||
|
||||
return observe(ElasticsearchOperationName.DELETE_BY_QUERY, index, () -> {
|
||||
DeleteByQueryRequest request = requestConverter.documentDeleteByQueryRequest(query, routingResolver.getRouting(),
|
||||
clazz, index, getRefreshPolicy());
|
||||
DeleteByQueryRequest request = requestConverter.documentDeleteByQueryRequest(query, routingResolver.getRouting(),
|
||||
clazz, index, getRefreshPolicy());
|
||||
|
||||
DeleteByQueryResponse response = execute(client -> client.deleteByQuery(request));
|
||||
DeleteByQueryResponse response = execute(client -> client.deleteByQuery(request));
|
||||
|
||||
return responseConverter.byQueryResponse(response);
|
||||
});
|
||||
return responseConverter.byQueryResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateResponse update(UpdateQuery updateQuery, IndexCoordinates index) {
|
||||
|
||||
return observe(ElasticsearchOperationName.UPDATE, index, () -> {
|
||||
UpdateRequest<Document, ?> request = requestConverter.documentUpdateRequest(updateQuery, index,
|
||||
getRefreshPolicy(), routingResolver.getRouting());
|
||||
co.elastic.clients.elasticsearch.core.UpdateResponse<Document> response = execute(
|
||||
client -> client.update(request, Document.class));
|
||||
return UpdateResponse.of(result(response.result()));
|
||||
});
|
||||
UpdateRequest<Document, ?> request = requestConverter.documentUpdateRequest(updateQuery, index, getRefreshPolicy(),
|
||||
routingResolver.getRouting());
|
||||
co.elastic.clients.elasticsearch.core.UpdateResponse<Document> response = execute(
|
||||
client -> client.update(request, Document.class));
|
||||
return UpdateResponse.of(result(response.result()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -307,13 +209,11 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
Assert.notNull(updateQuery, "updateQuery must not be null");
|
||||
Assert.notNull(index, "index must not be null");
|
||||
|
||||
return observe(ElasticsearchOperationName.UPDATE_BY_QUERY, index, () -> {
|
||||
UpdateByQueryRequest request = requestConverter.documentUpdateByQueryRequest(updateQuery, index,
|
||||
getRefreshPolicy());
|
||||
UpdateByQueryRequest request = requestConverter.documentUpdateByQueryRequest(updateQuery, index,
|
||||
getRefreshPolicy());
|
||||
|
||||
UpdateByQueryResponse byQueryResponse = execute(client -> client.updateByQuery(request));
|
||||
return responseConverter.byQueryResponse(byQueryResponse);
|
||||
});
|
||||
UpdateByQueryResponse byQueryResponse = execute(client -> client.updateByQuery(request));
|
||||
return responseConverter.byQueryResponse(byQueryResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -428,14 +328,12 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
Assert.notNull(query, "query must not be null");
|
||||
Assert.notNull(index, "index must not be null");
|
||||
|
||||
return observe(ElasticsearchOperationName.COUNT, index, () -> {
|
||||
SearchRequest searchRequest = requestConverter.searchRequest(query, routingResolver.getRouting(), clazz, index,
|
||||
true);
|
||||
SearchRequest searchRequest = requestConverter.searchRequest(query, routingResolver.getRouting(), clazz, index,
|
||||
true);
|
||||
|
||||
SearchResponse<EntityAsMap> searchResponse = execute(client -> client.search(searchRequest, EntityAsMap.class));
|
||||
SearchResponse<EntityAsMap> searchResponse = execute(client -> client.search(searchRequest, EntityAsMap.class));
|
||||
|
||||
return searchResponse.hits().total().value();
|
||||
});
|
||||
return searchResponse.hits().total().value();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -445,13 +343,11 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
Assert.notNull(clazz, "clazz must not be null");
|
||||
Assert.notNull(index, "index must not be null");
|
||||
|
||||
return observe(ElasticsearchOperationName.SEARCH, index, () -> {
|
||||
if (query instanceof SearchTemplateQuery searchTemplateQuery) {
|
||||
return doSearch(searchTemplateQuery, clazz, index);
|
||||
} else {
|
||||
return doSearch(query, clazz, index);
|
||||
}
|
||||
});
|
||||
if (query instanceof SearchTemplateQuery searchTemplateQuery) {
|
||||
return doSearch(searchTemplateQuery, clazz, index);
|
||||
} else {
|
||||
return doSearch(query, clazz, index);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> SearchHits<T> doSearch(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||
@@ -762,7 +658,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
QueryResponse response = sqlClient.query(requestConverter.sqlQueryRequest(query));
|
||||
|
||||
return responseConverter.sqlResponse(response);
|
||||
} catch (Exception e) {
|
||||
} catch (IOException e) {
|
||||
throw exceptionTranslator.translateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-10
@@ -17,12 +17,9 @@ package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*;
|
||||
|
||||
import co.elastic.clients.util.NamedValue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.elasticsearch.core.query.highlight.Highlight;
|
||||
@@ -30,6 +27,7 @@ import org.springframework.data.elasticsearch.core.query.highlight.HighlightFiel
|
||||
import org.springframework.data.elasticsearch.core.query.highlight.HighlightFieldParameters;
|
||||
import org.springframework.data.elasticsearch.core.query.highlight.HighlightParameters;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -45,8 +43,7 @@ class HighlightQueryBuilder {
|
||||
private final RequestConverter requestConverter;
|
||||
|
||||
HighlightQueryBuilder(
|
||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext,
|
||||
RequestConverter requestConverter) {
|
||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext, RequestConverter requestConverter) {
|
||||
this.mappingContext = mappingContext;
|
||||
this.requestConverter = requestConverter;
|
||||
}
|
||||
@@ -62,11 +59,10 @@ class HighlightQueryBuilder {
|
||||
|
||||
for (HighlightField highlightField : highlight.getFields()) {
|
||||
String mappedName = mapFieldName(highlightField.getName(), type);
|
||||
highlightBuilder.fields(
|
||||
NamedValue.of(mappedName, co.elastic.clients.elasticsearch.core.search.HighlightField.of(hf -> {
|
||||
addParameters(highlightField.getParameters(), hf, type);
|
||||
return hf;
|
||||
})));
|
||||
highlightBuilder.fields(mappedName, hf -> {
|
||||
addParameters(highlightField.getParameters(), hf, type);
|
||||
return hf;
|
||||
});
|
||||
}
|
||||
|
||||
return highlightBuilder.build();
|
||||
|
||||
+8
-14
@@ -27,10 +27,8 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.elasticsearch.ResourceNotFoundException;
|
||||
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
||||
import org.springframework.data.elasticsearch.core.IndexInformation;
|
||||
@@ -51,6 +49,7 @@ import org.springframework.data.elasticsearch.core.mapping.Alias;
|
||||
import org.springframework.data.elasticsearch.core.mapping.CreateIndexSettings;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -114,7 +113,7 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean create(Map<String, @Nullable Object> settings) {
|
||||
public boolean create(Map<String, Object> settings) {
|
||||
|
||||
Assert.notNull(settings, "settings must not be null");
|
||||
|
||||
@@ -122,7 +121,7 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean create(Map<String, @Nullable Object> settings, Document mapping) {
|
||||
public boolean create(Map<String, Object> settings, Document mapping) {
|
||||
|
||||
Assert.notNull(settings, "settings must not be null");
|
||||
Assert.notNull(mapping, "mapping must not be null");
|
||||
@@ -135,7 +134,7 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
|
||||
return doCreate(getIndexCoordinates(), createSettings(), createMapping());
|
||||
}
|
||||
|
||||
protected boolean doCreate(IndexCoordinates indexCoordinates, Map<String, @Nullable Object> settings,
|
||||
protected boolean doCreate(IndexCoordinates indexCoordinates, Map<String, Object> settings,
|
||||
@Nullable Document mapping) {
|
||||
Set<Alias> aliases = (boundClass != null) ? getAliasesFor(boundClass) : new HashSet<>();
|
||||
CreateIndexSettings indexSettings = CreateIndexSettings.builder(indexCoordinates)
|
||||
@@ -233,7 +232,7 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, @Nullable Object> getMapping() {
|
||||
public Map<String, Object> getMapping() {
|
||||
|
||||
IndexCoordinates indexCoordinates = getIndexCoordinates();
|
||||
GetMappingRequest getMappingRequest = requestConverter.indicesGetMappingRequest(indexCoordinates);
|
||||
@@ -316,20 +315,15 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable TemplateData getTemplate(GetTemplateRequest getTemplateRequest) {
|
||||
public TemplateData getTemplate(GetTemplateRequest getTemplateRequest) {
|
||||
|
||||
Assert.notNull(getTemplateRequest, "getTemplateRequest must not be null");
|
||||
|
||||
co.elastic.clients.elasticsearch.indices.GetTemplateRequest getTemplateRequestES = requestConverter
|
||||
.indicesGetTemplateRequest(getTemplateRequest);
|
||||
GetTemplateResponse getTemplateResponse = execute(client -> client.getTemplate(getTemplateRequestES));
|
||||
|
||||
try {
|
||||
GetTemplateResponse getTemplateResponse = execute(client -> client.getTemplate(getTemplateRequestES));
|
||||
return responseConverter.indicesGetTemplateData(getTemplateResponse, getTemplateRequest.getTemplateName());
|
||||
} catch (ResourceNotFoundException e) {
|
||||
// since Elasticsearch 9.1.0 we get an exception (404) instead of an empty result
|
||||
return null;
|
||||
}
|
||||
return responseConverter.indicesGetTemplateData(getTemplateResponse, getTemplateRequest.getTemplateName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
@@ -48,7 +48,7 @@ final class JsonUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String queryToJson(co.elastic.clients.elasticsearch._types.query_dsl.@Nullable Query query,
|
||||
public static String queryToJson(@Nullable co.elastic.clients.elasticsearch._types.query_dsl.Query query,
|
||||
JsonpMapper mapper) {
|
||||
|
||||
if (query == null) {
|
||||
|
||||
@@ -28,8 +28,8 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.query.BaseQuery;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -44,7 +44,7 @@ import org.springframework.util.Assert;
|
||||
public class NativeQuery extends BaseQuery {
|
||||
|
||||
@Nullable private final Query query;
|
||||
private org.springframework.data.elasticsearch.core.query.@Nullable Query springDataQuery;
|
||||
@Nullable private org.springframework.data.elasticsearch.core.query.Query springDataQuery;
|
||||
@Nullable private Query filter;
|
||||
// note: the new client does not have pipeline aggs, these are just set up as normal aggs
|
||||
private final Map<String, Aggregation> aggregations = new LinkedHashMap<>();
|
||||
@@ -117,7 +117,7 @@ public class NativeQuery extends BaseQuery {
|
||||
* @see NativeQueryBuilder#withQuery(org.springframework.data.elasticsearch.core.query.Query).
|
||||
* @since 5.1
|
||||
*/
|
||||
public void setSpringDataQuery(org.springframework.data.elasticsearch.core.query.@Nullable Query springDataQuery) {
|
||||
public void setSpringDataQuery(@Nullable org.springframework.data.elasticsearch.core.query.Query springDataQuery) {
|
||||
this.springDataQuery = springDataQuery;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,8 @@ public class NativeQuery extends BaseQuery {
|
||||
return knnSearches;
|
||||
}
|
||||
|
||||
public org.springframework.data.elasticsearch.core.query.@Nullable Query getSpringDataQuery() {
|
||||
@Nullable
|
||||
public org.springframework.data.elasticsearch.core.query.Query getSpringDataQuery() {
|
||||
return springDataQuery;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -33,8 +33,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.query.BaseQueryBuilder;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -53,7 +53,7 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
|
||||
private final List<SortOptions> sortOptions = new ArrayList<>();
|
||||
private final Map<String, JsonData> searchExtensions = new LinkedHashMap<>();
|
||||
|
||||
private org.springframework.data.elasticsearch.core.query.@Nullable Query springDataQuery;
|
||||
@Nullable private org.springframework.data.elasticsearch.core.query.Query springDataQuery;
|
||||
@Nullable private KnnQuery knnQuery;
|
||||
@Nullable private List<KnnSearch> knnSearches = Collections.emptyList();
|
||||
|
||||
@@ -104,7 +104,8 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
|
||||
return knnSearches;
|
||||
}
|
||||
|
||||
public org.springframework.data.elasticsearch.core.query.@Nullable Query getSpringDataQuery() {
|
||||
@Nullable
|
||||
public org.springframework.data.elasticsearch.core.query.Query getSpringDataQuery() {
|
||||
return springDataQuery;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import org.springframework.data.elasticsearch.core.query.BaseQueryBuilder;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import reactor.core.publisher.Mono;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
+2
-10
@@ -16,15 +16,7 @@
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import co.elastic.clients.ApiClient;
|
||||
import co.elastic.clients.elasticsearch.cluster.DeleteComponentTemplateRequest;
|
||||
import co.elastic.clients.elasticsearch.cluster.DeleteComponentTemplateResponse;
|
||||
import co.elastic.clients.elasticsearch.cluster.ExistsComponentTemplateRequest;
|
||||
import co.elastic.clients.elasticsearch.cluster.GetComponentTemplateRequest;
|
||||
import co.elastic.clients.elasticsearch.cluster.GetComponentTemplateResponse;
|
||||
import co.elastic.clients.elasticsearch.cluster.HealthRequest;
|
||||
import co.elastic.clients.elasticsearch.cluster.HealthResponse;
|
||||
import co.elastic.clients.elasticsearch.cluster.PutComponentTemplateRequest;
|
||||
import co.elastic.clients.elasticsearch.cluster.PutComponentTemplateResponse;
|
||||
import co.elastic.clients.elasticsearch.cluster.*;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.TransportOptions;
|
||||
import co.elastic.clients.transport.endpoints.BooleanResponse;
|
||||
@@ -33,7 +25,7 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Reactive version of the {@link co.elastic.clients.elasticsearch.cluster.ElasticsearchClusterClient}
|
||||
|
||||
+11
-22
@@ -16,19 +16,15 @@
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.json.jackson.Jackson3JsonpMapper;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.TransportOptions;
|
||||
import co.elastic.clients.transport.rest5_client.Rest5ClientOptions;
|
||||
import co.elastic.clients.transport.rest5_client.low_level.RequestOptions;
|
||||
import co.elastic.clients.transport.rest5_client.low_level.Rest5Client;
|
||||
import tools.jackson.databind.cfg.JsonNodeFeature;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
import co.elastic.clients.transport.rest_client.RestClientOptions;
|
||||
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.client.elc.rest5_client.Rest5Clients;
|
||||
import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport;
|
||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
@@ -59,11 +55,11 @@ public abstract class ReactiveElasticsearchConfiguration extends ElasticsearchCo
|
||||
* @return RestClient
|
||||
*/
|
||||
@Bean
|
||||
public Rest5Client elasticsearchRestClient(ClientConfiguration clientConfiguration) {
|
||||
public RestClient elasticsearchRestClient(ClientConfiguration clientConfiguration) {
|
||||
|
||||
Assert.notNull(clientConfiguration, "clientConfiguration must not be null");
|
||||
|
||||
return Rest5Clients.getRest5Client(clientConfiguration);
|
||||
return ElasticsearchClients.getRestClient(clientConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,12 +70,12 @@ public abstract class ReactiveElasticsearchConfiguration extends ElasticsearchCo
|
||||
* @since 5.2
|
||||
*/
|
||||
@Bean
|
||||
public ElasticsearchTransport elasticsearchTransport(Rest5Client rest5Client, JsonpMapper jsonpMapper) {
|
||||
public ElasticsearchTransport elasticsearchTransport(RestClient restClient, JsonpMapper jsonpMapper) {
|
||||
|
||||
Assert.notNull(rest5Client, "restClient must not be null");
|
||||
Assert.notNull(restClient, "restClient must not be null");
|
||||
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
|
||||
|
||||
return ElasticsearchClients.getElasticsearchTransport(rest5Client, ElasticsearchClients.REACTIVE_CLIENT,
|
||||
return ElasticsearchClients.getElasticsearchTransport(restClient, ElasticsearchClients.REACTIVE_CLIENT,
|
||||
transportOptions(), jsonpMapper);
|
||||
}
|
||||
|
||||
@@ -114,7 +110,7 @@ public abstract class ReactiveElasticsearchConfiguration extends ElasticsearchCo
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the JsonpMapper that is used in the {@link #elasticsearchTransport(Rest5Client, JsonpMapper)} method and
|
||||
* Provides the JsonpMapper that is used in the {@link #elasticsearchTransport(RestClient, JsonpMapper)} method and
|
||||
* exposes it as a bean.
|
||||
*
|
||||
* @return the {@link JsonpMapper} to use
|
||||
@@ -122,20 +118,13 @@ public abstract class ReactiveElasticsearchConfiguration extends ElasticsearchCo
|
||||
*/
|
||||
@Bean
|
||||
public JsonpMapper jsonpMapper() {
|
||||
// we need to create our own objectMapper that keeps null values in order to provide the storeNullValue
|
||||
// functionality. The one Elasticsearch would provide removes the nulls. We remove unwanted nulls before they get
|
||||
// into this mapper, so we can safely keep them here.
|
||||
JsonMapper jsonMapper = JsonMapper.builder()
|
||||
.enable(JsonNodeFeature.WRITE_NULL_PROPERTIES)
|
||||
.enable(JsonNodeFeature.READ_NULL_PROPERTIES)
|
||||
.build();
|
||||
return new Jackson3JsonpMapper(jsonMapper);
|
||||
return new JacksonJsonpMapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the options that should be added to every request. Must not be {@literal null}
|
||||
*/
|
||||
public TransportOptions transportOptions() {
|
||||
return new Rest5ClientOptions(RequestOptions.DEFAULT, false);
|
||||
return new RestClientOptions(RequestOptions.DEFAULT, false).toBuilder().build();
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -25,7 +25,7 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Reactive version of the {@link co.elastic.clients.elasticsearch.indices.ElasticsearchIndicesClient}
|
||||
@@ -539,6 +539,14 @@ public class ReactiveElasticsearchIndicesClient
|
||||
return stats(builder -> builder);
|
||||
}
|
||||
|
||||
public Mono<UnfreezeResponse> unfreeze(UnfreezeRequest request) {
|
||||
return Mono.fromFuture(transport.performRequestAsync(request, UnfreezeRequest._ENDPOINT, transportOptions));
|
||||
}
|
||||
|
||||
public Mono<UnfreezeResponse> unfreeze(Function<UnfreezeRequest.Builder, ObjectBuilder<UnfreezeRequest>> fn) {
|
||||
return unfreeze(fn.apply(new UnfreezeRequest.Builder()).build());
|
||||
}
|
||||
|
||||
public Mono<UpdateAliasesResponse> updateAliases(UpdateAliasesRequest request) {
|
||||
return Mono.fromFuture(transport.performRequestAsync(request, UpdateAliasesRequest._ENDPOINT, transportOptions));
|
||||
}
|
||||
|
||||
-144
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.TransportOptions;
|
||||
import co.elastic.clients.transport.rest_client.RestClientOptions;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.client.elc.rest_client.RestClients;
|
||||
import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport;
|
||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for a @{@link org.springframework.context.annotation.Configuration} class to set up the Elasticsearch
|
||||
* connection using the {@link ReactiveElasticsearchClient}. This class exposes different parts of the setup as Spring
|
||||
* beans. Deriving * classes must provide the {@link ClientConfiguration} to use. <br/>
|
||||
* This class uses the Elasticsearch RestClient which was replaced b y the Rest5Client in Elasticsearch 9. It is still
|
||||
* available here but deprecated. *
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.4
|
||||
* @deprecated since 6.0 use {@link ReactiveElasticsearchConfiguration}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval=true)
|
||||
public abstract class ReactiveElasticsearchLegacyRestClientConfiguration extends ElasticsearchConfigurationSupport {
|
||||
|
||||
/**
|
||||
* Must be implemented by deriving classes to provide the {@link ClientConfiguration}.
|
||||
*
|
||||
* @return configuration, must not be {@literal null}
|
||||
*/
|
||||
@Bean(name = "elasticsearchClientConfiguration")
|
||||
public abstract ClientConfiguration clientConfiguration();
|
||||
|
||||
/**
|
||||
* Provides the underlying low level RestClient.
|
||||
*
|
||||
* @param clientConfiguration configuration for the client, must not be {@literal null}
|
||||
* @return RestClient
|
||||
*/
|
||||
@Bean
|
||||
public RestClient elasticsearchRestClient(ClientConfiguration clientConfiguration) {
|
||||
|
||||
Assert.notNull(clientConfiguration, "clientConfiguration must not be null");
|
||||
|
||||
return RestClients.getRestClient(clientConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the Elasticsearch transport to be used. The default implementation uses the {@link RestClient} bean and
|
||||
* the {@link JsonpMapper} bean provided in this class.
|
||||
*
|
||||
* @return the {@link ElasticsearchTransport}
|
||||
* @since 5.2
|
||||
*/
|
||||
@Bean
|
||||
public ElasticsearchTransport elasticsearchTransport(RestClient restClient, JsonpMapper jsonpMapper) {
|
||||
|
||||
Assert.notNull(restClient, "restClient must not be null");
|
||||
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
|
||||
|
||||
return ElasticsearchClients.getElasticsearchTransport(restClient, ElasticsearchClients.REACTIVE_CLIENT,
|
||||
transportOptions(), jsonpMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the {@link ReactiveElasticsearchClient} instance used.
|
||||
*
|
||||
* @param transport the ElasticsearchTransport to use
|
||||
* @return ReactiveElasticsearchClient instance.
|
||||
*/
|
||||
@Bean
|
||||
public ReactiveElasticsearchClient reactiveElasticsearchClient(ElasticsearchTransport transport) {
|
||||
|
||||
Assert.notNull(transport, "transport must not be null");
|
||||
|
||||
return ElasticsearchClients.createReactive(transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link ReactiveElasticsearchOperations}.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
@Bean(name = { "reactiveElasticsearchOperations", "reactiveElasticsearchTemplate" })
|
||||
public ReactiveElasticsearchOperations reactiveElasticsearchOperations(ElasticsearchConverter elasticsearchConverter,
|
||||
ReactiveElasticsearchClient reactiveElasticsearchClient) {
|
||||
|
||||
ReactiveElasticsearchTemplate template = new ReactiveElasticsearchTemplate(reactiveElasticsearchClient,
|
||||
elasticsearchConverter);
|
||||
template.setRefreshPolicy(refreshPolicy());
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the JsonpMapper that is used in the {@link #elasticsearchTransport(RestClient, JsonpMapper)} method and
|
||||
* exposes it as a bean.
|
||||
*
|
||||
* @return the {@link JsonpMapper} to use
|
||||
* @since 5.2
|
||||
*/
|
||||
@Bean
|
||||
public JsonpMapper jsonpMapper() {
|
||||
// we need to create our own objectMapper that keeps null values in order to provide the storeNullValue
|
||||
// functionality. The one Elasticsearch would provide removes the nulls. We remove unwanted nulls before they get
|
||||
// into this mapper, so we can safely keep them here.
|
||||
var objectMapper = (new ObjectMapper())
|
||||
.configure(SerializationFeature.INDENT_OUTPUT, false)
|
||||
.setSerializationInclusion(JsonInclude.Include.ALWAYS);
|
||||
return new JacksonJsonpMapper(objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the options that should be added to every request. Must not be {@literal null}
|
||||
*/
|
||||
public TransportOptions transportOptions() {
|
||||
return new RestClientOptions(RequestOptions.DEFAULT, false).toBuilder().build();
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -27,8 +27,7 @@ import reactor.core.publisher.Mono;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Reactive version of {@link co.elastic.clients.elasticsearch.sql.ElasticsearchSqlClient}.
|
||||
|
||||
+36
-159
@@ -25,8 +25,6 @@ import co.elastic.clients.elasticsearch.core.search.ResponseBody;
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.transport.Version;
|
||||
import co.elastic.clients.transport.endpoints.BooleanResponse;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
@@ -42,10 +40,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.elasticsearch.BulkFailureException;
|
||||
import org.springframework.data.elasticsearch.NoSuchIndexException;
|
||||
@@ -56,7 +51,6 @@ import org.springframework.data.elasticsearch.core.AggregationContainer;
|
||||
import org.springframework.data.elasticsearch.core.IndexedObjectInformation;
|
||||
import org.springframework.data.elasticsearch.core.MultiGetItem;
|
||||
import org.springframework.data.elasticsearch.core.ReactiveIndexOperations;
|
||||
import org.springframework.data.elasticsearch.core.SearchHit;
|
||||
import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
@@ -69,6 +63,7 @@ import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
|
||||
import org.springframework.data.elasticsearch.core.reindex.ReindexResponse;
|
||||
import org.springframework.data.elasticsearch.core.script.Script;
|
||||
import org.springframework.data.elasticsearch.core.sql.SqlResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -80,15 +75,12 @@ import org.springframework.util.StringUtils;
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Illia Ulianov
|
||||
* @author Junghoon Ban
|
||||
* @author maryantocinn
|
||||
* @since 4.4
|
||||
*/
|
||||
public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearchTemplate {
|
||||
|
||||
private static final Log LOGGER = LogFactory.getLog(ReactiveElasticsearchTemplate.class);
|
||||
|
||||
@Nullable private ElasticsearchObservationConvention observationConvention;
|
||||
|
||||
private final ReactiveElasticsearchClient client;
|
||||
private final ReactiveElasticsearchSqlClient sqlClient;
|
||||
private final RequestConverter requestConverter;
|
||||
@@ -109,105 +101,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
exceptionTranslator = new ElasticsearchExceptionTranslator(jsonpMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
|
||||
super.setApplicationContext(applicationContext);
|
||||
|
||||
if (observationRegistry == ObservationRegistry.NOOP) {
|
||||
applicationContext.getBeanProvider(ObservationRegistry.class).ifAvailable(this::setObservationRegistry);
|
||||
}
|
||||
|
||||
if (observationConvention == null) {
|
||||
applicationContext.getBeanProvider(ElasticsearchObservationConvention.class)
|
||||
.ifAvailable(this::setObservationConvention);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a custom {@link ElasticsearchObservationConvention} to override the default convention.
|
||||
*
|
||||
* @param observationConvention can be {@literal null}.
|
||||
* @since 6.1
|
||||
*/
|
||||
public void setObservationConvention(@Nullable ElasticsearchObservationConvention observationConvention) {
|
||||
this.observationConvention = observationConvention;
|
||||
}
|
||||
|
||||
private <T> Mono<T> observeMono(ElasticsearchOperationName operationName, @Nullable IndexCoordinates index,
|
||||
Mono<T> mono) {
|
||||
return Mono.defer(() -> {
|
||||
Observation observation = createObservation(operationName, index, null);
|
||||
return mono.doOnError(observation::error) //
|
||||
.doFinally(signalType -> observation.stop())
|
||||
.contextWrite(context -> context.put(Observation.class, observation))
|
||||
.doOnSubscribe(subscription -> observation.start());
|
||||
});
|
||||
}
|
||||
|
||||
private <T> Flux<T> observeFlux(ElasticsearchOperationName operationName, @Nullable IndexCoordinates index,
|
||||
Flux<T> flux) {
|
||||
return Flux.defer(() -> {
|
||||
Observation observation = createObservation(operationName, index, null);
|
||||
return flux.doOnError(observation::error) //
|
||||
.doFinally(signalType -> observation.stop())
|
||||
.contextWrite(context -> context.put(Observation.class, observation))
|
||||
.doOnSubscribe(subscription -> observation.start());
|
||||
});
|
||||
}
|
||||
|
||||
private <T> Mono<T> observeMono(ElasticsearchOperationName operationName, @Nullable IndexCoordinates index,
|
||||
int batchSize, Mono<T> mono) {
|
||||
return Mono.defer(() -> {
|
||||
Observation observation = createObservation(operationName, index, batchSize);
|
||||
return mono.doOnError(observation::error) //
|
||||
.doFinally(signalType -> observation.stop())
|
||||
.contextWrite(context -> context.put(Observation.class, observation))
|
||||
.doOnSubscribe(subscription -> observation.start());
|
||||
});
|
||||
}
|
||||
|
||||
private Observation createObservation(ElasticsearchOperationName operationName, @Nullable IndexCoordinates index,
|
||||
@Nullable Integer batchSize) {
|
||||
|
||||
ElasticsearchObservationContext context = new ElasticsearchObservationContext(operationName, index);
|
||||
context.setBatchSize(batchSize);
|
||||
|
||||
return ElasticsearchObservation.ELASTICSEARCH_COMMAND_OBSERVATION.observation(observationConvention,
|
||||
DefaultElasticsearchObservationConvention.INSTANCE, () -> context, observationRegistry);
|
||||
}
|
||||
|
||||
// region Document operations
|
||||
@Override
|
||||
public <T> Mono<T> save(T entity, IndexCoordinates index) {
|
||||
return observeMono(ElasticsearchOperationName.SAVE, index, super.save(entity, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> exists(String id, IndexCoordinates index) {
|
||||
return observeMono(ElasticsearchOperationName.EXISTS, index, super.exists(id, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> delete(Object entity, IndexCoordinates index) {
|
||||
return observeMono(ElasticsearchOperationName.DELETE, index, super.delete(entity, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> delete(String id, IndexCoordinates index) {
|
||||
return observeMono(ElasticsearchOperationName.DELETE, index, super.delete(id, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<SearchHit<T>> search(Query query, Class<?> entityType, Class<T> resultType, IndexCoordinates index) {
|
||||
return observeFlux(ElasticsearchOperationName.SEARCH, index, super.search(query, entityType, resultType, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> count(Query query, Class<?> entityType, IndexCoordinates index) {
|
||||
return observeMono(ElasticsearchOperationName.COUNT, index, super.count(query, entityType, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> Mono<Tuple2<T, IndexResponseMetaData>> doIndex(T entity, IndexCoordinates index) {
|
||||
|
||||
@@ -229,7 +123,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
|
||||
Assert.notNull(entitiesPublisher, "entitiesPublisher must not be null!");
|
||||
|
||||
return observeFlux(ElasticsearchOperationName.BULK, index, entitiesPublisher //
|
||||
return entitiesPublisher //
|
||||
.flatMapMany(entities -> Flux.fromIterable(entities) //
|
||||
.concatMap(entity -> maybeCallbackBeforeConvert(entity, index)) //
|
||||
).collectList() //
|
||||
@@ -251,12 +145,12 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
response.index(), //
|
||||
response.seqNo(), //
|
||||
response.primaryTerm(), //
|
||||
response.version()), //
|
||||
converter, //
|
||||
response.version()),
|
||||
converter,
|
||||
routingResolver);
|
||||
return maybeCallbackAfterSave(updatedEntity, index);
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -277,11 +171,9 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
public Mono<ByQueryResponse> delete(DeleteQuery query, Class<?> entityType, IndexCoordinates index) {
|
||||
Assert.notNull(query, "query must not be null");
|
||||
|
||||
return observeMono(ElasticsearchOperationName.DELETE_BY_QUERY, index, Mono.defer(() -> {
|
||||
DeleteByQueryRequest request = requestConverter.documentDeleteByQueryRequest(query, routingResolver.getRouting(),
|
||||
entityType, index, getRefreshPolicy());
|
||||
return Mono.from(execute(client -> client.deleteByQuery(request))).map(responseConverter::byQueryResponse);
|
||||
}));
|
||||
DeleteByQueryRequest request = requestConverter.documentDeleteByQueryRequest(query, routingResolver.getRouting(),
|
||||
entityType, index, getRefreshPolicy());
|
||||
return Mono.from(execute(client -> client.deleteByQuery(request))).map(responseConverter::byQueryResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -291,15 +183,13 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
Assert.notNull(entityType, "entityType must not be null");
|
||||
Assert.notNull(index, "index must not be null");
|
||||
|
||||
return observeMono(ElasticsearchOperationName.GET, index, Mono.defer(() -> {
|
||||
GetRequest getRequest = requestConverter.documentGetRequest(id, routingResolver.getRouting(), index);
|
||||
GetRequest getRequest = requestConverter.documentGetRequest(id, routingResolver.getRouting(), index);
|
||||
|
||||
Mono<GetResponse<EntityAsMap>> getResponse = Mono //
|
||||
.from(execute(client -> client.get(getRequest, EntityAsMap.class)));
|
||||
Mono<GetResponse<EntityAsMap>> getResponse = Mono
|
||||
.from(execute(client -> client.get(getRequest, EntityAsMap.class)));
|
||||
|
||||
ReadDocumentCallback<T> callback = new ReadDocumentCallback<>(converter, entityType, index);
|
||||
return getResponse.flatMap(response -> callback.toEntity(DocumentAdapters.from(response)));
|
||||
}));
|
||||
ReadDocumentCallback<T> callback = new ReadDocumentCallback<>(converter, entityType, index);
|
||||
return getResponse.flatMap(response -> callback.toEntity(DocumentAdapters.from(response)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -336,15 +226,13 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
Assert.notNull(updateQuery, "UpdateQuery must not be null");
|
||||
Assert.notNull(index, "Index must not be null");
|
||||
|
||||
return observeMono(ElasticsearchOperationName.UPDATE, index, Mono.defer(() -> {
|
||||
UpdateRequest<Document, ?> request = requestConverter.documentUpdateRequest(updateQuery, index,
|
||||
getRefreshPolicy(), routingResolver.getRouting());
|
||||
UpdateRequest<Document, ?> request = requestConverter.documentUpdateRequest(updateQuery, index, getRefreshPolicy(),
|
||||
routingResolver.getRouting());
|
||||
|
||||
return Mono.from(execute(client -> client.update(request, Document.class))).flatMap(response -> {
|
||||
UpdateResponse.Result result = result(response.result());
|
||||
return result == null ? Mono.empty() : Mono.just(UpdateResponse.of(result));
|
||||
});
|
||||
}));
|
||||
return Mono.from(execute(client -> client.update(request, Document.class))).flatMap(response -> {
|
||||
UpdateResponse.Result result = result(response.result());
|
||||
return result == null ? Mono.empty() : Mono.just(UpdateResponse.of(result));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -359,8 +247,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
Assert.notNull(bulkOptions, "BulkOptions must not be null");
|
||||
Assert.notNull(index, "Index must not be null");
|
||||
|
||||
return observeMono(ElasticsearchOperationName.BULK, index, queries.size(),
|
||||
doBulkOperation(queries, bulkOptions, index).then());
|
||||
return doBulkOperation(queries, bulkOptions, index).then();
|
||||
}
|
||||
|
||||
private Flux<BulkResponseItem> doBulkOperation(List<?> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
||||
@@ -380,7 +267,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
|
||||
for (BulkResponseItem item : bulkResponse.items()) {
|
||||
|
||||
if (item.error() != null && item.id() != null) {
|
||||
if (item.error() != null) {
|
||||
failedDocuments.put(item.id(), new BulkFailureException.FailureDetails(item.status(), item.error().reason()));
|
||||
}
|
||||
}
|
||||
@@ -423,24 +310,22 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
Assert.notNull(query, "query must not be null");
|
||||
Assert.notNull(clazz, "clazz must not be null");
|
||||
|
||||
return observeFlux(ElasticsearchOperationName.MULTI_GET, index, Flux.defer(() -> {
|
||||
MgetRequest request = requestConverter.documentMgetRequest(query, clazz, index);
|
||||
MgetRequest request = requestConverter.documentMgetRequest(query, clazz, index);
|
||||
|
||||
ReadDocumentCallback<T> callback = new ReadDocumentCallback<>(converter, clazz, index);
|
||||
ReadDocumentCallback<T> callback = new ReadDocumentCallback<>(converter, clazz, index);
|
||||
|
||||
Publisher<MgetResponse<EntityAsMap>> response = execute(client -> client.mget(request, EntityAsMap.class));
|
||||
Publisher<MgetResponse<EntityAsMap>> response = execute(client -> client.mget(request, EntityAsMap.class));
|
||||
|
||||
return Mono.from(response)//
|
||||
.flatMapMany(it -> Flux.fromIterable(DocumentAdapters.from(it))) //
|
||||
.flatMap(multiGetItem -> {
|
||||
if (multiGetItem.isFailed()) {
|
||||
return Mono.just(MultiGetItem.of(null, multiGetItem.getFailure()));
|
||||
} else {
|
||||
return callback.toEntity(multiGetItem.getItem()) //
|
||||
.map(t -> MultiGetItem.of(t, multiGetItem.getFailure()));
|
||||
}
|
||||
});
|
||||
}));
|
||||
return Mono.from(response)//
|
||||
.flatMapMany(it -> Flux.fromIterable(DocumentAdapters.from(it))) //
|
||||
.flatMap(multiGetItem -> {
|
||||
if (multiGetItem.isFailed()) {
|
||||
return Mono.just(MultiGetItem.of(null, multiGetItem.getFailure()));
|
||||
} else {
|
||||
return callback.toEntity(multiGetItem.getItem()) //
|
||||
.map(t -> MultiGetItem.of(t, multiGetItem.getFailure()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// endregion
|
||||
@@ -450,14 +335,6 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
return new ReactiveElasticsearchTemplate(client, converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeCopy(AbstractReactiveElasticsearchTemplate copy) {
|
||||
|
||||
if (copy instanceof ReactiveElasticsearchTemplate reactiveTemplate) {
|
||||
reactiveTemplate.observationConvention = this.observationConvention;
|
||||
}
|
||||
}
|
||||
|
||||
// region search operations
|
||||
|
||||
@Override
|
||||
@@ -537,7 +414,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
List<Object> sortOptions = hits.get(hits.size() - 1).sort().stream().map(TypeUtils::toObjectNotNull)
|
||||
List<Object> sortOptions = hits.get(hits.size() - 1).sort().stream().map(TypeUtils::toObject)
|
||||
.collect(Collectors.toList());
|
||||
baseQuery.setSearchAfter(sortOptions);
|
||||
SearchRequest followSearchRequest = requestConverter.searchRequest(baseQuery,
|
||||
@@ -631,8 +508,8 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
||||
SearchRequest searchRequest = requestConverter.searchRequest(query, routingResolver.getRouting(), clazz, index,
|
||||
false);
|
||||
|
||||
// noinspection unchecked
|
||||
SearchDocumentCallback<T> callback = new ReadSearchDocumentCallback<>((Class<T>) clazz, index);
|
||||
|
||||
SearchDocumentResponse.EntityCreator<T> entityCreator = searchDocument -> callback.toEntity(searchDocument)
|
||||
.toFuture();
|
||||
|
||||
|
||||
+6
-8
@@ -21,7 +21,6 @@ import co.elastic.clients.elasticsearch._types.AcknowledgedResponseBase;
|
||||
import co.elastic.clients.elasticsearch.indices.*;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.endpoints.BooleanResponse;
|
||||
import org.springframework.data.elasticsearch.ResourceNotFoundException;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -30,7 +29,6 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.elasticsearch.NoSuchIndexException;
|
||||
@@ -53,6 +51,7 @@ import org.springframework.data.elasticsearch.core.mapping.Alias;
|
||||
import org.springframework.data.elasticsearch.core.mapping.CreateIndexSettings;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -108,7 +107,7 @@ public class ReactiveIndicesTemplate
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> create(Map<String, @Nullable Object> settings) {
|
||||
public Mono<Boolean> create(Map<String, Object> settings) {
|
||||
|
||||
Assert.notNull(settings, "settings must not be null");
|
||||
|
||||
@@ -116,7 +115,7 @@ public class ReactiveIndicesTemplate
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> create(Map<String, @Nullable Object> settings, Document mapping) {
|
||||
public Mono<Boolean> create(Map<String, Object> settings, Document mapping) {
|
||||
|
||||
Assert.notNull(settings, "settings must not be null");
|
||||
Assert.notNull(mapping, "mapping must not be null");
|
||||
@@ -132,7 +131,7 @@ public class ReactiveIndicesTemplate
|
||||
doCreate(getIndexCoordinates(), settings, mapping))); //
|
||||
}
|
||||
|
||||
private Mono<Boolean> doCreate(IndexCoordinates indexCoordinates, Map<String, @Nullable Object> settings,
|
||||
private Mono<Boolean> doCreate(IndexCoordinates indexCoordinates, Map<String, Object> settings,
|
||||
@Nullable Document mapping) {
|
||||
Set<Alias> aliases = (boundClass != null) ? getAliasesFor(boundClass) : new HashSet<>();
|
||||
CreateIndexSettings indexSettings = CreateIndexSettings.builder(indexCoordinates)
|
||||
@@ -270,7 +269,7 @@ public class ReactiveIndicesTemplate
|
||||
return getAliases(null, indexNames);
|
||||
}
|
||||
|
||||
private Mono<Map<String, Set<AliasData>>> getAliases(String@Nullable [] aliasNames, String@Nullable [] indexNames) {
|
||||
private Mono<Map<String, Set<AliasData>>> getAliases(@Nullable String[] aliasNames, @Nullable String[] indexNames) {
|
||||
|
||||
GetAliasRequest getAliasRequest = requestConverter.indicesGetAliasRequest(aliasNames, indexNames);
|
||||
Mono<GetAliasResponse> getAliasResponse = Mono.from(execute(client -> client.getAlias(getAliasRequest)));
|
||||
@@ -390,8 +389,7 @@ public class ReactiveIndicesTemplate
|
||||
co.elastic.clients.elasticsearch.indices.GetTemplateRequest getTemplateRequestES = requestConverter
|
||||
.indicesGetTemplateRequest(getTemplateRequest);
|
||||
Mono<GetTemplateResponse> getTemplateResponse = Mono
|
||||
.from(execute(client -> client.getTemplate(getTemplateRequestES)))
|
||||
.onErrorComplete(ResourceNotFoundException.class);
|
||||
.from(execute(client -> client.getTemplate(getTemplateRequestES)));
|
||||
|
||||
return getTemplateResponse.flatMap(response -> {
|
||||
if (response != null) {
|
||||
|
||||
+139
-147
@@ -42,10 +42,10 @@ import co.elastic.clients.elasticsearch.core.bulk.CreateOperation;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.IndexOperation;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.UpdateOperation;
|
||||
import co.elastic.clients.elasticsearch.core.mget.MultiGetOperation;
|
||||
import co.elastic.clients.elasticsearch.core.msearch.MultisearchBody;
|
||||
import co.elastic.clients.elasticsearch.core.msearch.MultisearchHeader;
|
||||
import co.elastic.clients.elasticsearch.core.search.Highlight;
|
||||
import co.elastic.clients.elasticsearch.core.search.Rescore;
|
||||
import co.elastic.clients.elasticsearch.core.search.SearchRequestBody;
|
||||
import co.elastic.clients.elasticsearch.core.search.SourceConfig;
|
||||
import co.elastic.clients.elasticsearch.indices.*;
|
||||
import co.elastic.clients.elasticsearch.indices.ExistsIndexTemplateRequest;
|
||||
@@ -74,11 +74,10 @@ import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.elasticsearch.core.RefreshPolicy;
|
||||
@@ -102,6 +101,7 @@ import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
|
||||
import org.springframework.data.elasticsearch.core.reindex.Remote;
|
||||
import org.springframework.data.elasticsearch.core.script.Script;
|
||||
import org.springframework.data.elasticsearch.support.DefaultStringObjectMap;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -114,7 +114,6 @@ import org.springframework.util.StringUtils;
|
||||
* @author cdalxndr
|
||||
* @author scoobyzhang
|
||||
* @author Haibo Liu
|
||||
* @author Steven Pearce
|
||||
* @since 4.4
|
||||
*/
|
||||
class RequestConverter extends AbstractQueryProcessor {
|
||||
@@ -175,9 +174,17 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
private co.elastic.clients.elasticsearch.indices.Alias.Builder buildAlias(AliasActionParameters parameters,
|
||||
co.elastic.clients.elasticsearch.indices.Alias.Builder aliasBuilder) {
|
||||
|
||||
getRouting(parameters.getRouting()).ifPresent(aliasBuilder::routing);
|
||||
getRouting(parameters.getIndexRouting()).ifPresent(aliasBuilder::indexRouting);
|
||||
getRouting(parameters.getSearchRouting()).ifPresent(aliasBuilder::searchRouting);
|
||||
if (parameters.getRouting() != null) {
|
||||
aliasBuilder.routing(parameters.getRouting());
|
||||
}
|
||||
|
||||
if (parameters.getIndexRouting() != null) {
|
||||
aliasBuilder.indexRouting(parameters.getIndexRouting());
|
||||
}
|
||||
|
||||
if (parameters.getSearchRouting() != null) {
|
||||
aliasBuilder.searchRouting(parameters.getSearchRouting());
|
||||
}
|
||||
|
||||
if (parameters.getHidden() != null) {
|
||||
aliasBuilder.isHidden(parameters.getHidden());
|
||||
@@ -233,16 +240,12 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
Map<String, co.elastic.clients.elasticsearch.indices.Alias> aliases = new HashMap<>();
|
||||
for (Alias alias : indexSettings.getAliases()) {
|
||||
co.elastic.clients.elasticsearch.indices.Alias esAlias = co.elastic.clients.elasticsearch.indices.Alias
|
||||
.of(ab -> {
|
||||
co.elastic.clients.elasticsearch.indices.Alias.Builder aliasBuilder = ab.filter(getQuery(alias.getFilter(), null))
|
||||
.isHidden(alias.getHidden())
|
||||
.isWriteIndex(alias.getWriteIndex());
|
||||
getRouting(alias.getRouting()).ifPresent(aliasBuilder::routing);
|
||||
getRouting(alias.getIndexRouting()).ifPresent(aliasBuilder::indexRouting);
|
||||
getRouting(alias.getSearchRouting()).ifPresent(aliasBuilder::searchRouting);
|
||||
|
||||
return aliasBuilder;
|
||||
});
|
||||
.of(ab -> ab.filter(getQuery(alias.getFilter(), null))
|
||||
.routing(alias.getRouting())
|
||||
.indexRouting(alias.getIndexRouting())
|
||||
.searchRouting(alias.getSearchRouting())
|
||||
.isHidden(alias.getHidden())
|
||||
.isWriteIndex(alias.getWriteIndex()));
|
||||
aliases.put(alias.getAlias(), esAlias);
|
||||
}
|
||||
|
||||
@@ -307,6 +310,7 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
return updateAliasRequestBuilder.build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Action.Builder getBuilder(AliasAction aliasAction) {
|
||||
Action.Builder actionBuilder = new Action.Builder();
|
||||
|
||||
@@ -316,11 +320,10 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
addActionBuilder //
|
||||
.indices(Arrays.asList(parameters.getIndices())) //
|
||||
.isHidden(parameters.getHidden()) //
|
||||
.isWriteIndex(parameters.getWriteIndex()); //
|
||||
|
||||
getRouting(parameters.getRouting()).ifPresent(addActionBuilder::routing);
|
||||
getRouting(parameters.getIndexRouting()).ifPresent(addActionBuilder::indexRouting);
|
||||
getRouting(parameters.getSearchRouting()).ifPresent(addActionBuilder::searchRouting);
|
||||
.isWriteIndex(parameters.getWriteIndex()) //
|
||||
.routing(parameters.getRouting()) //
|
||||
.indexRouting(parameters.getIndexRouting()) //
|
||||
.searchRouting(parameters.getSearchRouting()); //
|
||||
|
||||
if (parameters.getAliases() != null) {
|
||||
addActionBuilder.aliases(Arrays.asList(parameters.getAliases()));
|
||||
@@ -588,11 +591,10 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
builder.version(query.getVersion()).versionType(versionType);
|
||||
}
|
||||
|
||||
builder
|
||||
.ifSeqNo(query.getSeqNo())
|
||||
.ifPrimaryTerm(query.getPrimaryTerm());
|
||||
|
||||
getRouting(query.getRouting()).ifPresent(builder::routing);
|
||||
builder //
|
||||
.ifSeqNo(query.getSeqNo()) //
|
||||
.ifPrimaryTerm(query.getPrimaryTerm()) //
|
||||
.routing(query.getRouting()); //
|
||||
|
||||
if (query.getOpType() != null) {
|
||||
switch (query.getOpType()) {
|
||||
@@ -642,9 +644,8 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
|
||||
builder //
|
||||
.ifSeqNo(query.getSeqNo()) //
|
||||
.ifPrimaryTerm(query.getPrimaryTerm()); //
|
||||
|
||||
getRouting(query.getRouting()).ifPresent(builder::routing);
|
||||
.ifPrimaryTerm(query.getPrimaryTerm()) //
|
||||
.routing(query.getRouting()); //
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
@@ -685,9 +686,8 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
|
||||
builder //
|
||||
.ifSeqNo(query.getSeqNo()) //
|
||||
.ifPrimaryTerm(query.getPrimaryTerm()); //
|
||||
|
||||
getRouting(query.getRouting()).ifPresent(builder::routing);
|
||||
.ifPrimaryTerm(query.getPrimaryTerm()) //
|
||||
.routing(query.getRouting()); //
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
@@ -723,19 +723,20 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
return a;
|
||||
});
|
||||
|
||||
uob
|
||||
.ifSeqNo(query.getIfSeqNo())
|
||||
.ifPrimaryTerm(query.getIfPrimaryTerm())
|
||||
.retryOnConflict(query.getRetryOnConflict());
|
||||
|
||||
getRouting(query.getRouting()).ifPresent(uob::routing);
|
||||
uob //
|
||||
.routing(query.getRouting()) //
|
||||
.ifSeqNo(query.getIfSeqNo() != null ? Long.valueOf(query.getIfSeqNo()) : null) //
|
||||
.ifPrimaryTerm(query.getIfPrimaryTerm() != null ? Long.valueOf(query.getIfPrimaryTerm()) : null) //
|
||||
.retryOnConflict(query.getRetryOnConflict()) //
|
||||
;
|
||||
|
||||
// no refresh, timeout, waitForActiveShards on UpdateOperation or UpdateAction
|
||||
|
||||
return uob.build();
|
||||
}
|
||||
|
||||
private co.elastic.clients.elasticsearch._types.@Nullable Script getScript(@Nullable ScriptData scriptData) {
|
||||
@Nullable
|
||||
private co.elastic.clients.elasticsearch._types.Script getScript(@Nullable ScriptData scriptData) {
|
||||
|
||||
if (scriptData == null) {
|
||||
return null;
|
||||
@@ -748,10 +749,11 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
}
|
||||
return co.elastic.clients.elasticsearch._types.Script.of(sb -> {
|
||||
sb.lang(scriptData.language())
|
||||
.params(params)
|
||||
.id(scriptData.scriptName());
|
||||
if (scriptData.script() != null) {
|
||||
sb.source(s -> s.scriptString(scriptData.script()));
|
||||
.params(params);
|
||||
if (scriptData.type() == ScriptType.INLINE) {
|
||||
sb.source(scriptData.script());
|
||||
} else if (scriptData.type() == ScriptType.STORED) {
|
||||
sb.id(scriptData.script());
|
||||
}
|
||||
return sb;
|
||||
});
|
||||
@@ -779,7 +781,9 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
builder.pipeline(bulkOptions.getPipeline());
|
||||
}
|
||||
|
||||
getRouting(bulkOptions.getRoutingId()).ifPresent(builder::routing);
|
||||
if (bulkOptions.getRoutingId() != null) {
|
||||
builder.routing(bulkOptions.getRoutingId());
|
||||
}
|
||||
|
||||
List<BulkOperation> operations = queries.stream().map(query -> {
|
||||
BulkOperation.Builder ob = new BulkOperation.Builder();
|
||||
@@ -806,13 +810,10 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
Assert.notNull(id, "id must not be null");
|
||||
Assert.notNull(indexCoordinates, "indexCoordinates must not be null");
|
||||
|
||||
return GetRequest.of(grb -> {
|
||||
GetRequest.Builder builder = grb //
|
||||
.index(indexCoordinates.getIndexName()) //
|
||||
.id(id); //
|
||||
getRouting(routing).ifPresent(builder::routing);
|
||||
return builder;
|
||||
});
|
||||
return GetRequest.of(grb -> grb //
|
||||
.index(indexCoordinates.getIndexName()) //
|
||||
.id(id) //
|
||||
.routing(routing));
|
||||
}
|
||||
|
||||
public co.elastic.clients.elasticsearch.core.ExistsRequest documentExistsRequest(String id, @Nullable String routing,
|
||||
@@ -821,13 +822,10 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
Assert.notNull(id, "id must not be null");
|
||||
Assert.notNull(indexCoordinates, "indexCoordinates must not be null");
|
||||
|
||||
return co.elastic.clients.elasticsearch.core.ExistsRequest.of(erb -> {
|
||||
co.elastic.clients.elasticsearch.core.ExistsRequest.Builder builder = erb
|
||||
.index(indexCoordinates.getIndexName())
|
||||
.id(id);
|
||||
getRouting(routing).ifPresent(builder::routing);
|
||||
return builder;
|
||||
});
|
||||
return co.elastic.clients.elasticsearch.core.ExistsRequest.of(erb -> erb
|
||||
.index(indexCoordinates.getIndexName())
|
||||
.id(id)
|
||||
.routing(routing));
|
||||
}
|
||||
|
||||
public <T> MgetRequest documentMgetRequest(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||
@@ -845,14 +843,11 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
SourceConfig sourceConfig = getSourceConfig(query);
|
||||
|
||||
List<MultiGetOperation> multiGetOperations = query.getIdsWithRouting().stream()
|
||||
.map(idWithRouting -> MultiGetOperation.of(mgo -> {
|
||||
MultiGetOperation.Builder builder = mgo //
|
||||
.index(index.getIndexName()) //
|
||||
.id(idWithRouting.id()) //
|
||||
.source(sourceConfig);
|
||||
getRouting(idWithRouting.routing()).ifPresent(builder::routing);
|
||||
return builder;
|
||||
}))
|
||||
.map(idWithRouting -> MultiGetOperation.of(mgo -> mgo //
|
||||
.index(index.getIndexName()) //
|
||||
.id(idWithRouting.id()) //
|
||||
.routing(idWithRouting.routing()) //
|
||||
.source(sourceConfig)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return MgetRequest.of(mg -> mg//
|
||||
@@ -910,17 +905,8 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
}
|
||||
|
||||
SourceFilter sourceFilter = source.getSourceFilter();
|
||||
if (sourceFilter != null && (sourceFilter.getIncludes() != null || sourceFilter.getExcludes() != null)) {
|
||||
s.sourceFields(cfg -> cfg
|
||||
.filter(f -> {
|
||||
if (sourceFilter.getIncludes() != null) {
|
||||
f.includes(Arrays.asList(sourceFilter.getIncludes()));
|
||||
}
|
||||
if (sourceFilter.getExcludes() != null) {
|
||||
f.excludes(Arrays.asList(sourceFilter.getExcludes()));
|
||||
}
|
||||
return f;
|
||||
}));
|
||||
if (sourceFilter != null && sourceFilter.getIncludes() != null) {
|
||||
s.sourceFields(Arrays.asList(sourceFilter.getIncludes()));
|
||||
}
|
||||
return s;
|
||||
}) //
|
||||
@@ -939,13 +925,9 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
|
||||
ReindexRequest.Script script = reindexRequest.getScript();
|
||||
if (script != null) {
|
||||
builder.script(sb -> {
|
||||
if (script.getSource() != null) {
|
||||
sb.source(s -> s.scriptString(script.getSource()));
|
||||
}
|
||||
sb.lang(script.getLang());
|
||||
return sb;
|
||||
});
|
||||
builder.script(sb -> sb
|
||||
.lang(script.getLang())
|
||||
.source(script.getSource()));
|
||||
}
|
||||
|
||||
builder.timeout(time(reindexRequest.getTimeout())) //
|
||||
@@ -974,7 +956,10 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
|
||||
return DeleteRequest.of(r -> {
|
||||
r.id(id).index(index.getIndexName());
|
||||
getRouting(routing).ifPresent(r::routing);
|
||||
|
||||
if (routing != null) {
|
||||
r.routing(routing);
|
||||
}
|
||||
r.refresh(refresh(refreshPolicy));
|
||||
return r;
|
||||
});
|
||||
@@ -998,7 +983,11 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
|
||||
b.scroll(time(query.getScrollTime()));
|
||||
|
||||
getRouting(query.getRoute(), routing).ifPresent(b::routing);
|
||||
if (query.getRoute() != null) {
|
||||
b.routing(query.getRoute());
|
||||
} else if (StringUtils.hasText(routing)) {
|
||||
b.routing(routing);
|
||||
}
|
||||
|
||||
return b;
|
||||
});
|
||||
@@ -1018,7 +1007,11 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
.scroll(time(query.getScroll()))
|
||||
.scrollSize(query.getScrollSize());
|
||||
|
||||
getRouting(query.getRouting(), routing).ifPresent(dqb::routing);
|
||||
if (query.getRouting() != null) {
|
||||
dqb.routing(query.getRouting());
|
||||
} else if (StringUtils.hasText(routing)) {
|
||||
dqb.routing(routing);
|
||||
}
|
||||
|
||||
if (query.getQ() != null) {
|
||||
dqb.q(query.getQ())
|
||||
@@ -1071,10 +1064,7 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
return UpdateRequest.of(uqb -> {
|
||||
uqb.index(indexName).id(query.getId());
|
||||
|
||||
var scriptData = query.getScriptData();
|
||||
var script = scriptData != null ? scriptData.script() : null;
|
||||
|
||||
if (script != null) {
|
||||
if (query.getScript() != null) {
|
||||
Map<String, JsonData> params = new HashMap<>();
|
||||
|
||||
if (query.getParams() != null) {
|
||||
@@ -1082,30 +1072,28 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
}
|
||||
|
||||
uqb.script(sb -> {
|
||||
sb
|
||||
.lang(scriptData.language())
|
||||
.params(params);
|
||||
sb.lang(query.getLang()).params(params);
|
||||
|
||||
if (script != null) {
|
||||
sb.source(s -> s.scriptString(script));
|
||||
if (query.getScriptType() == ScriptType.INLINE) {
|
||||
sb.source(query.getScript()); //
|
||||
} else if (query.getScriptType() == ScriptType.STORED) {
|
||||
sb.id(query.getScript());
|
||||
}
|
||||
sb.id(scriptData.scriptName());
|
||||
|
||||
return sb;
|
||||
});
|
||||
}
|
||||
|
||||
uqb
|
||||
.doc(query.getDocument())
|
||||
.upsert(query.getUpsert())
|
||||
.scriptedUpsert(query.getScriptedUpsert())
|
||||
.docAsUpsert(query.getDocAsUpsert())
|
||||
.ifSeqNo(query.getIfSeqNo())
|
||||
.ifPrimaryTerm(query.getIfPrimaryTerm())
|
||||
.refresh(query.getRefreshPolicy() != null ? refresh(query.getRefreshPolicy()) : refresh(refreshPolicy))
|
||||
.retryOnConflict(query.getRetryOnConflict());
|
||||
|
||||
getRouting(query.getRouting(), routing).ifPresent(uqb::routing);
|
||||
uqb //
|
||||
.doc(query.getDocument()) //
|
||||
.upsert(query.getUpsert()) //
|
||||
.routing(query.getRouting() != null ? query.getRouting() : routing) //
|
||||
.scriptedUpsert(query.getScriptedUpsert()) //
|
||||
.docAsUpsert(query.getDocAsUpsert()) //
|
||||
.ifSeqNo(query.getIfSeqNo() != null ? Long.valueOf(query.getIfSeqNo()) : null) //
|
||||
.ifPrimaryTerm(query.getIfPrimaryTerm() != null ? Long.valueOf(query.getIfPrimaryTerm()) : null) //
|
||||
.refresh(query.getRefreshPolicy() != null ? refresh(query.getRefreshPolicy()) : refresh(refreshPolicy)) //
|
||||
.retryOnConflict(query.getRetryOnConflict()) //
|
||||
;
|
||||
|
||||
if (query.getFetchSource() != null) {
|
||||
uqb.source(sc -> sc.fetch(query.getFetchSource()));
|
||||
@@ -1139,7 +1127,8 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
}
|
||||
|
||||
return uqb;
|
||||
});
|
||||
} //
|
||||
);
|
||||
}
|
||||
|
||||
public UpdateByQueryRequest documentUpdateByQueryRequest(UpdateQuery updateQuery, IndexCoordinates index,
|
||||
@@ -1149,14 +1138,13 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
ub //
|
||||
.index(Arrays.asList(index.getIndexNames())) //
|
||||
.refresh(refreshPolicy == RefreshPolicy.IMMEDIATE) //
|
||||
.routing(updateQuery.getRouting()) //
|
||||
.script(getScript(updateQuery.getScriptData())) //
|
||||
.maxDocs(updateQuery.getMaxDocs() != null ? Long.valueOf(updateQuery.getMaxDocs()) : null) //
|
||||
.pipeline(updateQuery.getPipeline()) //
|
||||
.requestsPerSecond(updateQuery.getRequestsPerSecond()) //
|
||||
.slices(slices(updateQuery.getSlices() != null ? Long.valueOf(updateQuery.getSlices()) : null));
|
||||
|
||||
getRouting(updateQuery.getRouting()).ifPresent(ub::routing);
|
||||
|
||||
if (updateQuery.getAbortOnVersionConflict() != null) {
|
||||
ub.conflicts(updateQuery.getAbortOnVersionConflict() ? Conflicts.Abort : Conflicts.Proceed);
|
||||
}
|
||||
@@ -1230,7 +1218,12 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
|
||||
builder.query(getQuery(query, clazz));
|
||||
|
||||
getRouting(query.getRoute(), routing).ifPresent(builder::routing);
|
||||
if (StringUtils.hasText(query.getRoute())) {
|
||||
builder.routing(query.getRoute());
|
||||
}
|
||||
if (StringUtils.hasText(routing)) {
|
||||
builder.routing(routing);
|
||||
}
|
||||
|
||||
addPostFilter(query, builder);
|
||||
|
||||
@@ -1248,11 +1241,11 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
mtrb.searchTemplates(stb -> stb
|
||||
.header(msearchHeaderBuilder(query, param.index(), routing))
|
||||
.body(bb -> {
|
||||
bb.explain(query.getExplain()) //
|
||||
.id(query.getId()); //
|
||||
if (query.getSource() != null) {
|
||||
bb.source(s -> s.scriptString(query.getSource()));
|
||||
}
|
||||
bb //
|
||||
.explain(query.getExplain()) //
|
||||
.id(query.getId()) //
|
||||
.source(query.getSource()) //
|
||||
;
|
||||
|
||||
if (!CollectionUtils.isEmpty(query.getParams())) {
|
||||
Map<String, JsonData> params = getTemplateParams(query.getParams().entrySet());
|
||||
@@ -1336,9 +1329,7 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
|
||||
if (script != null) {
|
||||
rfb.script(s -> {
|
||||
if (script != null) {
|
||||
s.source(so -> so.scriptString(script));
|
||||
}
|
||||
s.source(script);
|
||||
|
||||
if (runtimeField.getParams() != null) {
|
||||
s.params(TypeUtils.paramsMap(runtimeField.getParams()));
|
||||
@@ -1397,7 +1388,11 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
.requestCache(query.getRequestCache()) //
|
||||
;
|
||||
|
||||
getRouting(query.getRoute(), routing).ifPresent(h::routing);
|
||||
if (StringUtils.hasText(query.getRoute())) {
|
||||
h.routing(query.getRoute());
|
||||
} else if (StringUtils.hasText(routing)) {
|
||||
h.routing(routing);
|
||||
}
|
||||
|
||||
if (query.getPreference() != null) {
|
||||
h.preference(query.getPreference());
|
||||
@@ -1427,7 +1422,6 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
.searchType(searchType) //
|
||||
.timeout(timeStringMs(query.getTimeout())) //
|
||||
.requestCache(query.getRequestCache()) //
|
||||
.includeNamedQueriesScore(query.getIncludeNamedQueriesScore()) //
|
||||
;
|
||||
|
||||
var pointInTime = query.getPointInTime();
|
||||
@@ -1443,7 +1437,11 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
builder.expandWildcards(expandWildcards(expandWildcards));
|
||||
}
|
||||
|
||||
getRouting(query.getRoute(), routing).ifPresent(builder::routing);
|
||||
if (query.getRoute() != null) {
|
||||
builder.routing(query.getRoute());
|
||||
} else if (StringUtils.hasText(routing)) {
|
||||
builder.routing(routing);
|
||||
}
|
||||
|
||||
if (query.getPreference() != null) {
|
||||
builder.preference(query.getPreference());
|
||||
@@ -1527,9 +1525,7 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
String script = runtimeField.getScript();
|
||||
if (script != null) {
|
||||
rfb.script(s -> {
|
||||
if (script != null) {
|
||||
s.source(so -> so.scriptString(script));
|
||||
}
|
||||
s.source(script);
|
||||
|
||||
if (runtimeField.getParams() != null) {
|
||||
s.params(TypeUtils.paramsMap(runtimeField.getParams()));
|
||||
@@ -1626,7 +1622,7 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
builder.highlight(highlight);
|
||||
}
|
||||
|
||||
private void addHighlight(Query query, SearchRequestBody.Builder builder) {
|
||||
private void addHighlight(Query query, MultisearchBody.Builder builder) {
|
||||
|
||||
Highlight highlight = query.getHighlightQuery()
|
||||
.map(highlightQuery -> new HighlightQueryBuilder(elasticsearchConverter.getMappingContext(), this)
|
||||
@@ -1706,7 +1702,7 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private NestedSortValue getNestedSort(Order.@Nullable Nested nested,
|
||||
private NestedSortValue getNestedSort(@Nullable Order.Nested nested,
|
||||
@Nullable ElasticsearchPersistentEntity<?> persistentEntity) {
|
||||
return (nested == null || persistentEntity == null) ? null
|
||||
: NestedSortValue.of(b -> b //
|
||||
@@ -1750,7 +1746,7 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
private void prepareNativeSearch(NativeQuery query, SearchRequestBody.Builder builder) {
|
||||
private void prepareNativeSearch(NativeQuery query, MultisearchBody.Builder builder) {
|
||||
|
||||
builder //
|
||||
.suggest(query.getSuggester()) //
|
||||
@@ -1770,7 +1766,8 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
co.elastic.clients.elasticsearch._types.query_dsl.@Nullable Query getQuery(@Nullable Query query,
|
||||
@Nullable
|
||||
co.elastic.clients.elasticsearch._types.query_dsl.Query getQuery(@Nullable Query query,
|
||||
@Nullable Class<?> clazz) {
|
||||
return getEsQuery(query, (q) -> elasticsearchConverter.updateQuery(q, clazz));
|
||||
}
|
||||
@@ -1869,12 +1866,15 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
.id(query.getId()) //
|
||||
.index(Arrays.asList(index.getIndexNames())) //
|
||||
.preference(query.getPreference()) //
|
||||
.searchType(searchType(query.getSearchType())); //
|
||||
.searchType(searchType(query.getSearchType())) //
|
||||
.source(query.getSource()) //
|
||||
;
|
||||
|
||||
if (query.getSource() != null) {
|
||||
builder.source(so -> so.scriptString(query.getSource()));
|
||||
if (query.getRoute() != null) {
|
||||
builder.routing(query.getRoute());
|
||||
} else if (StringUtils.hasText(routing)) {
|
||||
builder.routing(routing);
|
||||
}
|
||||
getRouting(query.getRoute(), routing).ifPresent(builder::routing);
|
||||
|
||||
var expandWildcards = query.getExpandWildcards();
|
||||
if (expandWildcards != null && !expandWildcards.isEmpty()) {
|
||||
@@ -1894,6 +1894,7 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<String, JsonData> getTemplateParams(Set<Map.Entry<String, Object>> query) {
|
||||
Function<Map.Entry<String, Object>, String> keyMapper = Map.Entry::getKey;
|
||||
Function<Map.Entry<String, Object>, JsonData> valueMapper = entry -> JsonData.of(entry.getValue(), jsonpMapper);
|
||||
@@ -1911,7 +1912,7 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
.id(script.id()) //
|
||||
.script(sb -> sb //
|
||||
.lang(script.language()) //
|
||||
.source(s -> s.scriptString(script.source()))));
|
||||
.source(script.source())));
|
||||
}
|
||||
|
||||
public GetScriptRequest scriptGet(String name) {
|
||||
@@ -1974,16 +1975,6 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
return null;
|
||||
}
|
||||
|
||||
Optional<String> getRouting(@Nullable String routing) {
|
||||
if (StringUtils.hasText(routing)) {
|
||||
return Optional.of(routing);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
Optional<String> getRouting(@Nullable String routing1, @Nullable String routing2) {
|
||||
return getRouting(routing1).or(() -> getRouting(routing2));
|
||||
}
|
||||
|
||||
private VersionType retrieveVersionTypeFromPersistentEntity(@Nullable Class<?> clazz) {
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = getPersistentEntity(clazz);
|
||||
@@ -1999,6 +1990,7 @@ class RequestConverter extends AbstractQueryProcessor {
|
||||
case INTERNAL -> VersionType.Internal;
|
||||
case EXTERNAL -> VersionType.External;
|
||||
case EXTERNAL_GTE -> VersionType.ExternalGte;
|
||||
case FORCE -> VersionType.Force;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+19
-22
@@ -22,7 +22,7 @@ import co.elastic.clients.elasticsearch._types.BulkIndexByScrollFailure;
|
||||
import co.elastic.clients.elasticsearch._types.ErrorCause;
|
||||
import co.elastic.clients.elasticsearch._types.Time;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
|
||||
import co.elastic.clients.elasticsearch.cluster.ComponentTemplateSummaryRes;
|
||||
import co.elastic.clients.elasticsearch.cluster.ComponentTemplateSummary;
|
||||
import co.elastic.clients.elasticsearch.cluster.GetComponentTemplateResponse;
|
||||
import co.elastic.clients.elasticsearch.cluster.HealthResponse;
|
||||
import co.elastic.clients.elasticsearch.core.DeleteByQueryResponse;
|
||||
@@ -48,7 +48,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.ElasticsearchErrorCause;
|
||||
import org.springframework.data.elasticsearch.core.IndexInformation;
|
||||
import org.springframework.data.elasticsearch.core.MultiGetItem;
|
||||
@@ -66,7 +65,7 @@ import org.springframework.data.elasticsearch.core.reindex.ReindexResponse;
|
||||
import org.springframework.data.elasticsearch.core.script.Script;
|
||||
import org.springframework.data.elasticsearch.core.sql.SqlResponse;
|
||||
import org.springframework.data.elasticsearch.support.DefaultStringObjectMap;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -133,7 +132,7 @@ class ResponseConverter {
|
||||
.build();
|
||||
}
|
||||
|
||||
private TemplateResponseData clusterGetComponentTemplateData(ComponentTemplateSummaryRes componentTemplateSummary) {
|
||||
private TemplateResponseData clusterGetComponentTemplateData(ComponentTemplateSummary componentTemplateSummary) {
|
||||
|
||||
var mapping = typeMapping(componentTemplateSummary.mappings());
|
||||
var settings = new Settings();
|
||||
@@ -192,7 +191,7 @@ class ResponseConverter {
|
||||
Assert.notNull(getMappingResponse, "getMappingResponse must not be null");
|
||||
Assert.notNull(indexCoordinates, "indexCoordinates must not be null");
|
||||
|
||||
Map<String, IndexMappingRecord> mappings = getMappingResponse.mappings();
|
||||
Map<String, IndexMappingRecord> mappings = getMappingResponse.result();
|
||||
|
||||
if (mappings == null || mappings.isEmpty()) {
|
||||
return Document.create();
|
||||
@@ -220,7 +219,7 @@ class ResponseConverter {
|
||||
|
||||
List<IndexInformation> indexInformationList = new ArrayList<>();
|
||||
|
||||
getIndexResponse.indices().forEach((indexName, indexState) -> {
|
||||
getIndexResponse.result().forEach((indexName, indexState) -> {
|
||||
Settings settings = indexState.settings() != null ? Settings.parse(toJson(indexState.settings(), jsonpMapper))
|
||||
: new Settings();
|
||||
Document mappings = indexState.mappings() != null ? Document.parse(toJson(indexState.mappings(), jsonpMapper))
|
||||
@@ -240,7 +239,7 @@ class ResponseConverter {
|
||||
Assert.notNull(getAliasResponse, "getAliasResponse must not be null");
|
||||
|
||||
Map<String, Set<AliasData>> aliasDataMap = new HashMap<>();
|
||||
getAliasResponse.aliases().forEach((indexName, alias) -> {
|
||||
getAliasResponse.result().forEach((indexName, alias) -> {
|
||||
Set<AliasData> aliasDataSet = new HashSet<>();
|
||||
alias.aliases()
|
||||
.forEach((aliasName, aliasDefinition) -> aliasDataSet.add(indicesGetAliasData(aliasName, aliasDefinition)));
|
||||
@@ -336,11 +335,11 @@ class ResponseConverter {
|
||||
.build();
|
||||
}
|
||||
|
||||
private TemplateResponseData indexGetComponentTemplateData(IndexTemplateSummaryWithRollover indexTemplateSummary,
|
||||
private TemplateResponseData indexGetComponentTemplateData(IndexTemplateSummary indexTemplateSummary,
|
||||
List<String> composedOf) {
|
||||
var mapping = typeMapping(indexTemplateSummary.mappings());
|
||||
|
||||
Function<@Nullable IndexSettings, @Nullable Settings> indexSettingsToSettings = indexSettings -> {
|
||||
Function<IndexSettings, Settings> indexSettingsToSettings = indexSettings -> {
|
||||
|
||||
if (indexSettings == null) {
|
||||
return null;
|
||||
@@ -416,7 +415,8 @@ class ResponseConverter {
|
||||
.withErrorCause(toErrorCause(failure.cause())).build();
|
||||
}
|
||||
|
||||
public static MultiGetItem.@Nullable Failure getFailure(MultiGetResponseItem<EntityAsMap> itemResponse) {
|
||||
@Nullable
|
||||
public static MultiGetItem.Failure getFailure(MultiGetResponseItem<EntityAsMap> itemResponse) {
|
||||
|
||||
MultiGetError responseFailure = itemResponse.isFailure() ? itemResponse.failure() : null;
|
||||
|
||||
@@ -498,7 +498,7 @@ class ResponseConverter {
|
||||
builder.withDeleted(response.deleted());
|
||||
}
|
||||
|
||||
if (response.updated() != null) {
|
||||
if(response.updated() != null) {
|
||||
builder.withUpdated(response.updated());
|
||||
}
|
||||
|
||||
@@ -536,7 +536,7 @@ class ResponseConverter {
|
||||
? Script.builder() //
|
||||
.withId(response.id()) //
|
||||
.withLanguage(response.script().lang()) //
|
||||
.withSource(response.script().source().scriptString()).build() //
|
||||
.withSource(response.script().source()).build() //
|
||||
: null;
|
||||
}
|
||||
// endregion
|
||||
@@ -575,20 +575,17 @@ class ResponseConverter {
|
||||
}
|
||||
}
|
||||
|
||||
@Contract("null -> null; !null -> !null")
|
||||
@Nullable
|
||||
static ElasticsearchErrorCause toErrorCause(@Nullable ErrorCause errorCause) {
|
||||
|
||||
if (errorCause != null) {
|
||||
return new ElasticsearchErrorCause(
|
||||
errorCause.type(),
|
||||
errorCause.reason(),
|
||||
errorCause.stackTrace(),
|
||||
toErrorCause(errorCause.causedBy()),
|
||||
(List<ElasticsearchErrorCause>) (errorCause.rootCause().stream()
|
||||
.map(ResponseConverter::toErrorCause).collect(Collectors.toList())),
|
||||
(List<ElasticsearchErrorCause>) (errorCause.suppressed().stream().map(ResponseConverter::toErrorCause)
|
||||
.collect(Collectors.toList())));
|
||||
return new ElasticsearchErrorCause( //
|
||||
errorCause.type(), //
|
||||
errorCause.reason(), //
|
||||
errorCause.stackTrace(), //
|
||||
toErrorCause(errorCause.causedBy()), //
|
||||
errorCause.rootCause().stream().map(ResponseConverter::toErrorCause).collect(Collectors.toList()), //
|
||||
errorCause.suppressed().stream().map(ResponseConverter::toErrorCause).collect(Collectors.toList()));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
+3
-5
@@ -39,7 +39,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.SearchShardStatistics;
|
||||
import org.springframework.data.elasticsearch.core.TotalHitsRelation;
|
||||
import org.springframework.data.elasticsearch.core.document.SearchDocument;
|
||||
@@ -49,6 +48,7 @@ import org.springframework.data.elasticsearch.core.suggest.response.PhraseSugges
|
||||
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
|
||||
import org.springframework.data.elasticsearch.core.suggest.response.TermSuggestion;
|
||||
import org.springframework.data.elasticsearch.support.ScoreDoc;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -133,8 +133,7 @@ class SearchDocumentResponseBuilder {
|
||||
* @return the {@link SearchDocumentResponse}
|
||||
*/
|
||||
public static <T> SearchDocumentResponse from(HitsMetadata<?> hitsMetadata, @Nullable ShardStatistics shards,
|
||||
@Nullable String scrollId, @Nullable String pointInTimeId, long executionDurationInMillis,
|
||||
@Nullable Map<String, Aggregate> aggregations,
|
||||
@Nullable String scrollId, @Nullable String pointInTimeId, long executionDurationInMillis, @Nullable Map<String, Aggregate> aggregations,
|
||||
Map<String, List<Suggestion<EntityAsMap>>> suggestES, SearchDocumentResponse.EntityCreator<T> entityCreator,
|
||||
JsonpMapper jsonpMapper) {
|
||||
|
||||
@@ -172,8 +171,7 @@ class SearchDocumentResponseBuilder {
|
||||
|
||||
SearchShardStatistics shardStatistics = shards != null ? shardsFrom(shards) : null;
|
||||
|
||||
return new SearchDocumentResponse(totalHits, totalHitsRelation, maxScore, executionDuration, scrollId,
|
||||
pointInTimeId, searchDocuments,
|
||||
return new SearchDocumentResponse(totalHits, totalHitsRelation, maxScore, executionDuration, scrollId, pointInTimeId, searchDocuments,
|
||||
aggregationsContainer, suggest, shardStatistics);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,10 +36,8 @@ import java.util.EnumSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.elasticsearch.core.RefreshPolicy;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
@@ -54,6 +52,7 @@ import org.springframework.data.elasticsearch.core.query.UpdateResponse;
|
||||
import org.springframework.data.elasticsearch.core.query.types.ConflictsType;
|
||||
import org.springframework.data.elasticsearch.core.query.types.OperatorType;
|
||||
import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -145,12 +144,6 @@ final class TypeUtils {
|
||||
}
|
||||
}
|
||||
|
||||
static Object toObjectNotNull(FieldValue fieldValue) {
|
||||
|
||||
Objects.requireNonNull(fieldValue);
|
||||
return toObject(fieldValue);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Object toObject(@Nullable FieldValue fieldValue) {
|
||||
|
||||
@@ -227,7 +220,7 @@ final class TypeUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static SortOrder sortOrder(Sort.@Nullable Direction direction) {
|
||||
static SortOrder sortOrder(@Nullable Sort.Direction direction) {
|
||||
|
||||
if (direction == null) {
|
||||
return null;
|
||||
@@ -308,7 +301,7 @@ final class TypeUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static OpType opType(IndexQuery.@Nullable OpType opType) {
|
||||
static OpType opType(@Nullable IndexQuery.OpType opType) {
|
||||
|
||||
if (opType != null) {
|
||||
return switch (opType) {
|
||||
@@ -332,7 +325,8 @@ final class TypeUtils {
|
||||
};
|
||||
}
|
||||
|
||||
static UpdateResponse.@Nullable Result result(@Nullable Result result) {
|
||||
@Nullable
|
||||
static UpdateResponse.Result result(@Nullable Result result) {
|
||||
|
||||
if (result == null) {
|
||||
return null;
|
||||
@@ -349,7 +343,7 @@ final class TypeUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ScoreMode scoreMode(RescorerQuery.@Nullable ScoreMode scoreMode) {
|
||||
static ScoreMode scoreMode(@Nullable RescorerQuery.ScoreMode scoreMode) {
|
||||
|
||||
if (scoreMode == null) {
|
||||
return null;
|
||||
@@ -367,7 +361,7 @@ final class TypeUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static SearchType searchType(Query.@Nullable SearchType searchType) {
|
||||
static SearchType searchType(@Nullable Query.SearchType searchType) {
|
||||
|
||||
if (searchType == null) {
|
||||
return null;
|
||||
@@ -424,13 +418,14 @@ final class TypeUtils {
|
||||
|
||||
@Nullable
|
||||
static VersionType versionType(
|
||||
org.springframework.data.elasticsearch.annotations.Document.@Nullable VersionType versionType) {
|
||||
@Nullable org.springframework.data.elasticsearch.annotations.Document.VersionType versionType) {
|
||||
|
||||
if (versionType != null) {
|
||||
return switch (versionType) {
|
||||
case INTERNAL -> VersionType.Internal;
|
||||
case EXTERNAL -> VersionType.External;
|
||||
case EXTERNAL_GTE -> VersionType.ExternalGte;
|
||||
case FORCE -> VersionType.Force;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -492,7 +487,7 @@ final class TypeUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static IndexSettings indexSettings(@Nullable Map<String, @Nullable Object> settings) {
|
||||
static IndexSettings indexSettings(@Nullable Map<String, Object> settings) {
|
||||
return settings != null ? IndexSettings.of(b -> b.withJson(new StringReader(Document.from(settings).toJson())))
|
||||
: null;
|
||||
}
|
||||
@@ -541,7 +536,7 @@ final class TypeUtils {
|
||||
* @param scoreMode spring-data-elasticsearch {@literal scoreMode}.
|
||||
* @return an Elasticsearch {@literal scoreMode}.
|
||||
*/
|
||||
static ChildScoreMode scoreMode(HasChildQuery.@Nullable ScoreMode scoreMode) {
|
||||
static ChildScoreMode scoreMode(@Nullable HasChildQuery.ScoreMode scoreMode) {
|
||||
if (scoreMode == null) {
|
||||
return ChildScoreMode.None;
|
||||
}
|
||||
|
||||
+19
-18
@@ -15,10 +15,15 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client.elc.aot;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType;
|
||||
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
|
||||
import co.elastic.clients.elasticsearch.indices.IndexSettings;
|
||||
import co.elastic.clients.elasticsearch.indices.PutMappingRequest;
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* runtime hints for the Elasticsearch client libraries, as these do not provide any of their own.
|
||||
@@ -32,24 +37,20 @@ public class ElasticsearchClientRuntimeHints implements RuntimeHintsRegistrar {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
|
||||
hints.reflection()
|
||||
.registerTypeIfPresent(classLoader, "co.elastic.clients.elasticsearch.indices.IndexSettings",
|
||||
builder -> builder.withField("_DESERIALIZER"))
|
||||
.registerTypeIfPresent(classLoader, "co.elastic.clients.elasticsearch.indices.PutMappingRequest",
|
||||
builder -> builder.withField("_DESERIALIZER"))
|
||||
.registerTypeIfPresent(classLoader, "co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType",
|
||||
builder -> builder.withField("_DESERIALIZER"))
|
||||
.registerTypeIfPresent(classLoader, "co.elastic.clients.elasticsearch._types.mapping.TypeMapping",
|
||||
builder -> builder.withField("_DESERIALIZER"));
|
||||
.registerType(TypeReference.of(IndexSettings.class), builder -> builder.withField("_DESERIALIZER")) //
|
||||
.registerType(TypeReference.of(PutMappingRequest.class), builder -> builder.withField("_DESERIALIZER")) //
|
||||
.registerType(TypeReference.of(RuntimeFieldType.class), builder -> builder.withField("_DESERIALIZER"))//
|
||||
.registerType(TypeReference.of(TypeMapping.class), builder -> builder.withField("_DESERIALIZER")) //
|
||||
;
|
||||
|
||||
if (ClassUtils.isPresent("org.apache.http.impl.auth.BasicScheme",
|
||||
ElasticsearchClientRuntimeHints.class.getClassLoader())) {
|
||||
hints.serialization()
|
||||
.registerType(org.apache.http.impl.auth.BasicScheme.class)
|
||||
.registerType(org.apache.http.impl.auth.RFC2617Scheme.class)
|
||||
.registerType(java.util.HashMap.class);
|
||||
}
|
||||
hints.serialization() //
|
||||
.registerType(org.apache.http.impl.auth.BasicScheme.class) //
|
||||
.registerType(org.apache.http.impl.auth.RFC2617Scheme.class) //
|
||||
.registerType(java.util.HashMap.class) //
|
||||
;
|
||||
|
||||
hints.resources() //
|
||||
.registerPattern("co/elastic/clients/version.properties");
|
||||
.registerPattern("co/elastic/clients/version.properties") //
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-17
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2022-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.elasticsearch.client.elc.aot;
|
||||
|
||||
@@ -18,5 +18,6 @@
|
||||
* This package contains classes that use the new Elasticsearch client library (co.elastic.clients:elasticsearch-java)
|
||||
* to access Elasticsearch.
|
||||
*/
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
-307
@@ -1,307 +0,0 @@
|
||||
package org.springframework.data.elasticsearch.client.elc.rest5_client;
|
||||
|
||||
import co.elastic.clients.transport.TransportOptions;
|
||||
import co.elastic.clients.transport.TransportUtils;
|
||||
import co.elastic.clients.transport.rest5_client.Rest5ClientOptions;
|
||||
import co.elastic.clients.transport.rest5_client.low_level.RequestOptions;
|
||||
import co.elastic.clients.transport.rest5_client.low_level.Rest5Client;
|
||||
import co.elastic.clients.transport.rest5_client.low_level.Rest5ClientBuilder;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.hc.client5.http.config.ConnectionConfig;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
|
||||
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
|
||||
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.message.BasicHeader;
|
||||
import org.apache.hc.core5.http.nio.ssl.BasicClientTlsStrategy;
|
||||
import org.apache.hc.core5.util.Timeout;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.support.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utility class containing the functions to create the Elasticsearch Rest5Client used from Elasticsearch 9 on.
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public final class Rest5Clients {
|
||||
|
||||
// values copied from Rest5ClientBuilder
|
||||
public static final int DEFAULT_SOCKET_TIMEOUT_MILLIS = 30000;
|
||||
public static final int DEFAULT_RESPONSE_TIMEOUT_MILLIS = 0; // meaning infinite
|
||||
|
||||
private Rest5Clients() {}
|
||||
|
||||
/**
|
||||
* Creates a low level {@link Rest5Client} for the given configuration.
|
||||
*
|
||||
* @param clientConfiguration must not be {@literal null}
|
||||
* @return the {@link Rest5Client}
|
||||
*/
|
||||
public static Rest5Client getRest5Client(ClientConfiguration clientConfiguration) {
|
||||
return getRest5ClientBuilder(clientConfiguration).build();
|
||||
}
|
||||
|
||||
private static Rest5ClientBuilder getRest5ClientBuilder(ClientConfiguration clientConfiguration) {
|
||||
|
||||
HttpHost[] httpHosts = getHttpHosts(clientConfiguration);
|
||||
Rest5ClientBuilder builder = Rest5Client.builder(httpHosts);
|
||||
|
||||
if (clientConfiguration.getPathPrefix() != null) {
|
||||
builder.setPathPrefix(clientConfiguration.getPathPrefix());
|
||||
}
|
||||
|
||||
HttpHeaders headers = clientConfiguration.getDefaultHeaders();
|
||||
|
||||
if (!headers.isEmpty()) {
|
||||
builder.setDefaultHeaders(toHeaderArray(headers));
|
||||
}
|
||||
|
||||
// RestClientBuilder configuration callbacks from the consumer
|
||||
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurationCallback : clientConfiguration
|
||||
.getClientConfigurers()) {
|
||||
if (clientConfigurationCallback instanceof ElasticsearchRest5ClientConfigurationCallback configurationCallback) {
|
||||
builder = configurationCallback.configure(builder);
|
||||
}
|
||||
}
|
||||
|
||||
Duration connectTimeout = clientConfiguration.getConnectTimeout();
|
||||
Duration socketTimeout = clientConfiguration.getSocketTimeout();
|
||||
|
||||
builder.setHttpClientConfigCallback(httpAsyncClientBuilder -> {
|
||||
|
||||
if (clientConfiguration.getProxy().isPresent()) {
|
||||
var proxy = clientConfiguration.getProxy().get();
|
||||
try {
|
||||
var proxyRoutePlanner = new DefaultProxyRoutePlanner(HttpHost.create(proxy));
|
||||
httpAsyncClientBuilder.setRoutePlanner(proxyRoutePlanner);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
httpAsyncClientBuilder.addRequestInterceptorFirst((request, entity, context) -> {
|
||||
clientConfiguration.getHeadersSupplier().get().forEach((header, values) -> {
|
||||
// The accept and content-type headers are already put on the request, despite this being the first
|
||||
// interceptor.
|
||||
if ("Accept".equalsIgnoreCase(header) || " Content-Type".equalsIgnoreCase(header)) {
|
||||
request.removeHeaders(header);
|
||||
}
|
||||
values.forEach(value -> request.addHeader(header, value));
|
||||
});
|
||||
});
|
||||
|
||||
// add httpclient configurator callbacks provided by the configuration
|
||||
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
|
||||
.getClientConfigurers()) {
|
||||
if (clientConfigurer instanceof ElasticsearchHttpClientConfigurationCallback httpClientConfigurer) {
|
||||
httpAsyncClientBuilder = httpClientConfigurer.configure(httpAsyncClientBuilder);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
builder.setConnectionConfigCallback(connectionConfigBuilder -> {
|
||||
|
||||
if (!connectTimeout.isNegative()) {
|
||||
connectionConfigBuilder.setConnectTimeout(
|
||||
Timeout.of(Math.toIntExact(connectTimeout.toMillis()), TimeUnit.MILLISECONDS));
|
||||
}
|
||||
if (!socketTimeout.isNegative()) {
|
||||
var soTimeout = Timeout.of(Math.toIntExact(socketTimeout.toMillis()), TimeUnit.MILLISECONDS);
|
||||
connectionConfigBuilder.setSocketTimeout(soTimeout);
|
||||
} else {
|
||||
connectionConfigBuilder.setSocketTimeout(Timeout.of(DEFAULT_SOCKET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
// add connectionConfig configurator callbacks provided by the configuration
|
||||
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
|
||||
.getClientConfigurers()) {
|
||||
if (clientConfigurer instanceof ElasticsearchConnectionConfigurationCallback connectionConfigurationCallback) {
|
||||
connectionConfigBuilder = connectionConfigurationCallback.configure(connectionConfigBuilder);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
builder.setConnectionManagerCallback(poolingAsyncClientConnectionManagerBuilder -> {
|
||||
|
||||
SSLContext sslContext = null;
|
||||
try {
|
||||
sslContext = clientConfiguration.getCaFingerprint().isPresent()
|
||||
? TransportUtils.sslContextFromCaFingerprint(clientConfiguration.getCaFingerprint().get())
|
||||
: (clientConfiguration.getSslContext().isPresent()
|
||||
? clientConfiguration.getSslContext().get()
|
||||
: SSLContext.getDefault());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("could not create the default ssl context", e);
|
||||
}
|
||||
poolingAsyncClientConnectionManagerBuilder.setTlsStrategy(new BasicClientTlsStrategy(sslContext));
|
||||
|
||||
// add connectionManager configurator callbacks provided by the configuration
|
||||
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
|
||||
.getClientConfigurers()) {
|
||||
if (clientConfigurer instanceof ElasticsearchConnectionManagerCallback connectionManagerCallback) {
|
||||
poolingAsyncClientConnectionManagerBuilder = connectionManagerCallback
|
||||
.configure(poolingAsyncClientConnectionManagerBuilder);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
builder.setRequestConfigCallback(requestConfigBuilder -> {
|
||||
|
||||
if (!socketTimeout.isNegative()) {
|
||||
var soTimeout = Timeout.of(Math.toIntExact(socketTimeout.toMillis()), TimeUnit.MILLISECONDS);
|
||||
requestConfigBuilder.setConnectionRequestTimeout(soTimeout);
|
||||
} else {
|
||||
requestConfigBuilder
|
||||
.setConnectionRequestTimeout(Timeout.of(DEFAULT_RESPONSE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
// add connectionConfig configurator callbacks provided by the configuration
|
||||
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
|
||||
.getClientConfigurers()) {
|
||||
if (clientConfigurer instanceof ElasticsearchRequestConfigCallback requestConfigCallback) {
|
||||
requestConfigBuilder = requestConfigCallback.configure(requestConfigBuilder);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static HttpHost[] getHttpHosts(ClientConfiguration clientConfiguration) {
|
||||
List<InetSocketAddress> hosts = clientConfiguration.getEndpoints();
|
||||
boolean useSsl = clientConfiguration.useSsl();
|
||||
return hosts.stream()
|
||||
.map(it -> (useSsl ? "https" : "http") + "://" + it.getHostString() + ':' + it.getPort())
|
||||
.map(URI::create)
|
||||
.map(HttpHost::create)
|
||||
.toArray(HttpHost[]::new);
|
||||
}
|
||||
|
||||
private static Header[] toHeaderArray(HttpHeaders headers) {
|
||||
return headers.entrySet().stream() //
|
||||
.flatMap(entry -> entry.getValue().stream() //
|
||||
.map(value -> new BasicHeader(entry.getKey(), value))) //
|
||||
.toList().toArray(new Header[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ClientConfiguration.ClientConfigurationCallback} to configure the Rest5Client client with a
|
||||
* {@link Rest5ClientBuilder}
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public interface ElasticsearchRest5ClientConfigurationCallback
|
||||
extends ClientConfiguration.ClientConfigurationCallback<Rest5ClientBuilder> {
|
||||
|
||||
static ElasticsearchRest5ClientConfigurationCallback from(
|
||||
Function<Rest5ClientBuilder, Rest5ClientBuilder> rest5ClientBuilderCallback) {
|
||||
|
||||
Assert.notNull(rest5ClientBuilderCallback, "rest5ClientBuilderCallback must not be null");
|
||||
|
||||
return rest5ClientBuilderCallback::apply;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
|
||||
* the Elasticsearch Rest5Client's Http client with a {@link HttpAsyncClientBuilder}
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public interface ElasticsearchHttpClientConfigurationCallback
|
||||
extends ClientConfiguration.ClientConfigurationCallback<HttpAsyncClientBuilder> {
|
||||
|
||||
static Rest5Clients.ElasticsearchHttpClientConfigurationCallback from(
|
||||
Function<HttpAsyncClientBuilder, HttpAsyncClientBuilder> httpClientBuilderCallback) {
|
||||
|
||||
Assert.notNull(httpClientBuilderCallback, "httpClientBuilderCallback must not be null");
|
||||
|
||||
return httpClientBuilderCallback::apply;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
|
||||
* the Elasticsearch Rest5Client's connection with a {@link ConnectionConfig.Builder}
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public interface ElasticsearchConnectionConfigurationCallback
|
||||
extends ClientConfiguration.ClientConfigurationCallback<ConnectionConfig.Builder> {
|
||||
|
||||
static ElasticsearchConnectionConfigurationCallback from(
|
||||
Function<ConnectionConfig.Builder, ConnectionConfig.Builder> connectionConfigBuilderCallback) {
|
||||
|
||||
Assert.notNull(connectionConfigBuilderCallback, "connectionConfigBuilderCallback must not be null");
|
||||
|
||||
return connectionConfigBuilderCallback::apply;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
|
||||
* the Elasticsearch Rest5Client's connection manager with a {@link PoolingAsyncClientConnectionManagerBuilder}
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public interface ElasticsearchConnectionManagerCallback
|
||||
extends ClientConfiguration.ClientConfigurationCallback<PoolingAsyncClientConnectionManagerBuilder> {
|
||||
|
||||
static ElasticsearchConnectionManagerCallback from(
|
||||
Function<PoolingAsyncClientConnectionManagerBuilder, PoolingAsyncClientConnectionManagerBuilder> connectionManagerBuilderCallback) {
|
||||
|
||||
Assert.notNull(connectionManagerBuilderCallback, "connectionManagerBuilderCallback must not be null");
|
||||
|
||||
return connectionManagerBuilderCallback::apply;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
|
||||
* the Elasticsearch Rest5Client's connection manager with a {@link RequestConfig.Builder}
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public interface ElasticsearchRequestConfigCallback
|
||||
extends ClientConfiguration.ClientConfigurationCallback<RequestConfig.Builder> {
|
||||
|
||||
static ElasticsearchRequestConfigCallback from(
|
||||
Function<RequestConfig.Builder, RequestConfig.Builder> requestConfigBuilderCallback) {
|
||||
|
||||
Assert.notNull(requestConfigBuilderCallback, "requestConfigBuilderCallback must not be null");
|
||||
|
||||
return requestConfigBuilderCallback::apply;
|
||||
}
|
||||
}
|
||||
|
||||
public static Rest5ClientOptions.Builder getRest5ClientOptionsBuilder(@Nullable TransportOptions transportOptions) {
|
||||
|
||||
if (transportOptions instanceof Rest5ClientOptions rest5ClientOptions) {
|
||||
return rest5ClientOptions.toBuilder();
|
||||
}
|
||||
|
||||
var builder = new Rest5ClientOptions.Builder(RequestOptions.DEFAULT.toBuilder());
|
||||
|
||||
if (transportOptions != null) {
|
||||
transportOptions.headers().forEach(header -> builder.addHeader(header.getKey(), header.getValue()));
|
||||
transportOptions.queryParameters().forEach(builder::setParameter);
|
||||
builder.onWarnings(transportOptions.onWarnings());
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains related to the new (from Elasticsearch 9 on) Rest5Client. There are also classes copied over from Elasticsearch in order to have a Rest5ClientBuilder that allows to configure the http client.
|
||||
*/
|
||||
@org.jspecify.annotations.NullMarked
|
||||
package org.springframework.data.elasticsearch.client.elc.rest5_client;
|
||||
-193
@@ -1,193 +0,0 @@
|
||||
package org.springframework.data.elasticsearch.client.elc.rest_client;
|
||||
|
||||
import co.elastic.clients.transport.TransportOptions;
|
||||
import co.elastic.clients.transport.TransportUtils;
|
||||
import co.elastic.clients.transport.rest_client.RestClientOptions;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpRequestInterceptor;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.client.RestClientBuilder;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.support.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utility class containing the functions to create the Elasticsearch RestClient used up to Elasticsearch 9.
|
||||
*
|
||||
* @since 6.0
|
||||
* @deprecated since 6.0, use the new Rest5Client the code for that is in the package ../rest_client.
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public final class RestClients {
|
||||
|
||||
/**
|
||||
* Creates a low level {@link RestClient} for the given configuration.
|
||||
*
|
||||
* @param clientConfiguration must not be {@literal null}
|
||||
* @return the {@link RestClient}
|
||||
*/
|
||||
public static RestClient getRestClient(ClientConfiguration clientConfiguration) {
|
||||
return getRestClientBuilder(clientConfiguration).build();
|
||||
}
|
||||
|
||||
private static RestClientBuilder getRestClientBuilder(ClientConfiguration clientConfiguration) {
|
||||
HttpHost[] httpHosts = getHttpHosts(clientConfiguration);
|
||||
RestClientBuilder builder = RestClient.builder(httpHosts);
|
||||
|
||||
if (clientConfiguration.getPathPrefix() != null) {
|
||||
builder.setPathPrefix(clientConfiguration.getPathPrefix());
|
||||
}
|
||||
|
||||
HttpHeaders headers = clientConfiguration.getDefaultHeaders();
|
||||
|
||||
if (!headers.isEmpty()) {
|
||||
builder.setDefaultHeaders(toHeaderArray(headers));
|
||||
}
|
||||
|
||||
builder.setHttpClientConfigCallback(clientBuilder -> {
|
||||
if (clientConfiguration.getCaFingerprint().isPresent()) {
|
||||
clientBuilder
|
||||
.setSSLContext(TransportUtils.sslContextFromCaFingerprint(clientConfiguration.getCaFingerprint().get()));
|
||||
}
|
||||
clientConfiguration.getSslContext().ifPresent(clientBuilder::setSSLContext);
|
||||
clientConfiguration.getHostNameVerifier().ifPresent(clientBuilder::setSSLHostnameVerifier);
|
||||
clientBuilder.addInterceptorLast(new CustomHeaderInjector(clientConfiguration.getHeadersSupplier()));
|
||||
|
||||
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
|
||||
Duration connectTimeout = clientConfiguration.getConnectTimeout();
|
||||
|
||||
if (!connectTimeout.isNegative()) {
|
||||
requestConfigBuilder.setConnectTimeout(Math.toIntExact(connectTimeout.toMillis()));
|
||||
}
|
||||
|
||||
Duration socketTimeout = clientConfiguration.getSocketTimeout();
|
||||
|
||||
if (!socketTimeout.isNegative()) {
|
||||
requestConfigBuilder.setSocketTimeout(Math.toIntExact(socketTimeout.toMillis()));
|
||||
requestConfigBuilder.setConnectionRequestTimeout(Math.toIntExact(socketTimeout.toMillis()));
|
||||
}
|
||||
|
||||
clientBuilder.setDefaultRequestConfig(requestConfigBuilder.build());
|
||||
|
||||
clientConfiguration.getProxy().map(HttpHost::create).ifPresent(clientBuilder::setProxy);
|
||||
|
||||
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
|
||||
.getClientConfigurers()) {
|
||||
if (clientConfigurer instanceof RestClients.ElasticsearchHttpClientConfigurationCallback restClientConfigurationCallback) {
|
||||
clientBuilder = restClientConfigurationCallback.configure(clientBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
return clientBuilder;
|
||||
});
|
||||
|
||||
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurationCallback : clientConfiguration
|
||||
.getClientConfigurers()) {
|
||||
if (clientConfigurationCallback instanceof ElasticsearchRestClientConfigurationCallback configurationCallback) {
|
||||
builder = configurationCallback.configure(builder);
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static HttpHost[] getHttpHosts(ClientConfiguration clientConfiguration) {
|
||||
List<InetSocketAddress> hosts = clientConfiguration.getEndpoints();
|
||||
boolean useSsl = clientConfiguration.useSsl();
|
||||
return hosts.stream()
|
||||
.map(it -> (useSsl ? "https" : "http") + "://" + it.getHostString() + ':' + it.getPort())
|
||||
.map(HttpHost::create).toArray(HttpHost[]::new);
|
||||
}
|
||||
|
||||
private static org.apache.http.Header[] toHeaderArray(HttpHeaders headers) {
|
||||
return headers.entrySet().stream() //
|
||||
.flatMap(entry -> entry.getValue().stream() //
|
||||
.map(value -> new BasicHeader(entry.getKey(), value))) //
|
||||
.toArray(org.apache.http.Header[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interceptor to inject custom supplied headers.
|
||||
*
|
||||
* @since 4.4
|
||||
*/
|
||||
record CustomHeaderInjector(Supplier<HttpHeaders> headersSupplier) implements HttpRequestInterceptor {
|
||||
|
||||
@Override
|
||||
public void process(@Nullable HttpRequest request, @Nullable HttpContext context) {
|
||||
HttpHeaders httpHeaders = headersSupplier.get();
|
||||
|
||||
if (!httpHeaders.isEmpty() && request != null) {
|
||||
Arrays.stream(toHeaderArray(httpHeaders)).forEach(request::addHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
|
||||
* the Elasticsearch RestClient's Http client with a {@link HttpAsyncClientBuilder}
|
||||
*
|
||||
* @since 4.4
|
||||
*/
|
||||
public interface ElasticsearchHttpClientConfigurationCallback
|
||||
extends ClientConfiguration.ClientConfigurationCallback<HttpAsyncClientBuilder> {
|
||||
|
||||
static RestClients.ElasticsearchHttpClientConfigurationCallback from(
|
||||
Function<HttpAsyncClientBuilder, HttpAsyncClientBuilder> httpClientBuilderCallback) {
|
||||
|
||||
Assert.notNull(httpClientBuilderCallback, "httpClientBuilderCallback must not be null");
|
||||
|
||||
return httpClientBuilderCallback::apply;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
|
||||
* the RestClient client with a {@link RestClientBuilder}
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface ElasticsearchRestClientConfigurationCallback
|
||||
extends ClientConfiguration.ClientConfigurationCallback<RestClientBuilder> {
|
||||
|
||||
static ElasticsearchRestClientConfigurationCallback from(
|
||||
Function<RestClientBuilder, RestClientBuilder> restClientBuilderCallback) {
|
||||
|
||||
Assert.notNull(restClientBuilderCallback, "restClientBuilderCallback must not be null");
|
||||
|
||||
return restClientBuilderCallback::apply;
|
||||
}
|
||||
}
|
||||
|
||||
public static RestClientOptions.Builder getRestClientOptionsBuilder(@Nullable TransportOptions transportOptions) {
|
||||
|
||||
if (transportOptions instanceof RestClientOptions restClientOptions) {
|
||||
return restClientOptions.toBuilder();
|
||||
}
|
||||
|
||||
var builder = new RestClientOptions.Builder(RequestOptions.DEFAULT.toBuilder());
|
||||
|
||||
if (transportOptions != null) {
|
||||
transportOptions.headers().forEach(header -> builder.addHeader(header.getKey(), header.getValue()));
|
||||
transportOptions.queryParameters().forEach(builder::setParameter);
|
||||
builder.onWarnings(transportOptions.onWarnings());
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains related to the old (up to Elasticsearch 9) RestClient.
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval=true)
|
||||
@org.jspecify.annotations.NullMarked
|
||||
package org.springframework.data.elasticsearch.client.elc.rest_client;
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2022-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.elasticsearch.client;
|
||||
|
||||
@@ -19,7 +19,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2022-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.elasticsearch.client.util;
|
||||
|
||||
+1
-1
@@ -17,7 +17,6 @@ package org.springframework.data.elasticsearch.config;
|
||||
|
||||
import static org.springframework.data.config.ParsingUtils.*;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
@@ -29,6 +28,7 @@ import org.springframework.data.auditing.config.IsNewAwareAuditingHandlerBeanDef
|
||||
import org.springframework.data.elasticsearch.core.event.AuditingEntityCallback;
|
||||
import org.springframework.data.elasticsearch.core.event.ReactiveAuditingEntityCallback;
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
+2
-3
@@ -18,10 +18,8 @@ package org.springframework.data.elasticsearch.config;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
@@ -36,6 +34,7 @@ import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchC
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -99,7 +98,7 @@ public class ElasticsearchConfigurationSupport {
|
||||
protected Collection<String> getMappingBasePackages() {
|
||||
|
||||
Package mappingBasePackage = getClass().getPackage();
|
||||
return mappingBasePackage == null ? Collections.emptyList() : List.of(mappingBasePackage.getName());
|
||||
return Collections.singleton(mappingBasePackage == null ? null : mappingBasePackage.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2022-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.elasticsearch.config;
|
||||
|
||||
+4
-33
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -26,7 +24,6 @@ import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
@@ -45,6 +42,7 @@ import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersiste
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
import org.springframework.data.elasticsearch.core.query.BulkOptions;
|
||||
import org.springframework.data.elasticsearch.core.query.ByQueryResponse;
|
||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
|
||||
@@ -59,7 +57,7 @@ import org.springframework.data.elasticsearch.support.VersionInfo;
|
||||
import org.springframework.data.mapping.callback.EntityCallbacks;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -87,7 +85,6 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
@Nullable protected EntityCallbacks entityCallbacks;
|
||||
@Nullable protected RefreshPolicy refreshPolicy;
|
||||
protected RoutingResolver routingResolver;
|
||||
protected ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
|
||||
|
||||
public AbstractElasticsearchTemplate() {
|
||||
this(null);
|
||||
@@ -120,8 +117,6 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
|
||||
copy.setRoutingResolver(routingResolver);
|
||||
copy.setRefreshPolicy(refreshPolicy);
|
||||
copy.setObservationRegistry(observationRegistry);
|
||||
customizeCopy(copy);
|
||||
|
||||
return copy;
|
||||
}
|
||||
@@ -176,27 +171,6 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
return refreshPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ObservationRegistry} to use for recording observations.
|
||||
*
|
||||
* @param observationRegistry must not be {@literal null}.
|
||||
* @since 6.1
|
||||
*/
|
||||
public void setObservationRegistry(ObservationRegistry observationRegistry) {
|
||||
|
||||
Assert.notNull(observationRegistry, "observationRegistry must not be null");
|
||||
|
||||
this.observationRegistry = observationRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for subclasses to copy additional state during {@link #copy()}. Called after all common fields have been
|
||||
* copied. The default implementation does nothing.
|
||||
*
|
||||
* @param copy the new template instance to customize
|
||||
*/
|
||||
protected void customizeCopy(AbstractElasticsearchTemplate copy) {}
|
||||
|
||||
/**
|
||||
* logs the versions of the different Elasticsearch components.
|
||||
*
|
||||
@@ -261,7 +235,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
List<IndexedObjectInformation> indexedObjectInformationList = bulkIndex(indexQueries, index);
|
||||
Iterator<IndexedObjectInformation> iterator = indexedObjectInformationList.iterator();
|
||||
|
||||
// noinspection unchecked,DataFlowIssue
|
||||
// noinspection unchecked
|
||||
return indexQueries.stream() //
|
||||
.map(IndexQuery::getObject) //
|
||||
.map(entity -> (T) entityOperations.updateIndexedObject(
|
||||
@@ -594,7 +568,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
}
|
||||
|
||||
protected <T> SearchDocumentResponse.EntityCreator<T> getEntityCreator(ReadDocumentCallback<T> documentCallback) {
|
||||
return searchDocument -> CompletableFuture.<T> completedFuture(documentCallback.doWith(searchDocument));
|
||||
return searchDocument -> CompletableFuture.completedFuture(documentCallback.doWith(searchDocument));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -753,7 +727,6 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
|
||||
// region Document callbacks
|
||||
protected interface DocumentCallback<T> {
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
T doWith(@Nullable Document document);
|
||||
}
|
||||
@@ -817,7 +790,6 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
|
||||
@Override
|
||||
public SearchHits<T> doWith(SearchDocumentResponse response) {
|
||||
// noinspection NullableProblems,DataFlowIssue
|
||||
List<T> entities = response.getSearchDocuments().stream().map(delegate::doWith).collect(Collectors.toList());
|
||||
return SearchHitMapping.mappingFor(type, elasticsearchConverter).mapHits(response, entities);
|
||||
}
|
||||
@@ -838,7 +810,6 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
|
||||
@Override
|
||||
public SearchScrollHits<T> doWith(SearchDocumentResponse response) {
|
||||
// noinspection DataFlowIssue,NullableProblems
|
||||
List<T> entities = response.getSearchDocuments().stream().map(delegate::doWith).collect(Collectors.toList());
|
||||
return SearchHitMapping.mappingFor(type, elasticsearchConverter).mapScrollHits(response, entities);
|
||||
}
|
||||
|
||||
+4
-29
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.Sinks;
|
||||
@@ -27,7 +26,6 @@ import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.reactivestreams.Subscription;
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -58,6 +56,7 @@ import org.springframework.data.elasticsearch.core.script.Script;
|
||||
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
|
||||
import org.springframework.data.elasticsearch.support.VersionInfo;
|
||||
import org.springframework.data.mapping.callback.ReactiveEntityCallbacks;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -78,7 +77,6 @@ abstract public class AbstractReactiveElasticsearchTemplate
|
||||
protected RoutingResolver routingResolver;
|
||||
|
||||
protected @Nullable ReactiveEntityCallbacks entityCallbacks;
|
||||
protected ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
|
||||
|
||||
// region Initialization
|
||||
protected AbstractReactiveElasticsearchTemplate(@Nullable ElasticsearchConverter converter) {
|
||||
@@ -111,8 +109,6 @@ abstract public class AbstractReactiveElasticsearchTemplate
|
||||
}
|
||||
|
||||
copy.setRoutingResolver(routingResolver);
|
||||
copy.setObservationRegistry(observationRegistry);
|
||||
customizeCopy(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@@ -166,27 +162,6 @@ abstract public class AbstractReactiveElasticsearchTemplate
|
||||
this.entityCallbacks = entityCallbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ObservationRegistry} to use for recording observations.
|
||||
*
|
||||
* @param observationRegistry must not be {@literal null}.
|
||||
* @since 6.1
|
||||
*/
|
||||
public void setObservationRegistry(ObservationRegistry observationRegistry) {
|
||||
|
||||
Assert.notNull(observationRegistry, "observationRegistry must not be null");
|
||||
|
||||
this.observationRegistry = observationRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for subclasses to copy additional state during {@link #copy()}. Called after all common fields have been
|
||||
* copied. The default implementation does nothing.
|
||||
*
|
||||
* @param copy the new template instance to customize
|
||||
*/
|
||||
protected void customizeCopy(AbstractReactiveElasticsearchTemplate copy) {}
|
||||
|
||||
/**
|
||||
* logs the versions of the different Elasticsearch components.
|
||||
*
|
||||
@@ -284,7 +259,8 @@ abstract public class AbstractReactiveElasticsearchTemplate
|
||||
sink.tryEmitComplete();
|
||||
}
|
||||
})
|
||||
.subscribe(v -> {}, error -> {
|
||||
.subscribe(v -> {
|
||||
}, error -> {
|
||||
if (subscription != null) {
|
||||
subscription.cancel();
|
||||
}
|
||||
@@ -766,8 +742,7 @@ abstract public class AbstractReactiveElasticsearchTemplate
|
||||
/**
|
||||
* Value class to capture client independent information from a response to an index request.
|
||||
*/
|
||||
public record IndexResponseMetaData(String id, String index, @Nullable Long seqNo, @Nullable Long primaryTerm,
|
||||
long version) {
|
||||
public record IndexResponseMetaData(String id, String index, long seqNo, long primaryTerm, long version) {
|
||||
}
|
||||
// endregion
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.data.elasticsearch.core;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.query.BulkOptions;
|
||||
import org.springframework.data.elasticsearch.core.query.ByQueryResponse;
|
||||
@@ -29,6 +28,7 @@ import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.UpdateResponse;
|
||||
import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
|
||||
import org.springframework.data.elasticsearch.core.reindex.ReindexResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* The operations for the
|
||||
|
||||
+1
-1
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.cluster.ClusterOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.routing.RoutingResolver;
|
||||
import org.springframework.data.elasticsearch.core.script.ScriptOperations;
|
||||
import org.springframework.data.elasticsearch.core.sql.SqlOperations;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* ElasticsearchOperations. Since 4.0 this interface only contains common helper functions, the other methods have been
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.join.JoinField;
|
||||
@@ -30,6 +29,7 @@ import org.springframework.data.mapping.IdentifierAccessor;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -123,7 +123,7 @@ public class EntityOperations {
|
||||
|
||||
// Only deal with text because ES generated Ids are strings!
|
||||
if (indexedObjectInformation.id() != null && idProperty != null
|
||||
// isReadable from the base class is false in case of records
|
||||
// isReadable from the base class is false in case of records
|
||||
&& (idProperty.isReadable() || idProperty.getOwner().getType().isRecord())
|
||||
&& idProperty.getType().isAssignableFrom(String.class)) {
|
||||
propertyAccessor.setProperty(idProperty, indexedObjectInformation.id());
|
||||
@@ -389,7 +389,7 @@ public class EntityOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SeqNoPrimaryTerm getSeqNoPrimaryTerm() {
|
||||
public SeqNoPrimaryTerm getSeqNoPrimaryTerm() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -425,12 +425,12 @@ public class EntityOperations {
|
||||
* @see org.springframework.data.elasticsearch.core.EntityOperations.Entity#getPersistentEntity()
|
||||
*/
|
||||
@Override
|
||||
public @Nullable ElasticsearchPersistentEntity<?> getPersistentEntity() {
|
||||
public ElasticsearchPersistentEntity<?> getPersistentEntity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getRouting() {
|
||||
public String getRouting() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -650,7 +650,7 @@ public class EntityOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getRouting() {
|
||||
public String getRouting() {
|
||||
|
||||
String routing = routingResolver.getRouting(propertyAccessor.getBean());
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.index.AliasData;
|
||||
import org.springframework.data.elasticsearch.core.index.Settings;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Immutable object that holds information(name, settings, mappings, aliases) about an Index
|
||||
|
||||
@@ -19,10 +19,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.index.*;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* The operations for the
|
||||
@@ -52,7 +52,7 @@ public interface IndexOperations {
|
||||
* @param settings the index settings
|
||||
* @return {@literal true} if the index was created
|
||||
*/
|
||||
boolean create(Map<String, @Nullable Object> settings);
|
||||
boolean create(Map<String, Object> settings);
|
||||
|
||||
/**
|
||||
* Create an index for given settings and mapping.
|
||||
@@ -62,7 +62,7 @@ public interface IndexOperations {
|
||||
* @return {@literal true} if the index was created
|
||||
* @since 4.2
|
||||
*/
|
||||
boolean create(Map<String, @Nullable Object> settings, Document mapping);
|
||||
boolean create(Map<String, Object> settings, Document mapping);
|
||||
|
||||
/**
|
||||
* Create an index with the settings and mapping defined for the entity this IndexOperations is bound to.
|
||||
@@ -142,7 +142,7 @@ public interface IndexOperations {
|
||||
*
|
||||
* @return the mapping
|
||||
*/
|
||||
Map<String, @Nullable Object> getMapping();
|
||||
Map<String, Object> getMapping();
|
||||
|
||||
// endregion
|
||||
|
||||
|
||||
+4
-4
@@ -22,10 +22,10 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.index.*;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -46,12 +46,12 @@ public interface IndexOperationsAdapter extends IndexOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean create(Map<String, @Nullable Object> settings) {
|
||||
public boolean create(Map<String, Object> settings) {
|
||||
return Boolean.TRUE.equals(reactiveIndexOperations.create(settings).block());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean create(Map<String, @Nullable Object> settings, Document mapping) {
|
||||
public boolean create(Map<String, Object> settings, Document mapping) {
|
||||
return Boolean.TRUE.equals(reactiveIndexOperations.create(settings, mapping).block());
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public interface IndexOperationsAdapter extends IndexOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, @Nullable Object> getMapping() {
|
||||
public Map<String, Object> getMapping() {
|
||||
return Objects.requireNonNull(reactiveIndexOperations.getMapping().block());
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Value class capturing information about a newly indexed document in Elasticsearch.
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.ElasticsearchErrorCause;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Response object for items returned from multiget requests, encapsulating the returned data and potential error
|
||||
@@ -36,7 +36,7 @@ public class MultiGetItem<T> {
|
||||
}
|
||||
|
||||
public static <T> MultiGetItem<T> of(@Nullable T item, @Nullable Failure failure) {
|
||||
return new MultiGetItem(item, failure);
|
||||
return new MultiGetItem<>(item, failure);
|
||||
}
|
||||
|
||||
public boolean hasItem() {
|
||||
|
||||
+1
-1
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
@@ -23,6 +22,7 @@ import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.routing.RoutingResolver;
|
||||
import org.springframework.data.elasticsearch.core.script.ReactiveScriptOperations;
|
||||
import org.springframework.data.elasticsearch.core.sql.ReactiveSqlOperations;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Interface that specifies a basic set of Elasticsearch operations executed in a reactive way.
|
||||
|
||||
+2
-3
@@ -21,7 +21,6 @@ import reactor.core.publisher.Mono;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.index.*;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
@@ -51,7 +50,7 @@ public interface ReactiveIndexOperations {
|
||||
* @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if eg.
|
||||
* the index already exist.
|
||||
*/
|
||||
Mono<Boolean> create(Map<String, @Nullable Object> settings);
|
||||
Mono<Boolean> create(Map<String, Object> settings);
|
||||
|
||||
/**
|
||||
* Create an index for given settings and mapping.
|
||||
@@ -62,7 +61,7 @@ public interface ReactiveIndexOperations {
|
||||
* the index already exist.
|
||||
* @since 4.2
|
||||
*/
|
||||
Mono<Boolean> create(Map<String, @Nullable Object> settings, Document mapping);
|
||||
Mono<Boolean> create(Map<String, Object> settings, Document mapping);
|
||||
|
||||
/**
|
||||
* Create an index with the settings and mapping defined for the entity this IndexOperations is bound to.
|
||||
|
||||
@@ -19,8 +19,8 @@ import reactor.core.publisher.Flux;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Encapsulates a Flux of {@link SearchHit}s with additional information from the search.
|
||||
|
||||
+1
-1
@@ -19,8 +19,8 @@ import reactor.core.publisher.Flux;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
|
||||
@@ -23,9 +23,9 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.document.Explanation;
|
||||
import org.springframework.data.elasticsearch.core.document.NestedMetaData;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -48,12 +48,12 @@ public class SearchHit<T> {
|
||||
@Nullable private final NestedMetaData nestedMetaData;
|
||||
@Nullable private final String routing;
|
||||
@Nullable private final Explanation explanation;
|
||||
private final Map<String, Double> matchedQueries = new LinkedHashMap<>();
|
||||
private final List<String> matchedQueries = new ArrayList<>();
|
||||
|
||||
public SearchHit(@Nullable String index, @Nullable String id, @Nullable String routing, float score,
|
||||
Object @Nullable [] sortValues, @Nullable Map<String, List<String>> highlightFields,
|
||||
@Nullable Object[] sortValues, @Nullable Map<String, List<String>> highlightFields,
|
||||
@Nullable Map<String, SearchHits<?>> innerHits, @Nullable NestedMetaData nestedMetaData,
|
||||
@Nullable Explanation explanation, @Nullable Map<String, Double> matchedQueries, T content) {
|
||||
@Nullable Explanation explanation, @Nullable List<String> matchedQueries, T content) {
|
||||
this.index = index;
|
||||
this.id = id;
|
||||
this.routing = routing;
|
||||
@@ -73,7 +73,7 @@ public class SearchHit<T> {
|
||||
this.content = content;
|
||||
|
||||
if (matchedQueries != null) {
|
||||
this.matchedQueries.putAll(matchedQueries);
|
||||
this.matchedQueries.addAll(matchedQueries);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +193,8 @@ public class SearchHit<T> {
|
||||
/**
|
||||
* @return the matched queries for this SearchHit.
|
||||
*/
|
||||
public Map<String, Double> getMatchedQueries() {
|
||||
@Nullable
|
||||
public List<String> getMatchedQueries() {
|
||||
return matchedQueries;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
@@ -35,6 +34,7 @@ import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersiste
|
||||
import org.springframework.data.elasticsearch.core.suggest.response.CompletionSuggestion;
|
||||
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,12 +21,11 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.core.ReactiveWrappers;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.data.util.ReactiveWrappers;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Utility class with helper methods for working with {@link SearchHit}.
|
||||
@@ -47,7 +46,6 @@ public final class SearchHitSupport {
|
||||
* @return a corresponding object where the SearchHits are replaced by their content if possible, otherwise the
|
||||
* original object
|
||||
*/
|
||||
@Contract("null -> null; !null -> !null")
|
||||
@Nullable
|
||||
public static Object unwrapSearchHits(@Nullable Object result) {
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ import java.time.Duration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Encapsulates a list of {@link SearchHit}s with additional information from the search.
|
||||
|
||||
@@ -19,9 +19,9 @@ import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -133,7 +133,7 @@ public class SearchHitsImpl<T> implements SearchScrollHits<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SearchShardStatistics getSearchShardStatistics() {
|
||||
public SearchShardStatistics getSearchShardStatistics() {
|
||||
return searchShardStatistics;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A {@link SearchHitsIterator} encapsulates {@link SearchHit} results that can be wrapped in a Java 8
|
||||
|
||||
@@ -18,11 +18,11 @@ package org.springframework.data.elasticsearch.core;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.query.BaseQueryBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* The operations for the
|
||||
@@ -233,8 +233,7 @@ public interface SearchOperations {
|
||||
Query idsQuery(List<String> ids);
|
||||
|
||||
/**
|
||||
* Creates a {@link BaseQueryBuilder} that has the given ids setto the parameter value. No other properties of the
|
||||
* bulder are set.
|
||||
* Creates a {@link BaseQueryBuilder} that has the given ids setto the parameter value. No other properties of the bulder are set.
|
||||
*
|
||||
* @param ids the list of ids must not be {@literal null}
|
||||
* @return query returning the documents with the given ids
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* This interface is used to expose the current {@code scrollId} from the underlying scroll context.
|
||||
|
||||
+1
-1
@@ -17,8 +17,8 @@ package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.ElasticsearchErrorCause;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Haibo Liu
|
||||
|
||||
@@ -23,8 +23,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.elasticsearch.client.util.ScrollState;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
+4
-16
@@ -1,18 +1,6 @@
|
||||
/*
|
||||
* Copyright 2022-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
/**
|
||||
* Interfaces and classes related to Elasticsearch cluster information and management.
|
||||
*/
|
||||
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.elasticsearch.core.cluster;
|
||||
|
||||
+2
-3
@@ -19,16 +19,15 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.data.convert.DefaultTypeMapper;
|
||||
import org.springframework.data.convert.SimpleTypeInformationMapper;
|
||||
import org.springframework.data.convert.TypeAliasAccessor;
|
||||
import org.springframework.data.convert.TypeInformationMapper;
|
||||
import org.springframework.data.core.TypeInformation;
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Elasticsearch specific {@link org.springframework.data.convert.TypeMapper} implementation.
|
||||
|
||||
+1
-1
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.convert;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.convert.EntityConverter;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
@@ -24,6 +23,7 @@ import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverte
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user