Compare commits
80 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d2a2b6268 | |||
| c1219da439 | |||
| 3203f29f08 | |||
| f18bea58f1 | |||
| 1a415958ad | |||
| c26f8bf8e4 | |||
| ca6ef58195 | |||
| 6bd96dc4d8 | |||
| 82c314206a | |||
| 2d2e4408d2 | |||
| 5c7b2a07ac | |||
| fa364c8bd4 | |||
| 679be76847 | |||
| 1fea502355 | |||
| 52e725f9a2 | |||
| 160fd851e6 | |||
| a409440e4e | |||
| 83d5a58737 | |||
| 1b62e311fd | |||
| bf5eaae357 | |||
| ee660bb208 | |||
| e01d618c83 | |||
| d48bfcc820 | |||
| c87e4a2fa5 | |||
| 3770f37855 | |||
| c5287dc326 | |||
| 53a9181d5f | |||
| 0c36132c5c | |||
| 33174ff28e | |||
| 67972f5b29 | |||
| e943a815b9 | |||
| 43e8e26b5b | |||
| 43133d6a9f | |||
| 5184fc44a7 | |||
| 93b353e3bf | |||
| 401893eb34 | |||
| b19af5cf17 | |||
| fd713bfc8e | |||
| c3bde816fe | |||
| 187a8b9e15 | |||
| ee02073142 | |||
| 0df58615e9 | |||
| a69658dc8b | |||
| f3e83bf4ae | |||
| 88552cfe1a | |||
| 40ecf9211d | |||
| bd898f0363 | |||
| b1a6dc524c | |||
| 197956c4d4 | |||
| bc0bead9b8 | |||
| 1459dd491d | |||
| 952e0c8985 | |||
| f6caa731dd | |||
| b7dbdbf0e0 | |||
| 80a61e27c4 | |||
| 0ce8e7ce0e | |||
| fde9f42735 | |||
| 6b2ad6cdc6 | |||
| 7e7ceb885d | |||
| 54c80f3375 | |||
| 39b318caa7 | |||
| 17af36702f | |||
| e22e2bbfc3 | |||
| b11f8d2c38 | |||
| 6062896568 | |||
| 33057cafb1 | |||
| 643b8b1e64 | |||
| 8f5947bfc7 | |||
| af78e0bf3d | |||
| e4f1c8ba58 | |||
| be4924a214 | |||
| 55119989f7 | |||
| 068de487b2 | |||
| bacad5ca0c | |||
| 864d41cb01 | |||
| 8dd7cfcc6e | |||
| 868664aa78 | |||
| 5f9eab9a97 | |||
| 090ed0be5c | |||
| fc9e47ccd7 |
@@ -1,8 +0,0 @@
|
||||
dist: xenial
|
||||
|
||||
language: java
|
||||
|
||||
jdk:
|
||||
- openjdk8
|
||||
|
||||
script: "mvn clean dependency:list test -Dsort -U -B"
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>3.2.4.RELEASE</version>
|
||||
<version>3.2.11.RELEASE</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.2.4.RELEASE</version>
|
||||
<version>2.2.11.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<name>Spring Data Elasticsearch</name>
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
<properties>
|
||||
<commonslang>2.6</commonslang>
|
||||
<elasticsearch>6.8.4</elasticsearch>
|
||||
<elasticsearch>6.8.13</elasticsearch>
|
||||
<log4j>2.9.1</log4j>
|
||||
<springdata.commons>2.2.4.RELEASE</springdata.commons>
|
||||
<springdata.commons>2.2.11.RELEASE</springdata.commons>
|
||||
<netty>4.1.39.Final</netty>
|
||||
<java-module-name>spring.data.elasticsearch</java-module-name>
|
||||
</properties>
|
||||
@@ -296,6 +296,7 @@
|
||||
<useFile>false</useFile>
|
||||
<includes>
|
||||
<include>**/*Tests.java</include>
|
||||
<include>**/*Test.java</include>
|
||||
</includes>
|
||||
<systemPropertyVariables>
|
||||
<es.set.netty.runtime.available.processors>false</es.set.netty.runtime.available.processors>
|
||||
|
||||
@@ -35,7 +35,7 @@ The following table shows the Elasticsearch versions that are used by Spring Dat
|
||||
[cols="^,^,^,^",options="header"]
|
||||
|===
|
||||
|Spring Data Release Train |Spring Data Elasticsearch |Elasticsearch | Spring Boot
|
||||
|Moore |3.2.x |6.8.4 |2.2.x
|
||||
|Moore |3.2.x |6.8.13 |2.2.x
|
||||
|Lovelace |3.1.x |6.2.2|2.1.x
|
||||
|Kayfootnote:oom[Out of maintenance]|3.0.xfootnote:oom[] |5.5.0 |2.0.xfootnote:oom[]
|
||||
|Ingallsfootnote:oom[]|2.1.xfootnote:oom[] |2.4.0 |1.5.xfootnote:oom[]
|
||||
|
||||
@@ -8,7 +8,7 @@ The Elasticsearch module supports all basic query building feature as string que
|
||||
|
||||
=== Declared queries
|
||||
|
||||
Deriving the query from the method name is not always sufficient and/or may result in unreadable method names. In this case one might make either use of `@Query` annotation (see <<elasticsearch.query-methods.at-query>> ).
|
||||
Deriving the query from the method name is not always sufficient and/or may result in unreadable method names. In this case one might make use of the `@Query` annotation (see <<elasticsearch.query-methods.at-query>> ).
|
||||
|
||||
[[elasticsearch.query-methods.criterions]]
|
||||
== Query creation
|
||||
@@ -29,12 +29,14 @@ The method name above will be translated into the following Elasticsearch json q
|
||||
|
||||
[source]
|
||||
----
|
||||
{ "bool" :
|
||||
{ "must" :
|
||||
[
|
||||
{ "field" : {"name" : "?"} },
|
||||
{ "field" : {"price" : "?"} }
|
||||
]
|
||||
{
|
||||
"query": {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } },
|
||||
{ "query_string" : { "query" : "?", "fields" : [ "price" ] } }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
@@ -48,80 +50,184 @@ A list of supported keywords for Elasticsearch is shown below.
|
||||
| Sample
|
||||
| Elasticsearch Query String| `And`
|
||||
| `findByNameAndPrice`
|
||||
| `{"bool" : {"must" : [ {"field" : {"name" : "?"}},
|
||||
{"field" : {"price" : "?"}} ]}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } },
|
||||
{ "query_string" : { "query" : "?", "fields" : [ "price" ] } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `Or`
|
||||
| `findByNameOrPrice`
|
||||
| `{"bool" : {"should" : [ {"field" : {"name" : "?"}},
|
||||
{"field" : {"price" : "?"}} ]}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"should" : [
|
||||
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } },
|
||||
{ "query_string" : { "query" : "?", "fields" : [ "price" ] } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `Is`
|
||||
| `findByName`
|
||||
| `{"bool" : {"must" : {"field" : {"name" : "?"}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `Not`
|
||||
| `findByNameNot`
|
||||
| `{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must_not" : [
|
||||
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `Between`
|
||||
| `findByPriceBetween`
|
||||
| `{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{"range" : {"price" : {"from" : ?, "to" : ?, "include_lower" : true, "include_upper" : true } } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `LessThan`
|
||||
| `findByPriceLessThan`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : false } } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `LessThanEqual`
|
||||
| `findByPriceLessThan`
|
||||
| `{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
null,"to" : ?,"include_lower" : true,"include_upper" :
|
||||
true}}}}}`
|
||||
| `findByPriceLessThanEqual`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `GreaterThan`
|
||||
| `findByPriceGreaterThan`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : false, "include_upper" : true } } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
|
||||
| `GreaterThanEqual`
|
||||
| `findByPriceGreaterThan`
|
||||
| `{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
?,"to" : null,"include_lower" : true,"include_upper" :
|
||||
true}}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `Before`
|
||||
| `findByPriceBefore`
|
||||
| `{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
null,"to" : ?,"include_lower" : true,"include_upper" :
|
||||
true}}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `After`
|
||||
| `findByPriceAfter`
|
||||
| `{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
?,"to" : null,"include_lower" : true,"include_upper" :
|
||||
true}}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `Like`
|
||||
| `findByNameLike`
|
||||
| `{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"?*","analyze_wildcard" : true}}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{ "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `StartingWith`
|
||||
| `findByNameStartingWith`
|
||||
| `{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"?*","analyze_wildcard" : true}}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{ "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `EndingWith`
|
||||
| `findByNameEndingWith`
|
||||
| `{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"*?","analyze_wildcard" : true}}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{ "query_string" : { "query" : "*?", "fields" : [ "name" ] }, "analyze_wildcard": true }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `Contains/Containing`
|
||||
| `findByNameContaining`
|
||||
| `{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"*?*","analyze_wildcard" : true}}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{ "query_string" : { "query" : "\*?*", "fields" : [ "name" ] }, "analyze_wildcard": true }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `In`
|
||||
| `findByNameIn(Collection<String>names)`
|
||||
| `{"bool" : {"must" : {"bool" : {"should" : [ {"field" :
|
||||
{"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{"bool" : {"must" : [
|
||||
{"terms" : {"name" : ["?","?"]}}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `NotIn`
|
||||
| `findByNameNotIn(Collection<String>names)`
|
||||
| `{"bool" : {"must_not" : {"bool" : {"should" : {"field" :
|
||||
{"name" : "?"}}}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{"bool" : {"must_not" : [
|
||||
{"terms" : {"name" : ["?","?"]}}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `Near`
|
||||
| `findByStoreNear`
|
||||
@@ -129,18 +235,45 @@ A list of supported keywords for Elasticsearch is shown below.
|
||||
|
||||
| `True`
|
||||
| `findByAvailableTrue`
|
||||
| `{"bool" : {"must" : {"field" : {"available" : true}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{ "query_string" : { "query" : "true", "fields" : [ "available" ] } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `False`
|
||||
| `findByAvailableFalse`
|
||||
| `{"bool" : {"must" : {"field" : {"available" : false}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{ "query_string" : { "query" : "false", "fields" : [ "available" ] } }
|
||||
]
|
||||
}
|
||||
}}`
|
||||
|
||||
| `OrderBy`
|
||||
| `findByAvailableTrueOrderByNameDesc`
|
||||
| `{"sort" : [{ "name" : {"order" : "desc"} }],"bool" :
|
||||
{"must" : {"field" : {"available" : true}}}}`
|
||||
| `{ "query" : {
|
||||
"bool" : {
|
||||
"must" : [
|
||||
{ "query_string" : { "query" : "true", "fields" : [ "available" ] } }
|
||||
]
|
||||
}
|
||||
}, "sort":[{"name":{"order":"desc"}}]
|
||||
}`
|
||||
|
||||
|===
|
||||
|
||||
== Method return types
|
||||
|
||||
Repository methods can be defined to have the following return types for returning multiple Elements:
|
||||
|
||||
* `List<T>`
|
||||
* `Stream<T>`
|
||||
* `AggregatedPage<T>`
|
||||
|
||||
[[elasticsearch.query-methods.at-query]]
|
||||
== Using @Query Annotation
|
||||
|
||||
@@ -149,8 +282,21 @@ A list of supported keywords for Elasticsearch is shown below.
|
||||
[source,java]
|
||||
----
|
||||
interface BookRepository extends ElasticsearchRepository<Book, String> {
|
||||
@Query("{\"bool\" : {\"must\" : {\"field\" : {\"name\" : \"?0\"}}}}")
|
||||
@Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}")
|
||||
Page<Book> findByName(String name,Pageable pageable);
|
||||
}
|
||||
----
|
||||
The String that is set as the annotation argument must be a valid Elasticsearch JSON query. It will be sent to Easticsearch as value of the query element; if for example the function is called with the parameter _John_, it would produce the following query body:
|
||||
[source,json]
|
||||
----
|
||||
{
|
||||
"query": {
|
||||
"match": {
|
||||
"name": {
|
||||
"query": "John"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
@@ -135,7 +135,8 @@ public final class RestClients {
|
||||
}
|
||||
|
||||
private static List<String> formattedHosts(List<InetSocketAddress> hosts, boolean useSsl) {
|
||||
return hosts.stream().map(it -> (useSsl ? "https" : "http") + "://" + it).collect(Collectors.toList());
|
||||
return hosts.stream().map(it -> (useSsl ? "https" : "http") + "://" + it.getHostString() + ':' + it.getPort())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+81
-13
@@ -16,7 +16,9 @@
|
||||
package org.springframework.data.elasticsearch.client.reactive;
|
||||
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.handler.ssl.ApplicationProtocolConfig;
|
||||
import io.netty.handler.ssl.ClientAuth;
|
||||
import io.netty.handler.ssl.IdentityCipherSuiteFilter;
|
||||
import io.netty.handler.ssl.JdkSslContext;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
import io.netty.handler.timeout.WriteTimeoutHandler;
|
||||
@@ -45,6 +47,7 @@ import java.util.function.Function;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchStatusException;
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
|
||||
@@ -94,7 +97,6 @@ import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.SearchHits;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.client.ClientLogger;
|
||||
import org.springframework.data.elasticsearch.client.ElasticsearchHost;
|
||||
@@ -113,7 +115,6 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.reactive.function.BodyExtractors;
|
||||
import org.springframework.web.reactive.function.client.ClientRequest;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
@@ -199,7 +200,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
}
|
||||
|
||||
if (!soTimeout.isNegative()) {
|
||||
|
||||
tcpClient = tcpClient.doOnConnected(connection -> connection //
|
||||
.addHandlerLast(new ReadTimeoutHandler(soTimeout.toMillis(), TimeUnit.MILLISECONDS))
|
||||
.addHandlerLast(new WriteTimeoutHandler(soTimeout.toMillis(), TimeUnit.MILLISECONDS)));
|
||||
@@ -210,11 +210,16 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
|
||||
if (clientConfiguration.useSsl()) {
|
||||
|
||||
httpClient = httpClient.secure(sslConfig -> {
|
||||
Optional<SSLContext> sslContext = clientConfiguration.getSslContext();
|
||||
|
||||
Optional<SSLContext> sslContext = clientConfiguration.getSslContext();
|
||||
sslContext.ifPresent(it -> sslConfig.sslContext(new JdkSslContext(it, true, ClientAuth.NONE)));
|
||||
});
|
||||
if (sslContext.isPresent()) {
|
||||
httpClient = httpClient.secure(sslContextSpec -> {
|
||||
sslContextSpec.sslContext(new JdkSslContext(sslContext.get(), true, null, IdentityCipherSuiteFilter.INSTANCE,
|
||||
ApplicationProtocolConfig.DISABLED, ClientAuth.NONE, null, false));
|
||||
});
|
||||
} else {
|
||||
httpClient = httpClient.secure();
|
||||
}
|
||||
|
||||
scheme = "https";
|
||||
}
|
||||
@@ -440,6 +445,7 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#ping(org.springframework.http.HttpHeaders, org.elasticsearch.index.reindex.DeleteByQueryRequest)
|
||||
*/
|
||||
@Override
|
||||
public Mono<BulkByScrollResponse> deleteBy(HttpHeaders headers, DeleteByQueryRequest deleteRequest) {
|
||||
|
||||
return sendRequest(deleteRequest, RequestCreator.deleteByQuery(), BulkByScrollResponse.class, headers) //
|
||||
@@ -673,6 +679,12 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
return handleServerError(request, response);
|
||||
}
|
||||
|
||||
if (response.statusCode().is4xxClientError()) {
|
||||
|
||||
ClientLogger.logRawResponse(logId, response.statusCode());
|
||||
return handleClientError(logId, request, response, responseType);
|
||||
}
|
||||
|
||||
return response.body(BodyExtractors.toMono(byte[].class)) //
|
||||
.map(it -> new String(it, StandardCharsets.UTF_8)) //
|
||||
.doOnNext(it -> ClientLogger.logResponse(logId, response.statusCode(), it)) //
|
||||
@@ -709,13 +721,68 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, content);
|
||||
}
|
||||
|
||||
private static <T> Publisher<? extends T> handleServerError(Request request, ClientResponse response) {
|
||||
private <T> Publisher<? extends T> handleServerError(Request request, ClientResponse response) {
|
||||
|
||||
return Mono.error(
|
||||
new HttpServerErrorException(response.statusCode(), String.format("%s request to %s returned error code %s.",
|
||||
request.getMethod(), request.getEndpoint(), response.statusCode().value())));
|
||||
RestStatus status = RestStatus.fromCode(response.statusCode().value());
|
||||
|
||||
return Mono.error(new ElasticsearchStatusException(String.format("%s request to %s returned error code %s.",
|
||||
request.getMethod(), request.getEndpoint(), response.statusCode().value()), status));
|
||||
}
|
||||
|
||||
private <T> Publisher<? extends T> handleClientError(String logId, Request request, ClientResponse response,
|
||||
Class<T> responseType) {
|
||||
|
||||
return response.body(BodyExtractors.toMono(byte[].class)) //
|
||||
.map(bytes -> new String(bytes, StandardCharsets.UTF_8)) //
|
||||
.flatMap(content -> {
|
||||
String mediaType = response.headers().contentType().map(MediaType::toString)
|
||||
.orElse(XContentType.JSON.mediaType());
|
||||
RestStatus status = RestStatus.fromCode(response.statusCode().value());
|
||||
try {
|
||||
ElasticsearchException exception = getElasticsearchException(response, content, mediaType);
|
||||
if (exception != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
buildExceptionMessages(sb, exception);
|
||||
return Mono.error(new ElasticsearchStatusException(sb.toString(), status, exception));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return Mono.error(new ElasticsearchStatusException(content, status));
|
||||
}
|
||||
return Mono.just(content);
|
||||
}).doOnNext(it -> ClientLogger.logResponse(logId, response.statusCode(), it)) //
|
||||
.flatMap(content -> doDecode(response, responseType, content));
|
||||
}
|
||||
|
||||
// region ElasticsearchException helper
|
||||
@Nullable
|
||||
private ElasticsearchException getElasticsearchException(ClientResponse response, String content, String mediaType)
|
||||
throws IOException {
|
||||
|
||||
XContentParser parser = createParser(mediaType, content);
|
||||
// we have a JSON object with an error and a status field
|
||||
XContentParser.Token token = parser.nextToken(); // Skip START_OBJECT
|
||||
|
||||
do {
|
||||
token = parser.nextToken();
|
||||
|
||||
if (parser.currentName().equals("error")) {
|
||||
return ElasticsearchException.failureFromXContent(parser);
|
||||
}
|
||||
} while (token == XContentParser.Token.FIELD_NAME);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void buildExceptionMessages(StringBuilder sb, Throwable t) {
|
||||
|
||||
sb.append(t.getMessage());
|
||||
for (Throwable throwable : t.getSuppressed()) {
|
||||
sb.append(", ");
|
||||
buildExceptionMessages(sb, throwable);
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region internal classes
|
||||
static class RequestCreator {
|
||||
|
||||
static Function<SearchRequest, Request> search() {
|
||||
@@ -769,7 +836,7 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
try {
|
||||
return RequestConverters.deleteByQuery(request);
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("Could not parse request", e);
|
||||
throw new org.springframework.data.elasticsearch.ElasticsearchException("Could not parse request", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -781,7 +848,7 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
try {
|
||||
return RequestConverters.bulk(request);
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("Could not parse request", e);
|
||||
throw new org.springframework.data.elasticsearch.ElasticsearchException("Could not parse request", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -885,4 +952,5 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
||||
+2
@@ -15,6 +15,8 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class AbstractElasticsearchTemplate {
|
||||
|
||||
static final Integer INDEX_MAX_RESULT_WINDOW = 10_000;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractElasticsearchTemplate.class);
|
||||
|
||||
protected ElasticsearchConverter elasticsearchConverter;
|
||||
|
||||
+31
-14
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import static org.elasticsearch.index.query.Operator.AND;
|
||||
import static org.elasticsearch.index.query.Operator.*;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.springframework.data.elasticsearch.core.query.Criteria.*;
|
||||
|
||||
@@ -25,7 +25,9 @@ import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.apache.lucene.queryparser.flexible.core.util.StringUtils;
|
||||
import org.elasticsearch.index.query.*;
|
||||
import org.apache.lucene.queryparser.flexible.standard.QueryParserUtil;
|
||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -39,7 +41,6 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
class CriteriaQueryProcessor {
|
||||
|
||||
|
||||
QueryBuilder createQueryFromCriteria(Criteria criteria) {
|
||||
if (criteria == null)
|
||||
return null;
|
||||
@@ -104,7 +105,6 @@ class CriteriaQueryProcessor {
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
private QueryBuilder createQueryFragmentForCriteria(Criteria chainedCriteria) {
|
||||
if (chainedCriteria.getQueryCriteriaEntries().isEmpty())
|
||||
return null;
|
||||
@@ -131,8 +131,8 @@ class CriteriaQueryProcessor {
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
private QueryBuilder processCriteriaEntry(Criteria.CriteriaEntry entry,/* OperationKey key, Object value,*/ String fieldName) {
|
||||
private QueryBuilder processCriteriaEntry(Criteria.CriteriaEntry entry,
|
||||
/* OperationKey key, Object value,*/ String fieldName) {
|
||||
Object value = entry.getValue();
|
||||
if (value == null) {
|
||||
return null;
|
||||
@@ -180,17 +180,15 @@ class CriteriaQueryProcessor {
|
||||
query = fuzzyQuery(fieldName, searchText);
|
||||
break;
|
||||
case IN:
|
||||
query = boolQuery();
|
||||
collection = (Iterable<Object>) value;
|
||||
for (Object item : collection) {
|
||||
((BoolQueryBuilder) query).should(queryStringQuery(item.toString()).field(fieldName));
|
||||
if (value instanceof Iterable) {
|
||||
Iterable<?> iterable = (Iterable<?>) value;
|
||||
query = queryStringQuery(orQueryString(iterable)).field(fieldName);
|
||||
}
|
||||
break;
|
||||
case NOT_IN:
|
||||
query = boolQuery();
|
||||
collection = (Iterable<Object>) value;
|
||||
for (Object item : collection) {
|
||||
((BoolQueryBuilder) query).mustNot(queryStringQuery(item.toString()).field(fieldName));
|
||||
if (value instanceof Iterable) {
|
||||
Iterable<?> iterable = (Iterable<?>) value;
|
||||
query = queryStringQuery("NOT(" + orQueryString(iterable) + ')').field(fieldName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -203,4 +201,23 @@ class CriteriaQueryProcessor {
|
||||
}
|
||||
query.boost(boost);
|
||||
}
|
||||
|
||||
private static String orQueryString(Iterable<?> iterable) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (Object item : iterable) {
|
||||
|
||||
if (item != null) {
|
||||
|
||||
if (sb.length() > 0) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append('"');
|
||||
sb.append(QueryParserUtil.escape(item.toString()));
|
||||
sb.append('"');
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
+30
-14
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -52,6 +50,8 @@ import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
|
||||
/**
|
||||
* Elasticsearch specific {@link EntityReader} & {@link EntityWriter} implementation based on domain type
|
||||
@@ -241,27 +241,31 @@ public class ElasticsearchEntityMapper implements
|
||||
Map<String, Object> target = new LinkedHashMap<>();
|
||||
for (Entry<String, Object> entry : source.entrySet()) {
|
||||
|
||||
if (isSimpleType(entry.getValue())) {
|
||||
target.put(entry.getKey(),
|
||||
readSimpleValue(entry.getValue(), targetType.isMap() ? targetType.getComponentType() : targetType));
|
||||
String entryKey = entry.getKey();
|
||||
Object entryValue = entry.getValue();
|
||||
|
||||
if (entryValue == null) {
|
||||
target.put(entryKey, null);
|
||||
} else if (isSimpleType(entryValue)) {
|
||||
target.put(entryKey,
|
||||
readSimpleValue(entryValue, targetType.isMap() ? targetType.getComponentType() : targetType));
|
||||
} else {
|
||||
|
||||
ElasticsearchPersistentEntity<?> targetEntity = computeGenericValueTypeForRead(property, entry.getValue());
|
||||
ElasticsearchPersistentEntity<?> targetEntity = computeGenericValueTypeForRead(property, entryValue);
|
||||
|
||||
if (targetEntity.getTypeInformation().isMap()) {
|
||||
|
||||
Map<String, Object> valueMap = (Map) entry.getValue();
|
||||
Map<String, Object> valueMap = (Map) entryValue;
|
||||
if (typeMapper.containsTypeInformation(valueMap)) {
|
||||
target.put(entry.getKey(), readEntity(targetEntity, (Map) entry.getValue()));
|
||||
target.put(entryKey, readEntity(targetEntity, (Map) entryValue));
|
||||
} else {
|
||||
target.put(entry.getKey(), readValue(valueMap, property, targetEntity.getTypeInformation()));
|
||||
target.put(entryKey, readValue(valueMap, property, targetEntity.getTypeInformation()));
|
||||
}
|
||||
|
||||
} else if (targetEntity.getTypeInformation().isCollectionLike()) {
|
||||
target.put(entry.getKey(),
|
||||
readValue(entry.getValue(), property, targetEntity.getTypeInformation().getActualType()));
|
||||
target.put(entryKey, readValue(entryValue, property, targetEntity.getTypeInformation().getActualType()));
|
||||
} else {
|
||||
target.put(entry.getKey(), readEntity(targetEntity, (Map) entry.getValue()));
|
||||
target.put(entryKey, readEntity(targetEntity, (Map) entryValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,13 +285,18 @@ public class ElasticsearchEntityMapper implements
|
||||
|
||||
for (Object value : source) {
|
||||
|
||||
if (isSimpleType(value)) {
|
||||
if (value == null) {
|
||||
target.add(null);
|
||||
} else if (isSimpleType(value)) {
|
||||
target.add(
|
||||
readSimpleValue(value, targetType.getComponentType() != null ? targetType.getComponentType() : targetType));
|
||||
} else {
|
||||
|
||||
if (value instanceof List) {
|
||||
target.add(readValue(value, property, property.getTypeInformation().getActualType()));
|
||||
} else if (value instanceof Map) {
|
||||
target
|
||||
.add(readMapValue((Map<String, Object>) value, property, property.getTypeInformation().getActualType()));
|
||||
} else {
|
||||
target.add(readEntity(computeGenericValueTypeForRead(property, value), (Map) value));
|
||||
}
|
||||
@@ -493,7 +502,14 @@ public class ElasticsearchEntityMapper implements
|
||||
|
||||
if (!typeHint.getActualType().getType().equals(Object.class)
|
||||
&& isSimpleType(typeHint.getMapValueType().getType())) {
|
||||
mapSource.forEach(it -> target.put(it.getKey(), getWriteSimpleValue(it.getValue())));
|
||||
mapSource.forEach(it -> {
|
||||
|
||||
if (it.getValue() == null) {
|
||||
target.put(it.getKey(), null);
|
||||
} else {
|
||||
target.put(it.getKey(), getWriteSimpleValue(it.getValue()));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
mapSource.forEach(it -> {
|
||||
|
||||
+20
-4
@@ -143,6 +143,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Mathias Teier
|
||||
* @author Gyula Attila Csorogi
|
||||
* @author Alexander Shabunevich
|
||||
*/
|
||||
public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate
|
||||
implements ElasticsearchOperations, EsClient<RestHighLevelClient>, ApplicationContextAware {
|
||||
@@ -208,11 +209,17 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate
|
||||
aliasAction.filter(query.getFilterBuilder());
|
||||
} else if (query.getFilter() != null) {
|
||||
aliasAction.filter(query.getFilter());
|
||||
} else if (hasText(query.getRouting())) {
|
||||
}
|
||||
|
||||
if (hasText(query.getRouting())) {
|
||||
aliasAction.routing(query.getRouting());
|
||||
} else if (hasText(query.getSearchRouting())) {
|
||||
}
|
||||
|
||||
if (hasText(query.getSearchRouting())) {
|
||||
aliasAction.searchRouting(query.getSearchRouting());
|
||||
} else if (hasText(query.getIndexRouting())) {
|
||||
}
|
||||
|
||||
if (hasText(query.getIndexRouting())) {
|
||||
aliasAction.indexRouting(query.getIndexRouting());
|
||||
}
|
||||
|
||||
@@ -1338,8 +1345,17 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate
|
||||
}
|
||||
|
||||
if (query.getPageable().isPaged()) {
|
||||
startRecord = query.getPageable().getPageNumber() * query.getPageable().getPageSize();
|
||||
long offset = query.getPageable().getOffset();
|
||||
|
||||
if (offset > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException(String.format("Offset must not be more than %d", Integer.MAX_VALUE));
|
||||
}
|
||||
|
||||
startRecord = (int) offset;
|
||||
sourceBuilder.size(query.getPageable().getPageSize());
|
||||
} else {
|
||||
startRecord = 0;
|
||||
sourceBuilder.size(INDEX_MAX_RESULT_WINDOW);
|
||||
}
|
||||
sourceBuilder.from(startRecord);
|
||||
|
||||
|
||||
+21
-4
@@ -123,6 +123,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Martin Choraine
|
||||
* @author Farid Azaza
|
||||
* @author Gyula Attila Csorogi
|
||||
* @author Alexander Shabunevich
|
||||
*/
|
||||
public class ElasticsearchTemplate extends AbstractElasticsearchTemplate
|
||||
implements ElasticsearchOperations, EsClient<Client>, ApplicationContextAware {
|
||||
@@ -189,13 +190,20 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate
|
||||
aliasAction.filter(query.getFilterBuilder());
|
||||
} else if (query.getFilter() != null) {
|
||||
aliasAction.filter(query.getFilter());
|
||||
} else if (!StringUtils.isEmpty(query.getRouting())) {
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(query.getRouting())) {
|
||||
aliasAction.routing(query.getRouting());
|
||||
} else if (!StringUtils.isEmpty(query.getSearchRouting())) {
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(query.getSearchRouting())) {
|
||||
aliasAction.searchRouting(query.getSearchRouting());
|
||||
} else if (!StringUtils.isEmpty(query.getIndexRouting())) {
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(query.getIndexRouting())) {
|
||||
aliasAction.indexRouting(query.getIndexRouting());
|
||||
}
|
||||
|
||||
return client.admin().indices().prepareAliases().addAliasAction(aliasAction).execute().actionGet().isAcknowledged();
|
||||
}
|
||||
|
||||
@@ -1115,8 +1123,17 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate
|
||||
}
|
||||
|
||||
if (query.getPageable().isPaged()) {
|
||||
startRecord = query.getPageable().getPageNumber() * query.getPageable().getPageSize();
|
||||
long offset = query.getPageable().getOffset();
|
||||
|
||||
if (offset > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException(String.format("Offset must not be more than %d", Integer.MAX_VALUE));
|
||||
}
|
||||
|
||||
startRecord = (int) offset;
|
||||
searchRequestBuilder.setSize(query.getPageable().getPageSize());
|
||||
} else {
|
||||
startRecord = 0;
|
||||
searchRequestBuilder.setSize(INDEX_MAX_RESULT_WINDOW);
|
||||
}
|
||||
searchRequestBuilder.setFrom(startRecord);
|
||||
|
||||
|
||||
+2
@@ -367,6 +367,8 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
||||
|
||||
request.source(searchSourceBuilder);
|
||||
} else {
|
||||
searchSourceBuilder.from(0);
|
||||
searchSourceBuilder.size(AbstractElasticsearchTemplate.INDEX_MAX_RESULT_WINDOW);
|
||||
request.source(searchSourceBuilder);
|
||||
}
|
||||
return request;
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
public interface ScrolledPage<T> extends Page<T> {
|
||||
|
||||
String getScrollId();
|
||||
|
||||
String getScrollId();
|
||||
}
|
||||
|
||||
@@ -21,11 +21,13 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utility to support streaming queries.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Sascha Woo
|
||||
* @since 3.2
|
||||
*/
|
||||
abstract class StreamQueries {
|
||||
@@ -33,72 +35,71 @@ abstract class StreamQueries {
|
||||
/**
|
||||
* Stream query results using {@link ScrolledPage}.
|
||||
*
|
||||
* @param page the initial page.
|
||||
* @param continueFunction continuation function accepting the current scrollId.
|
||||
* @param clearScroll cleanup function accepting the current scrollId.
|
||||
* @param page the initial scrolled page.
|
||||
* @param continueScrollFunction function to continue scrolling applies to the current scrollId.
|
||||
* @param clearScrollConsumer consumer to clear the scroll context by accepting the current scrollId.
|
||||
* @param <T>
|
||||
* @return the {@link CloseableIterator}.
|
||||
*/
|
||||
static <T> CloseableIterator<T> streamResults(ScrolledPage<T> page,
|
||||
Function<String, ScrolledPage<T>> continueFunction, Consumer<String> clearScroll) {
|
||||
Function<String, ScrolledPage<T>> continueScrollFunction, Consumer<String> clearScrollConsumer) {
|
||||
|
||||
Assert.notNull(page, "page must not be null.");
|
||||
Assert.notNull(page.getScrollId(), "scrollId must not be null.");
|
||||
Assert.notNull(continueScrollFunction, "continueScrollFunction must not be null.");
|
||||
Assert.notNull(clearScrollConsumer, "clearScrollConsumer must not be null.");
|
||||
|
||||
return new CloseableIterator<T>() {
|
||||
|
||||
/** As we couldn't retrieve single result with scroll, store current hits. */
|
||||
private volatile Iterator<T> currentHits = page.iterator();
|
||||
|
||||
/** The scroll id. */
|
||||
// As we couldn't retrieve single result with scroll, store current hits.
|
||||
private volatile Iterator<T> scrollHits = page.iterator();
|
||||
private volatile String scrollId = page.getScrollId();
|
||||
|
||||
/** If stream is finished (ie: cluster returns no results. */
|
||||
private volatile boolean finished = !currentHits.hasNext();
|
||||
private volatile boolean continueScroll = scrollHits.hasNext();
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
try {
|
||||
// Clear scroll on cluster only in case of error (cause elasticsearch auto clear scroll when it's done)
|
||||
if (!finished && scrollId != null && currentHits != null && currentHits.hasNext()) {
|
||||
clearScroll.accept(scrollId);
|
||||
}
|
||||
clearScrollConsumer.accept(scrollId);
|
||||
} finally {
|
||||
currentHits = null;
|
||||
scrollHits = null;
|
||||
scrollId = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
// Test if stream is finished
|
||||
if (finished) {
|
||||
|
||||
if (!continueScroll) {
|
||||
return false;
|
||||
}
|
||||
// Test if it remains hits
|
||||
if (currentHits == null || !currentHits.hasNext()) {
|
||||
// Do a new request
|
||||
ScrolledPage<T> scroll = continueFunction.apply(scrollId);
|
||||
// Save hits and scroll id
|
||||
currentHits = scroll.iterator();
|
||||
finished = !currentHits.hasNext();
|
||||
scrollId = scroll.getScrollId();
|
||||
|
||||
if (!scrollHits.hasNext()) {
|
||||
ScrolledPage<T> nextPage = continueScrollFunction.apply(scrollId);
|
||||
scrollHits = nextPage.iterator();
|
||||
scrollId = nextPage.getScrollId();
|
||||
continueScroll = scrollHits.hasNext();
|
||||
}
|
||||
return currentHits.hasNext();
|
||||
|
||||
return scrollHits.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (hasNext()) {
|
||||
return currentHits.next();
|
||||
return scrollHits.next();
|
||||
}
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("remove");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// utility constructor
|
||||
private StreamQueries() {}
|
||||
private StreamQueries() {
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -19,6 +19,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.MultiField;
|
||||
import org.springframework.data.elasticsearch.annotations.Parent;
|
||||
import org.springframework.data.elasticsearch.annotations.Score;
|
||||
import org.springframework.data.mapping.Association;
|
||||
@@ -77,13 +78,15 @@ public class SimpleElasticsearchPersistentProperty extends
|
||||
@Nullable
|
||||
private String getAnnotatedFieldName() {
|
||||
|
||||
if (isAnnotationPresent(Field.class)) {
|
||||
String name = null;
|
||||
|
||||
String name = findAnnotation(Field.class).name();
|
||||
return StringUtils.hasText(name) ? name : null;
|
||||
if (isAnnotationPresent(MultiField.class)) {
|
||||
name = findAnnotation(MultiField.class).mainField().name();
|
||||
} else if (isAnnotationPresent(Field.class)) {
|
||||
name = findAnnotation(Field.class).name();
|
||||
}
|
||||
|
||||
return null;
|
||||
return StringUtils.hasText(name) ? name : null;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -15,10 +15,13 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoBox;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
@@ -26,6 +29,8 @@ import org.springframework.data.geo.Box;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Criteria is the central class when constructing queries. It follows more or less a fluent API style, which allows to
|
||||
@@ -39,13 +44,9 @@ public class Criteria {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Criteria{" +
|
||||
"field=" + field.getName() +
|
||||
", boost=" + boost +
|
||||
", negating=" + negating +
|
||||
", queryCriteria=" + ObjectUtils.nullSafeToString(queryCriteria) +
|
||||
", filterCriteria=" + ObjectUtils.nullSafeToString(filterCriteria) +
|
||||
'}';
|
||||
return "Criteria{" + "field=" + field.getName() + ", boost=" + boost + ", negating=" + negating + ", queryCriteria="
|
||||
+ ObjectUtils.nullSafeToString(queryCriteria) + ", filterCriteria="
|
||||
+ ObjectUtils.nullSafeToString(filterCriteria) + '}';
|
||||
}
|
||||
|
||||
public static final String WILDCARD = "*";
|
||||
@@ -64,8 +65,7 @@ public class Criteria {
|
||||
|
||||
private Set<CriteriaEntry> filterCriteria = new LinkedHashSet<>();
|
||||
|
||||
public Criteria() {
|
||||
}
|
||||
public Criteria() {}
|
||||
|
||||
/**
|
||||
* Creates a new Criteria with provided field name
|
||||
@@ -305,7 +305,7 @@ public class Criteria {
|
||||
throw new InvalidDataAccessApiUsageException("Range [* TO *] is not allowed");
|
||||
}
|
||||
|
||||
queryCriteria.add(new CriteriaEntry(OperationKey.BETWEEN, new Object[]{lowerBound, upperBound}));
|
||||
queryCriteria.add(new CriteriaEntry(OperationKey.BETWEEN, new Object[] { lowerBound, upperBound }));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -376,11 +376,6 @@ public class Criteria {
|
||||
}
|
||||
|
||||
private List<Object> toCollection(Object... values) {
|
||||
if (values.length == 0 || (values.length > 1 && values[1] instanceof Collection)) {
|
||||
throw new InvalidDataAccessApiUsageException("At least one element "
|
||||
+ (values.length > 0 ? ("of argument of type " + values[1].getClass().getName()) : "")
|
||||
+ " has to be present.");
|
||||
}
|
||||
return Arrays.asList(values);
|
||||
}
|
||||
|
||||
@@ -398,15 +393,14 @@ public class Criteria {
|
||||
* Creates new CriteriaEntry for {@code location WITHIN distance}
|
||||
*
|
||||
* @param location {@link org.springframework.data.elasticsearch.core.geo.GeoPoint} center coordinates
|
||||
* @param distance {@link String} radius as a string (e.g. : '100km').
|
||||
* Distance unit :
|
||||
* either mi/miles or km can be set
|
||||
* @param distance {@link String} radius as a string (e.g. : '100km'). Distance unit : either mi/miles or km can be
|
||||
* set
|
||||
* @return Criteria the chaind criteria with the new 'within' criteria included.
|
||||
*/
|
||||
public Criteria within(GeoPoint location, String distance) {
|
||||
Assert.notNull(location, "Location value for near criteria must not be null");
|
||||
Assert.notNull(location, "Distance value for near criteria must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.WITHIN, new Object[]{location, distance}));
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.WITHIN, new Object[] { location, distance }));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -414,56 +408,54 @@ public class Criteria {
|
||||
* Creates new CriteriaEntry for {@code location WITHIN distance}
|
||||
*
|
||||
* @param location {@link org.springframework.data.geo.Point} center coordinates
|
||||
* @param distance {@link org.springframework.data.geo.Distance} radius
|
||||
* .
|
||||
* @param distance {@link org.springframework.data.geo.Distance} radius .
|
||||
* @return Criteria the chaind criteria with the new 'within' criteria included.
|
||||
*/
|
||||
public Criteria within(Point location, Distance distance) {
|
||||
Assert.notNull(location, "Location value for near criteria must not be null");
|
||||
Assert.notNull(location, "Distance value for near criteria must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.WITHIN, new Object[]{location, distance}));
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.WITHIN, new Object[] { location, distance }));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new CriteriaEntry for {@code geoLocation WITHIN distance}
|
||||
*
|
||||
* @param geoLocation {@link String} center point
|
||||
* supported formats:
|
||||
* lat on = > "41.2,45.1",
|
||||
* geohash = > "asd9as0d"
|
||||
* @param distance {@link String} radius as a string (e.g. : '100km').
|
||||
* Distance unit :
|
||||
* either mi/miles or km can be set
|
||||
* @param geoLocation {@link String} center point supported formats: lat on = > "41.2,45.1", geohash = > "asd9as0d"
|
||||
* @param distance {@link String} radius as a string (e.g. : '100km'). Distance unit : either mi/miles or km can be
|
||||
* set
|
||||
* @return
|
||||
*/
|
||||
public Criteria within(String geoLocation, String distance) {
|
||||
Assert.isTrue(!StringUtils.isEmpty(geoLocation), "geoLocation value must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.WITHIN, new Object[]{geoLocation, distance}));
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.WITHIN, new Object[] { geoLocation, distance }));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new CriteriaEntry for {@code location GeoBox bounding box}
|
||||
*
|
||||
* @param boundingBox {@link org.springframework.data.elasticsearch.core.geo.GeoBox} bounding box(left top corner + right bottom corner)
|
||||
* @param boundingBox {@link org.springframework.data.elasticsearch.core.geo.GeoBox} bounding box(left top corner +
|
||||
* right bottom corner)
|
||||
* @return Criteria the chaind criteria with the new 'boundingBox' criteria included.
|
||||
*/
|
||||
public Criteria boundedBy(GeoBox boundingBox) {
|
||||
Assert.notNull(boundingBox, "boundingBox value for boundedBy criteria must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{boundingBox}));
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[] { boundingBox }));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new CriteriaEntry for {@code location Box bounding box}
|
||||
*
|
||||
* @param boundingBox {@link org.springframework.data.elasticsearch.core.geo.GeoBox} bounding box(left top corner + right bottom corner)
|
||||
* @param boundingBox {@link org.springframework.data.elasticsearch.core.geo.GeoBox} bounding box(left top corner +
|
||||
* right bottom corner)
|
||||
* @return Criteria the chaind criteria with the new 'boundingBox' criteria included.
|
||||
*/
|
||||
public Criteria boundedBy(Box boundingBox) {
|
||||
Assert.notNull(boundingBox, "boundingBox value for boundedBy criteria must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{boundingBox.getFirst(), boundingBox.getSecond()}));
|
||||
filterCriteria
|
||||
.add(new CriteriaEntry(OperationKey.BBOX, new Object[] { boundingBox.getFirst(), boundingBox.getSecond() }));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -477,7 +469,7 @@ public class Criteria {
|
||||
public Criteria boundedBy(String topLeftGeohash, String bottomRightGeohash) {
|
||||
Assert.isTrue(!StringUtils.isEmpty(topLeftGeohash), "topLeftGeohash must not be empty");
|
||||
Assert.isTrue(!StringUtils.isEmpty(bottomRightGeohash), "bottomRightGeohash must not be empty");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{topLeftGeohash, bottomRightGeohash}));
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[] { topLeftGeohash, bottomRightGeohash }));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -491,14 +483,15 @@ public class Criteria {
|
||||
public Criteria boundedBy(GeoPoint topLeftPoint, GeoPoint bottomRightPoint) {
|
||||
Assert.notNull(topLeftPoint, "topLeftPoint must not be null");
|
||||
Assert.notNull(bottomRightPoint, "bottomRightPoint must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{topLeftPoint, bottomRightPoint}));
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[] { topLeftPoint, bottomRightPoint }));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Criteria boundedBy(Point topLeftPoint, Point bottomRightPoint) {
|
||||
Assert.notNull(topLeftPoint, "topLeftPoint must not be null");
|
||||
Assert.notNull(bottomRightPoint, "bottomRightPoint must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{GeoPoint.fromPoint(topLeftPoint), GeoPoint.fromPoint(bottomRightPoint)}));
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX,
|
||||
new Object[] { GeoPoint.fromPoint(topLeftPoint), GeoPoint.fromPoint(bottomRightPoint) }));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -611,10 +604,7 @@ public class Criteria {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CriteriaEntry{" +
|
||||
"key=" + key +
|
||||
", value=" + value +
|
||||
'}';
|
||||
return "CriteriaEntry{" + "key=" + key + ", value=" + value + '}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -155,7 +155,13 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
||||
|
||||
Assert.notNull(ids, "ids can't be null.");
|
||||
|
||||
SearchQuery query = new NativeSearchQueryBuilder().withIds(stringIdsRepresentation(ids)).build();
|
||||
List<String> stringIds = stringIdsRepresentation(ids);
|
||||
|
||||
if (stringIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
SearchQuery query = new NativeSearchQueryBuilder().withIds(stringIds).build();
|
||||
|
||||
return elasticsearchOperations.multiGet(query, getEntityClass());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,372 @@
|
||||
Spring Data Elasticsearch Changelog
|
||||
===================================
|
||||
|
||||
Changes in version 3.2.11.RELEASE (2020-10-28)
|
||||
----------------------------------------------
|
||||
* DATAES-961 - Upgrade to Elasticsearch 6.8.13.
|
||||
* DATAES-937 - Repository queries with IN filters fail with empty input list.
|
||||
* DATAES-925 - Release 3.2.11 (Moore SR11).
|
||||
|
||||
|
||||
Changes in version 3.1.21.RELEASE (2020-10-28)
|
||||
----------------------------------------------
|
||||
* DATAES-958 - Release 3.1.21 (Lovelace SR21).
|
||||
|
||||
|
||||
Changes in version 4.1.0-RC2 (2020-10-14)
|
||||
-----------------------------------------
|
||||
* DATAES-949 - dependency cleanup.
|
||||
* DATAES-947 - Adopt to API changes in Project Reactor.
|
||||
* DATAES-945 - Compilation error on JDK11+.
|
||||
* DATAES-944 - Simplify logging setup in test environment.
|
||||
* DATAES-943 - Add missing mapping parameters.
|
||||
* DATAES-940 - Update to Elasticsearch 7.9.2.
|
||||
* DATAES-937 - Repository queries with IN filters fail with empty input list.
|
||||
* DATAES-936 - Take id property from the source when deserializing an entity.
|
||||
* DATAES-935 - Setup integration tests separate from unit tests.
|
||||
* DATAES-934 - Add a Query taking method to ElasticsearchRepository.
|
||||
* DATAES-933 - Fix typo in javaDoc.
|
||||
* DATAES-932 - GeoPoint - Point conversion is wrong.
|
||||
* DATAES-930 - Add support for geo_shape type entity properties.
|
||||
* DATAES-929 - Support geo_shape field type field type.
|
||||
* DATAES-927 - Release 4.1 RC2 (2020.0.0).
|
||||
* DATAES-921 - Investigate WebClient.retrieve() instead of using WebClient.exchange().
|
||||
|
||||
|
||||
Changes in version 4.1.0-RC1 (2020-09-16)
|
||||
-----------------------------------------
|
||||
* DATAES-924 - Conversion of properties of collections of Temporal values fails.
|
||||
* DATAES-923 - Upgrade to Elasticsearch 7.9.1.
|
||||
* DATAES-922 - Move off Sink.emitXXX methods.
|
||||
* DATAES-920 - Add parameter to @Field annotation to store null values.
|
||||
* DATAES-919 - Fix error messages in test output.
|
||||
* DATAES-914 - Use Testcontainers.
|
||||
* DATAES-913 - Minor optimization on collection-returning derived queries.
|
||||
* DATAES-912 - Derived Query with "In" Keyword does not work on Text field.
|
||||
* DATAES-911 - Add documentation for automatic index creation.
|
||||
* DATAES-910 - Upgrade to Elasticsearch 7.9.0.
|
||||
* DATAES-909 - Add singular update() methods to ReactiveDocumentOperations.
|
||||
* DATAES-908 - Fill version on an indexed entity.
|
||||
* DATAES-907 - Track Total Hits not working when set to false.
|
||||
* DATAES-904 - Release 4.1 RC1 (2020.0.0).
|
||||
* DATAES-902 - Update to Elasticsearch 7.8.1.
|
||||
* DATAES-898 - Add join-type relevant parts to reactive calls.
|
||||
* DATAES-895 - Criteria.OperationKey.NEAR is not used anywhere.
|
||||
* DATAES-854 - Add support for rank_feature datatype.
|
||||
* DATAES-706 - CriteriaQueryProcessor must handle nested Criteria definitions.
|
||||
|
||||
|
||||
Changes in version 4.0.4.RELEASE (2020-09-16)
|
||||
---------------------------------------------
|
||||
* DATAES-924 - Conversion of properties of collections of Temporal values fails.
|
||||
* DATAES-912 - Derived Query with "In" Keyword does not work on Text field.
|
||||
* DATAES-905 - Release 4.0.4 (Neumann SR4).
|
||||
|
||||
|
||||
Changes in version 3.2.10.RELEASE (2020-09-16)
|
||||
----------------------------------------------
|
||||
* DATAES-903 - Update to Elasticsearch 6.8.12.
|
||||
* DATAES-892 - Fix ElasticsearchEntityMapper recursive descent when reading Map objects.
|
||||
* DATAES-888 - Release 3.2.10 (Moore SR10).
|
||||
|
||||
|
||||
Changes in version 3.1.20.RELEASE (2020-09-16)
|
||||
----------------------------------------------
|
||||
* DATAES-887 - Release 3.1.20 (Lovelace SR20).
|
||||
|
||||
|
||||
Changes in version 4.0.3.RELEASE (2020-08-12)
|
||||
---------------------------------------------
|
||||
* DATAES-897 - Add documentation for Highlight annotation.
|
||||
* DATAES-896 - Use mainField property of @MultiField annotation instead of additional @Field annotation.
|
||||
* DATAES-891 - Returning a Stream from a Query annotated repository method crashes.
|
||||
* DATAES-890 - Release 4.0.3 (Neumann SR3).
|
||||
|
||||
|
||||
Changes in version 4.1.0-M2 (2020-08-12)
|
||||
----------------------------------------
|
||||
* DATAES-901 - Operations deleting an entity should use a routing deducted from the entity.
|
||||
* DATAES-899 - Add documentation for join-type.
|
||||
* DATAES-897 - Add documentation for Highlight annotation.
|
||||
* DATAES-896 - Use mainField property of @MultiField annotation instead of additional @Field annotation.
|
||||
* DATAES-894 - Adapt to changes in Reactor.
|
||||
* DATAES-893 - Adopt to changed module layout of Reactor Netty.
|
||||
* DATAES-891 - Returning a Stream from a Query annotated repository method crashes.
|
||||
* DATAES-886 - Complete reactive auditing.
|
||||
* DATAES-883 - Fix log level on resource load error.
|
||||
* DATAES-878 - Wrong value for TermVector(woth_positions_offsets).
|
||||
* DATAES-877 - Update test logging dependency.
|
||||
* DATAES-876 - Add seqno and primary term to entity on initial save.
|
||||
* DATAES-875 - MappingElasticsearchConverter.updateQuery not called at all places.
|
||||
* DATAES-874 - Deprecate parent-id related methods and fields.
|
||||
* DATAES-872 - Release 4.1 M2 (2020.0.0).
|
||||
* DATAES-869 - Update to Elasticsearch 7.8.
|
||||
* DATAES-864 - Rework alias management.
|
||||
* DATAES-842 - Documentation fixes.
|
||||
* DATAES-612 - Add support for index templates.
|
||||
* DATAES-433 - Replace parent-child mappings to join field.
|
||||
* DATAES-321 - Support time base rolling indices.
|
||||
* DATAES-244 - Support alias renaming.
|
||||
* DATAES-233 - Support for rolling index strategy.
|
||||
* DATAES-207 - Allow fetching indices by alias.
|
||||
* DATAES-192 - Define alias for document.
|
||||
* DATAES-150 - mapping are not created when entity is saved in new dynamic name index (spel).
|
||||
|
||||
|
||||
Changes in version 4.0.2.RELEASE (2020-07-22)
|
||||
---------------------------------------------
|
||||
* DATAES-883 - Fix log level on resource load error.
|
||||
* DATAES-878 - Wrong value for TermVector(woth_positions_offsets).
|
||||
* DATAES-865 - Fix MappingElasticsearchConverter writing an Object property containing a Map.
|
||||
* DATAES-863 - Improve server error response handling.
|
||||
* DATAES-862 - Release 4.0.2 (Neumann SR2).
|
||||
|
||||
|
||||
Changes in version 3.2.9.RELEASE (2020-07-22)
|
||||
---------------------------------------------
|
||||
* DATAES-861 - Release 3.2.9 (Moore SR9).
|
||||
|
||||
|
||||
Changes in version 3.1.19.RELEASE (2020-07-22)
|
||||
----------------------------------------------
|
||||
* DATAES-860 - Release 3.1.19 (Lovelace SR19).
|
||||
|
||||
|
||||
Changes in version 4.1.0-M1 (2020-06-25)
|
||||
----------------------------------------
|
||||
* DATAES-870 - Workaround for reactor-netty error.
|
||||
* DATAES-868 - Upgrade to Netty 4.1.50.Final.
|
||||
* DATAES-867 - Adopt to changes in Reactor Netty 1.0.
|
||||
* DATAES-866 - Implement suggest search in reactive client.
|
||||
* DATAES-865 - Fix MappingElasticsearchConverter writing an Object property containing a Map.
|
||||
* DATAES-863 - Improve server error response handling.
|
||||
* DATAES-859 - Don't use randomNumeric() in tests.
|
||||
* DATAES-858 - Use standard Spring code of conduct.
|
||||
* DATAES-857 - Registered simple types are not read from list.
|
||||
* DATAES-853 - Cleanup tests that do not delete test indices.
|
||||
* DATAES-852 - Upgrade to Elasticsearch 7.7.1.
|
||||
* DATAES-850 - Add warning and documentation for missing TemporalAccessor configuration.
|
||||
* DATAES-848 - Add the name of the index to SearchHit.
|
||||
* DATAES-847 - Add missing DateFormat values.
|
||||
* DATAES-845 - MappingElasticsearchConverter crashes when writing lists containing null values.
|
||||
* DATAES-844 - Improve TOC formatting for migration guides.
|
||||
* DATAES-841 - Remove deprecated type mappings code.
|
||||
* DATAES-840 - Consolidate index name SpEL resolution.
|
||||
* DATAES-839 - ReactiveElasticsearchTemplate should use RequestFactory.
|
||||
* DATAES-838 - Update to Elasticsearch 7.7.0.
|
||||
* DATAES-836 - Fix typo in Javadocs.
|
||||
* DATAES-835 - Fix code sample in documentation for scroll API.
|
||||
* DATAES-832 - findAllById repository method returns iterable with null elements for not found ids.
|
||||
* DATAES-831 - SearchOperations.searchForStream does not use requested maxResults.
|
||||
* DATAES-829 - Deprecate AbstractElasticsearchRepository and cleanup SimpleElasticsearchRepository.
|
||||
* DATAES-828 - Fields of type date need to have a format defined.
|
||||
* DATAES-827 - Repositories should not try to create an index when it already exists.
|
||||
* DATAES-826 - Add method to IndexOperations to write an index mapping from a entity class.
|
||||
* DATAES-825 - Update readme to use latest spring.io docs.
|
||||
* DATAES-824 - Release 4.1 M1 (2020.0.0).
|
||||
* DATAES-678 - Introduce ReactiveIndexOperations.
|
||||
* DATAES-263 - Inner Hits support.
|
||||
|
||||
|
||||
Changes in version 4.0.1.RELEASE (2020-06-10)
|
||||
---------------------------------------------
|
||||
* DATAES-857 - Registered simple types are not read from list.
|
||||
* DATAES-850 - Add warning and documentation for missing TemporalAccessor configuration.
|
||||
* DATAES-845 - MappingElasticsearchConverter crashes when writing lists containing null values.
|
||||
* DATAES-844 - Improve TOC formatting for migration guides.
|
||||
* DATAES-839 - ReactiveElasticsearchTemplate should use RequestFactory.
|
||||
* DATAES-835 - Fix code sample in documentation for scroll API.
|
||||
* DATAES-832 - findAllById repository method returns iterable with null elements for not found ids.
|
||||
* DATAES-831 - SearchOperations.searchForStream does not use requested maxResults.
|
||||
* DATAES-828 - Fields of type date need to have a format defined.
|
||||
* DATAES-827 - Repositories should not try to create an index when it already exists.
|
||||
* DATAES-823 - Release 4.0.1 (Neumann SR1).
|
||||
|
||||
|
||||
Changes in version 3.2.8.RELEASE (2020-06-10)
|
||||
---------------------------------------------
|
||||
* DATAES-851 - Upgrade to Elasticsearch 6.8.10.
|
||||
* DATAES-837 - Update to Elasticsearch 6.8.9.
|
||||
* DATAES-821 - Fix code for adding an alias.
|
||||
* DATAES-811 - Remove Travis CI.
|
||||
* DATAES-807 - Release 3.2.8 (Moore SR8).
|
||||
* DATAES-776 - Adapt RestClients class to change in InetSocketAddress class in JDK14.
|
||||
* DATAES-767 - Fix ReactiveElasticsearch handling of 4xx HTTP responses.
|
||||
|
||||
|
||||
Changes in version 3.1.18.RELEASE (2020-06-10)
|
||||
----------------------------------------------
|
||||
* DATAES-811 - Remove Travis CI.
|
||||
* DATAES-806 - Release 3.1.18 (Lovelace SR18).
|
||||
|
||||
|
||||
Changes in version 4.0.0.RC2 (2020-04-28)
|
||||
-----------------------------------------
|
||||
* DATAES-803 - Move count request setup from reactive template to reactive client.
|
||||
* DATAES-802 - Update documentation for using scroll API with repository methods.
|
||||
* DATAES-801 - Implement callback to enable adding custom headers in the REST HTTP request.
|
||||
* DATAES-800 - De-Lombok production code.
|
||||
* DATAES-797 - Fix MappingElasticsearchConverter recursive descent when reading Map objetcsa.
|
||||
* DATAES-795 - Fix MappingElasticsearchConverter conversion from Document into Map<String, Object>.
|
||||
* DATAES-794 - MappingBuilder must not write empty mapping properties.
|
||||
* DATAES-792 - Add java.util.Date to the supported types for Field annonation date times.
|
||||
* DATAES-791 - DocumentOperations.multiGet() implementations must return null values for not found entities.
|
||||
* DATAES-790 - Deprecate noRefresh repository method.
|
||||
* DATAES-789 - Make ElasticsearchRestTemplate.ClientCallback public.
|
||||
* DATAES-788 - Add missing path mapping to completion context.
|
||||
* DATAES-787 - Use JDK 14 for Java.NEXT CI testing.
|
||||
* DATAES-786 - Move the creation of SearchHit(s) from ElasticsearchConverter closer to ElasticsearchTemplate.
|
||||
* DATAES-785 - Various entity callbacks implementation improvements.
|
||||
* DATAES-784 - MappingBuilder should use @Field annotation with custom value objects.
|
||||
* DATAES-782 - Make underlying TransportClient accessible.
|
||||
* DATAES-781 - Upgrade to Elasticsearch 7.6.2.
|
||||
* DATAES-778 - Fix SSL setup in the reactive client.
|
||||
* DATAES-777 - SearchHitsSupport must preserve pageable when unwrapping to AggregatedPage.
|
||||
* DATAES-776 - Adapt RestClients class to change in InetSocketAddress class in JDK14.
|
||||
* DATAES-775 - Fix test runner setup.
|
||||
* DATAES-774 - Release 4.0 RC2 (Neumann).
|
||||
* DATAES-773 - Add search-as-you-type field support to index mappings.
|
||||
* DATAES-772 - Add after-convert entity callbacks support.
|
||||
* DATAES-567 - Unable to read aggregations via Reactive*Operations.
|
||||
|
||||
|
||||
Changes in version 3.2.7.RELEASE (2020-04-28)
|
||||
---------------------------------------------
|
||||
* DATAES-780 - Upgrade 3.2.x to Elasticsearch 6.8.8.
|
||||
* DATAES-778 - Fix SSL setup in the reactive client.
|
||||
* DATAES-770 - Release 3.2.7 (Moore SR7).
|
||||
|
||||
|
||||
Changes in version 3.1.17.RELEASE (2020-04-28)
|
||||
----------------------------------------------
|
||||
* DATAES-793 - Upgrade to Elasticsearch 6.2.4.
|
||||
* DATAES-755 - Release 3.1.17 (Lovelace SR17).
|
||||
|
||||
|
||||
Changes in version 4.0.0.RC1 (2020-03-31)
|
||||
-----------------------------------------
|
||||
* DATAES-771 - Add after-save entity callbacks support.
|
||||
* DATAES-768 - Add missing query parameters for an UpdateQuery.
|
||||
* DATAES-766 - Replace CloseableIterator with SearchHitsIterator in stream operations.
|
||||
* DATAES-765 - Pageable.unpaged() is not used to build a query returning all documents.
|
||||
* DATAES-763 - Allow map properties in entity with null values.
|
||||
* DATAES-762 - Release 4.0 RC1 (Neumann).
|
||||
* DATAES-751 - Introduce ClientCallbackfor the rest client.
|
||||
* DATAES-653 - Make it easier to use a custom request converter when extending DefaultReactiveElasticsearchClient.
|
||||
* DATAES-435 - Report version mismatch if used with older ElasticSearch version.
|
||||
* DATAES-382 - Add Exception translation for Elasticsearch errors.
|
||||
* DATAES-68 - Add support for auditing annotations.
|
||||
|
||||
|
||||
Changes in version 3.2.6.RELEASE (2020-03-25)
|
||||
---------------------------------------------
|
||||
* DATAES-769 - Upgrade to Elasticsearch 6.8.7.
|
||||
* DATAES-765 - Pageable.unpaged() is not used to build a query returning all documents.
|
||||
* DATAES-764 - StreamQueries#streamResults does not clear scroll context when finished.
|
||||
* DATAES-763 - Allow map properties in entity with null values.
|
||||
* DATAES-758 - fix documentation for @Query annotation.
|
||||
* DATAES-756 - Release 3.2.6 (Moore SR6).
|
||||
|
||||
|
||||
Changes in version 4.0.0.M4 (2020-03-11)
|
||||
----------------------------------------
|
||||
* DATAES-759 - Update to Elasticsearch 7.6.1.
|
||||
* DATAES-758 - fix documentation for @Query annotation.
|
||||
* DATAES-754 - Completion field deserialization is failing due to class cast error.
|
||||
* DATAES-753 - Reactive Elasticsearch repository: Bulk update fails on empty entity list.
|
||||
* DATAES-749 - Introduce SearchPage as return type for repository methods.
|
||||
* DATAES-747 - ElasticsearchConfigurationSupport does not set customConversions into the MappingElasticsearchConverter.
|
||||
* DATAES-746 - Add store converters to convert binary data to base64 encoded strings.
|
||||
* DATAES-745 - Consolidate Operations API.
|
||||
* DATAES-744 - Release 4.0 M4 (Neumann).
|
||||
* DATAES-741 - Tests fail due to Elasticsearch cluster 'blocks' on nearly-full file-systems.
|
||||
* DATAES-282 - Remove all low-level reflection based field inspection from MappingBuilder in favor of PersistentProperty inspections.
|
||||
|
||||
|
||||
Changes in version 3.2.5.RELEASE (2020-02-26)
|
||||
---------------------------------------------
|
||||
* DATAES-752 - Upgrade to Elasticsearch 6.8.6.
|
||||
* DATAES-741 - Tests fail due to Elasticsearch cluster 'blocks' on nearly-full file-systems.
|
||||
* DATAES-730 - Release 3.2.5 (Moore SR5).
|
||||
* DATAES-214 - ElasticsearchTemplate's prepareSearch(Query query) method should use getOffset().
|
||||
|
||||
|
||||
Changes in version 3.1.16.RELEASE (2020-02-26)
|
||||
----------------------------------------------
|
||||
* DATAES-729 - Release 3.1.16 (Lovelace SR16).
|
||||
|
||||
|
||||
Changes in version 4.0.0.M3 (2020-02-12)
|
||||
----------------------------------------
|
||||
* DATAES-743 - Revert geo converters to back to store converters.
|
||||
* DATAES-740 - Adapt to spring-data-commons changes.
|
||||
* DATAES-739 - Introduce nullable annotations for API validation.
|
||||
* DATAES-738 - Add entity related save methods to DocumentOperations.
|
||||
* DATAES-735 - Update to Elasticsearch 7.5.2.
|
||||
* DATAES-734 - Add Sort implementation that allows geo distance sorts.
|
||||
* DATAES-732 - Release 4.0 M3 (Neumann).
|
||||
* DATAES-449 - Pass route parameter to created search request.
|
||||
|
||||
|
||||
Changes in version 4.0.0.M2 (2020-01-17)
|
||||
----------------------------------------
|
||||
* DATAES-731 - Release 4.0 M2 (Neumann).
|
||||
|
||||
|
||||
Changes in version 4.0.0.M1 (2020-01-16)
|
||||
----------------------------------------
|
||||
* DATAES-727 - Use track_total_hits parameter for count queries.
|
||||
* DATAES-725 - Update copyright years to 2020.
|
||||
* DATAES-724 - Provide IndexOperations bean.
|
||||
* DATAES-723 - Cleanup ElasticsearchRepository interface.
|
||||
* DATAES-722 - Return total count relation in the SearchHits object.
|
||||
* DATAES-721 - Deprecation and Warnings cleanup.
|
||||
* DATAES-720 - SimpleReactiveElasticsearchRepository findAll() returns only 10 elements.
|
||||
* DATAES-719 - Add customization hook for reactive WebClient.
|
||||
* DATAES-718 - Deprecate @Score and scoreProperty.
|
||||
* DATAES-717 - Enable Repositories to return a SearchHits instance instead of a list.
|
||||
* DATAES-716 - Add Value mapping to the ElasticsearchMappingConverter.
|
||||
* DATAES-715 - Highlight results should be returned in the SearchHits.
|
||||
* DATAES-714 - Sort results should be returned in the SearchHits.
|
||||
* DATAES-713 - Transfer returned aggregations from the AggregatedPage to the SearchHits.
|
||||
* DATAES-711 - Update to Elasticsearch 7.5.
|
||||
* DATAES-709 - Add parameter to include default settings on setting request.
|
||||
* DATAES-702 - Travis CI builds currently broken.
|
||||
* DATAES-701 - Enable proxy support for the reactive rest template.
|
||||
* DATAES-700 - Enable proxy support for RestClient.
|
||||
* DATAES-697 - Query refactoring cleanup.
|
||||
* DATAES-693 - Support for source fetching in update operations.
|
||||
* DATAES-690 - Enable builds on JDK 11+.
|
||||
* DATAES-688 - Remove unneeded SearchQuery subinterface.
|
||||
* DATAES-684 - Implement Bulk Request for Reactive.
|
||||
* DATAES-680 - ReactiveElasticsearchTemplate should use the count API.
|
||||
* DATAES-677 - Update to Elasticsearch 7.4.1.
|
||||
* DATAES-676 - fix documentation to reflect the changes in API restructuring.
|
||||
* DATAES-675 - migrate tests to JUnit 5.
|
||||
* DATAES-673 - Create a Ssl Rest Client using SslContext and HostnameVerifier.
|
||||
* DATAES-672 - Introduce SearchHit to enrich an Entity type.
|
||||
* DATAES-671 - Missing indicesOptions support for scrolling queries.
|
||||
* DATAES-670 - fix version compatibility matrix in documentation.
|
||||
* DATAES-666 - Rebase branch 4.0.x onto master and merge it.
|
||||
* DATAES-665 - Javadoc not deployed.
|
||||
* DATAES-663 - Release 4.0 M1 (Neumann).
|
||||
* DATAES-661 - Support track_total_hits request parameter.
|
||||
* DATAES-659 - Move MappingElasticsearchConverter to correct package.
|
||||
* DATAES-658 - Update 4.0.x to ES 7.3.2.
|
||||
* DATAES-654 - Add Junit 5 support.
|
||||
* DATAES-651 - Fix regression from escaping.
|
||||
* DATAES-650 - Add support for pathPrefix to ClientConfiguration.
|
||||
* DATAES-647 - In and NotIn uses should instead of terms-query.
|
||||
* DATAES-639 - Add ignore_above mapping parameter support.
|
||||
* DATAES-638 - Remove redundant public modifiers in @MultiField.
|
||||
* DATAES-637 - Change branch 4.0. to use Elasticsearch 7.3.
|
||||
* DATAES-635 - Create branch 4.0.x and integrate the changes from the existing 4.x branch.
|
||||
* DATAES-634 - Rearrange methods in Template API.
|
||||
* DATAES-633 - Introduce value object to capture index type/index name.
|
||||
* DATAES-632 - Use single Query type in Template API methods.
|
||||
* DATAES-631 - Consolidate query objects.
|
||||
|
||||
|
||||
Changes in version 3.2.4.RELEASE (2020-01-15)
|
||||
---------------------------------------------
|
||||
* DATAES-725 - Update copyright years to 2020.
|
||||
@@ -941,3 +1307,30 @@ Release Notes - Spring Data Elasticsearch - Version 1.0 M1 (2014-02-07)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data Elasticsearch 3.2.4
|
||||
Spring Data Elasticsearch 3.2.11 (Moore SR11)
|
||||
Copyright (c) [2013-2019] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -10,3 +10,10 @@ code for the these subcomponents is subject to the terms and
|
||||
conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+6
-6
@@ -551,7 +551,7 @@ public class ReactiveElasticsearchClientTests {
|
||||
assertThat(syncClient.indices().exists(new GetIndexRequest().indices(INDEX_I), RequestOptions.DEFAULT)).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAES-569
|
||||
@Test // DATAES-569, DATAES-767
|
||||
public void deleteNonExistingIndexErrors() {
|
||||
|
||||
client.indices().deleteIndex(request -> request.indices(INDEX_I)) //
|
||||
@@ -569,7 +569,7 @@ public class ReactiveElasticsearchClientTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-569
|
||||
@Test // DATAES-569, DATAES-767
|
||||
public void openNonExistingIndex() {
|
||||
|
||||
client.indices().openIndex(request -> request.indices(INDEX_I)) //
|
||||
@@ -587,7 +587,7 @@ public class ReactiveElasticsearchClientTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-569
|
||||
@Test // DATAES-569, DATAES-767
|
||||
public void closeNonExistingIndex() {
|
||||
|
||||
client.indices().closeIndex(request -> request.indices(INDEX_I)) //
|
||||
@@ -605,7 +605,7 @@ public class ReactiveElasticsearchClientTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-569
|
||||
@Test // DATAES-569, DATAES-767
|
||||
public void refreshNonExistingIndex() {
|
||||
|
||||
client.indices().refreshIndex(request -> request.indices(INDEX_I)) //
|
||||
@@ -626,7 +626,7 @@ public class ReactiveElasticsearchClientTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-569
|
||||
@Test // DATAES-569, DATAES-767
|
||||
public void updateMappingNonExistingIndex() {
|
||||
|
||||
Map<String, Object> jsonMap = Collections.singletonMap("properties",
|
||||
@@ -647,7 +647,7 @@ public class ReactiveElasticsearchClientTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-569
|
||||
@Test // DATAES-569, DATAES-767
|
||||
public void flushNonExistingIndex() {
|
||||
|
||||
client.indices().flushIndex(request -> request.indices(INDEX_I)) //
|
||||
|
||||
+1
-1
@@ -456,7 +456,7 @@ public class ReactiveElasticsearchClientUnitTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-488
|
||||
@Test // DATAES-488, DATAES-767
|
||||
public void updateShouldEmitErrorWhenNotFound() {
|
||||
|
||||
hostProvider.when(HOST) //
|
||||
|
||||
+26
@@ -531,6 +531,32 @@ public class ElasticsearchEntityMapperUnitTests {
|
||||
assertThat(target.address).isEqualTo(bigBunsCafe);
|
||||
}
|
||||
|
||||
@Test // DATAES-892
|
||||
public void readGenericListWithMaps() {
|
||||
Map<String, Object> simpleMap = new HashMap<>();
|
||||
simpleMap.put("int", 1);
|
||||
|
||||
List<Map<String, Object>> listWithSimpleMap = new ArrayList<>();
|
||||
listWithSimpleMap.add(simpleMap);
|
||||
|
||||
Map<String, List<Map<String, Object>>> mapWithSimpleList = new HashMap<>();
|
||||
mapWithSimpleList.put("someKey", listWithSimpleMap);
|
||||
|
||||
Map<String, Object> document = new LinkedHashMap<>();
|
||||
document.put("schemaLessObject", mapWithSimpleList);
|
||||
|
||||
SchemaLessObjectWrapper wrapper = entityMapper.read(SchemaLessObjectWrapper.class, document);
|
||||
assertThat(wrapper.getSchemaLessObject()).isEqualTo(mapWithSimpleList);
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
static class SchemaLessObjectWrapper {
|
||||
|
||||
private Map<String, Object> schemaLessObject;
|
||||
}
|
||||
|
||||
private String pointTemplate(String name, Point point) {
|
||||
return String.format(Locale.ENGLISH, "\"%s\":{\"lat\":%.1f,\"lon\":%.1f}", name, point.getX(), point.getY());
|
||||
}
|
||||
|
||||
@@ -394,13 +394,31 @@ public class MappingBuilderTests extends MappingContextBaseTests {
|
||||
assertEquals(expected, mapping, false);
|
||||
}
|
||||
|
||||
@Test // DATAES-568
|
||||
@Test // DATAES-568, DATAES-896
|
||||
public void shouldUseFieldNameOnMultiField() throws IOException, JSONException {
|
||||
|
||||
// given
|
||||
String expected = "{\"fieldname-type\":{\"properties\":{" + "\"id-property\":{\"type\":\"keyword\",\"index\":true},"
|
||||
+ "\"multifield-property\":{\"store\":false,\"type\":\"text\",\"analyzer\":\"whitespace\",\"fields\":{\"prefix\":{\"store\":false,\"type\":\"text\",\"analyzer\":\"stop\",\"search_analyzer\":\"standard\"}}}"
|
||||
+ "}}}";
|
||||
String expected = "{\n" + //
|
||||
" \"fieldname-type\": {\n" + //
|
||||
" \"properties\": {\n" + //
|
||||
" \"id-property\": {\n" + //
|
||||
" \"type\": \"keyword\",\n" + //
|
||||
" \"index\": true\n" + //
|
||||
" },\n" + //
|
||||
" \"main-field\": {\n" + //
|
||||
" \"type\": \"text\",\n" + //
|
||||
" \"analyzer\": \"whitespace\",\n" + //
|
||||
" \"fields\": {\n" + //
|
||||
" \"suff-ix\": {\n" + //
|
||||
" \"type\": \"text\",\n" + //
|
||||
" \"analyzer\": \"stop\",\n" + //
|
||||
" \"search_analyzer\": \"standard\"\n" + //
|
||||
" }\n" + //
|
||||
" }\n" + //
|
||||
" }\n" + //
|
||||
" }\n" + //
|
||||
" }\n" + //
|
||||
"}\n"; //
|
||||
|
||||
// when
|
||||
String mapping = getMappingBuilder().buildPropertyMapping(FieldNameEntity.MultiFieldEntity.class);
|
||||
@@ -470,9 +488,9 @@ public class MappingBuilderTests extends MappingContextBaseTests {
|
||||
@Id @Field("id-property") private String id;
|
||||
|
||||
@Field("multifield-property") //
|
||||
@MultiField(mainField = @Field(type = FieldType.Text, analyzer = "whitespace"), otherFields = {
|
||||
@InnerField(suffix = "prefix", type = FieldType.Text, analyzer = "stop", searchAnalyzer = "standard") }) //
|
||||
private String description;
|
||||
@MultiField(mainField = @Field(name = "main-field", type = FieldType.Text, analyzer = "whitespace"),
|
||||
otherFields = { @InnerField(suffix = "suff-ix", type = FieldType.Text, analyzer = "stop",
|
||||
searchAnalyzer = "standard") }) private String description;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-13
@@ -203,12 +203,12 @@ public class ReactiveElasticsearchTemplateTests {
|
||||
template.save(null);
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
public void findByIdShouldCompleteWhenIndexDoesNotExist() {
|
||||
@Test // DATAES-519, DATAES-767
|
||||
public void getByIdShouldCompleteWhenIndexDoesNotExist() {
|
||||
|
||||
template.findById("foo", SampleEntity.class, "no-such-index") //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyComplete();
|
||||
.expectError(ElasticsearchStatusException.class);
|
||||
}
|
||||
|
||||
@Test // DATAES-504
|
||||
@@ -312,12 +312,12 @@ public class ReactiveElasticsearchTemplateTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
public void findShouldCompleteWhenIndexDoesNotExist() {
|
||||
@Test // DATAES-519, DATAES-767
|
||||
public void searchShouldCompleteWhenIndexDoesNotExist() {
|
||||
|
||||
template.find(new CriteriaQuery(Criteria.where("message").is("some message")), SampleEntity.class, "no-such-index") //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyComplete();
|
||||
.expectError(ElasticsearchStatusException.class);
|
||||
}
|
||||
|
||||
@Test // DATAES-504
|
||||
@@ -410,7 +410,7 @@ public class ReactiveElasticsearchTemplateTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-595
|
||||
@Test // DATAES-595, DATAES-767
|
||||
public void shouldThrowElasticsearchStatusExceptionWhenInvalidPreferenceForGivenCriteria() {
|
||||
|
||||
SampleEntity sampleEntity1 = randomEntity("test message");
|
||||
@@ -480,13 +480,12 @@ public class ReactiveElasticsearchTemplateTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
@Test // DATAES-519, DATAES-767
|
||||
public void countShouldReturnZeroWhenIndexDoesNotExist() {
|
||||
|
||||
template.count(SampleEntity.class) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(0L) //
|
||||
.verifyComplete();
|
||||
.expectError(ElasticsearchStatusException.class);
|
||||
}
|
||||
|
||||
@Test // DATAES-504
|
||||
@@ -513,12 +512,12 @@ public class ReactiveElasticsearchTemplateTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
public void deleteByIdShouldCompleteWhenIndexDoesNotExist() {
|
||||
@Test // DATAES-519, DATAES-767
|
||||
public void deleteShouldErrorWhenIndexDoesNotExist() {
|
||||
|
||||
template.deleteById("does-not-exists", SampleEntity.class, "no-such-index") //
|
||||
.as(StepVerifier::create)//
|
||||
.verifyComplete();
|
||||
.expectError(ElasticsearchStatusException.class);
|
||||
}
|
||||
|
||||
@Test // DATAES-504
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2020 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.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
public class StreamQueriesTest {
|
||||
|
||||
@Test // DATAES-764
|
||||
public void shouldCallClearScrollOnIteratorClose() {
|
||||
|
||||
// given
|
||||
List<String> results = new ArrayList<>();
|
||||
results.add("one");
|
||||
|
||||
ScrolledPage<String> page = new ScrolledPageImpl("1234", results);
|
||||
|
||||
AtomicBoolean clearScrollCalled = new AtomicBoolean(false);
|
||||
|
||||
// when
|
||||
CloseableIterator<String> closeableIterator = StreamQueries.streamResults( //
|
||||
page, //
|
||||
scrollId -> new ScrolledPageImpl(scrollId, Collections.emptyList()), //
|
||||
scrollId -> clearScrollCalled.set(true));
|
||||
|
||||
while (closeableIterator.hasNext()) {
|
||||
closeableIterator.next();
|
||||
}
|
||||
closeableIterator.close();
|
||||
|
||||
// then
|
||||
assertThat(clearScrollCalled).isTrue();
|
||||
|
||||
}
|
||||
|
||||
private static class ScrolledPageImpl extends PageImpl<String> implements ScrolledPage<String> {
|
||||
|
||||
private String scrollId;
|
||||
|
||||
public ScrolledPageImpl(String scrollId, List<String> content) {
|
||||
super(content);
|
||||
this.scrollId = scrollId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getScrollId() {
|
||||
return scrollId;
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -19,8 +19,12 @@ import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.annotations.InnerField;
|
||||
import org.springframework.data.elasticsearch.annotations.MultiField;
|
||||
import org.springframework.data.elasticsearch.annotations.Score;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SimpleElasticsearchPersistentProperty}.
|
||||
@@ -62,6 +66,16 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
|
||||
assertThat(persistentProperty.getFieldName()).isEqualTo("by-value");
|
||||
}
|
||||
|
||||
@Test // DATAES-896
|
||||
public void shouldUseNameFromMultiFieldMainField() {
|
||||
SimpleElasticsearchPersistentEntity<?> persistentEntity = context
|
||||
.getRequiredPersistentEntity(MultiFieldProperty.class);
|
||||
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getPersistentProperty("mainfieldProperty");
|
||||
|
||||
assertThat(persistentProperty).isNotNull();
|
||||
assertThat(persistentProperty.getFieldName()).isEqualTo("mainfield");
|
||||
}
|
||||
|
||||
static class InvalidScoreProperty {
|
||||
@Score String scoreProperty;
|
||||
}
|
||||
@@ -73,4 +87,9 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
|
||||
static class FieldValueProperty {
|
||||
@Field(value = "by-value") String fieldProperty;
|
||||
}
|
||||
|
||||
static class MultiFieldProperty {
|
||||
@Nullable @MultiField(mainField = @Field("mainfield"),
|
||||
otherFields = { @InnerField(suffix = "suff", type = FieldType.Keyword) }) String mainfieldProperty;
|
||||
}
|
||||
}
|
||||
|
||||
+28
-9
@@ -23,6 +23,7 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -61,15 +62,15 @@ abstract class QueryKeywordsTests {
|
||||
|
||||
IndexInitializer.init(elasticsearchTemplate, Product.class);
|
||||
|
||||
Product product1 = Product.builder().id("1").name("Sugar").text("Cane sugar").price(1.0f).available(false)
|
||||
Product product1 = Product.builder().id("1").name("Sugar").text("Cane sugar").price(1.0f).available(false)
|
||||
.sortName("sort5").build();
|
||||
Product product2 = Product.builder().id("2").name("Sugar").text("Cane sugar").price(1.2f).available(true)
|
||||
Product product2 = Product.builder().id("2").name("Sugar").text("Cane sugar").price(1.2f).available(true)
|
||||
.sortName("sort4").build();
|
||||
Product product3 = Product.builder().id("3").name("Sugar").text("Beet sugar").price(1.1f).available(true)
|
||||
Product product3 = Product.builder().id("3").name("Sugar").text("Beet sugar").price(1.1f).available(true)
|
||||
.sortName("sort3").build();
|
||||
Product product4 = Product.builder().id("4").name("Salt").text("Rock salt").price(1.9f).available(true)
|
||||
Product product4 = Product.builder().id("4").name("Salt").text("Rock salt").price(1.9f).available(true)
|
||||
.sortName("sort2").build();
|
||||
Product product5 = Product.builder().id("5").name("Salt").text("Sea salt").price(2.1f).available(false)
|
||||
Product product5 = Product.builder().id("5").name("Salt").text("Sea salt").price(2.1f).available(false)
|
||||
.sortName("sort1").build();
|
||||
|
||||
repository.saveAll(Arrays.asList(product1, product2, product3, product4, product5));
|
||||
@@ -165,7 +166,7 @@ abstract class QueryKeywordsTests {
|
||||
|
||||
@Test // DATAES-615
|
||||
public void shouldSupportSortOnStandardFieldWithCriteria() {
|
||||
List<String> sortedIds = repository.findAllByNameOrderByText("Salt").stream() //
|
||||
List<String> sortedIds = repository.findAllByNameOrderByText("Salt").stream() //
|
||||
.map(it -> it.id).collect(Collectors.toList());
|
||||
|
||||
assertThat(sortedIds).containsExactly("4", "5");
|
||||
@@ -174,7 +175,7 @@ abstract class QueryKeywordsTests {
|
||||
@Test // DATAES-615
|
||||
public void shouldSupportSortOnFieldWithCustomFieldNameWithCriteria() {
|
||||
|
||||
List<String> sortedIds = repository.findAllByNameOrderBySortName("Sugar").stream() //
|
||||
List<String> sortedIds = repository.findAllByNameOrderBySortName("Sugar").stream() //
|
||||
.map(it -> it.id).collect(Collectors.toList());
|
||||
|
||||
assertThat(sortedIds).containsExactly("3", "2", "1");
|
||||
@@ -182,7 +183,7 @@ abstract class QueryKeywordsTests {
|
||||
|
||||
@Test // DATAES-615
|
||||
public void shouldSupportSortOnStandardFieldWithoutCriteria() {
|
||||
List<String> sortedIds = repository.findAllByOrderByText().stream() //
|
||||
List<String> sortedIds = repository.findAllByOrderByText().stream() //
|
||||
.map(it -> it.text).collect(Collectors.toList());
|
||||
|
||||
assertThat(sortedIds).containsExactly("Beet sugar", "Cane sugar", "Cane sugar", "Rock salt", "Sea salt");
|
||||
@@ -191,12 +192,28 @@ abstract class QueryKeywordsTests {
|
||||
@Test // DATAES-615
|
||||
public void shouldSupportSortOnFieldWithCustomFieldNameWithoutCriteria() {
|
||||
|
||||
List<String> sortedIds = repository.findAllByOrderBySortName().stream() //
|
||||
List<String> sortedIds = repository.findAllByOrderBySortName().stream() //
|
||||
.map(it -> it.id).collect(Collectors.toList());
|
||||
|
||||
assertThat(sortedIds).containsExactly("5", "4", "3", "2", "1");
|
||||
}
|
||||
|
||||
@Test // DATAES-937
|
||||
public void shouldReturnEmptyListOnFindByIdWithEmptyInputList() {
|
||||
|
||||
Iterable<Product> products = repository.findAllById(new ArrayList<>());
|
||||
|
||||
assertThat(products).isEmpty();
|
||||
}
|
||||
|
||||
@Test // DATAES-937
|
||||
public void shouldReturnEmptyListOnDerivedMethodWithEmptyInputList() {
|
||||
|
||||
Iterable<Product> products = repository.findAllByNameIn(new ArrayList<>());
|
||||
|
||||
assertThat(products).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
@@ -279,6 +296,8 @@ abstract class QueryKeywordsTests {
|
||||
List<Product> findAllByOrderByText();
|
||||
|
||||
List<Product> findAllByOrderBySortName();
|
||||
|
||||
List<Product> findAllByNameIn(List<String> names);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+26
-12
@@ -23,6 +23,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.elasticsearch.ElasticsearchStatusException;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -41,11 +42,11 @@ import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.annotation.Id;
|
||||
@@ -69,7 +70,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @currentRead Fool's Fate - Robin Hobb
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@@ -95,6 +96,11 @@ public class SimpleReactiveElasticsearchRepositoryTests {
|
||||
TestUtils.deleteIndex(INDEX);
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
TestUtils.deleteIndex(INDEX);
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
public void saveShouldSaveSingleEntity() {
|
||||
|
||||
@@ -125,9 +131,11 @@ public class SimpleReactiveElasticsearchRepositoryTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
public void findByIdShouldCompleteIfIndexDoesNotExist() {
|
||||
repository.findById("id-two").as(StepVerifier::create).verifyComplete();
|
||||
@Test // DATAES-519, DATAES-767
|
||||
public void findByIdShouldErrorIfIndexDoesNotExist() {
|
||||
repository.findById("id-two") //
|
||||
.as(StepVerifier::create) //
|
||||
.expectError(ElasticsearchStatusException.class);
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
@@ -169,9 +177,11 @@ public class SimpleReactiveElasticsearchRepositoryTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
@Test // DATAES-519, DATAES-767
|
||||
public void findAllByIdByIdShouldCompleteIfIndexDoesNotExist() {
|
||||
repository.findAllById(Arrays.asList("id-two", "id-two")).as(StepVerifier::create).verifyComplete();
|
||||
repository.findAllById(Arrays.asList("id-two", "id-two")).as(StepVerifier::create)
|
||||
.expectError(ElasticsearchStatusException.class);
|
||||
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
@@ -199,9 +209,10 @@ public class SimpleReactiveElasticsearchRepositoryTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
@Test // DATAES-519, DATAE-767
|
||||
public void countShouldReturnZeroWhenIndexDoesNotExist() {
|
||||
repository.count().as(StepVerifier::create).expectNext(0L).verifyComplete();
|
||||
repository.count().as(StepVerifier::create).expectNext(0L).expectError(ElasticsearchStatusException.class);
|
||||
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
@@ -287,9 +298,12 @@ public class SimpleReactiveElasticsearchRepositoryTests {
|
||||
repository.deleteById("does-not-exist").as(StepVerifier::create).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
public void deleteByIdShouldCompleteWhenIndexDoesNotExist() {
|
||||
repository.deleteById("does-not-exist").as(StepVerifier::create).verifyComplete();
|
||||
@Test // DATAES-519, DATAES-767
|
||||
public void deleteByIdShouldErrorWhenIndexDoesNotExist() {
|
||||
repository.deleteById("does-not-exist") //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyError(ElasticsearchStatusException.class);
|
||||
;
|
||||
}
|
||||
|
||||
@Test // DATAES-519
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#enabled scripts - this require groovy
|
||||
#script.inline: true
|
||||
#node.max_local_storage_nodes: 100
|
||||
#node.max_local_storage_nodes: 100
|
||||
cluster.routing.allocation.disk.watermark.low: 1gb
|
||||
cluster.routing.allocation.disk.watermark.high: 1gb
|
||||
cluster.routing.allocation.disk.watermark.flood_stage: 1gb
|
||||
|
||||
BIN
Binary file not shown.
+2
-2
@@ -20,7 +20,7 @@
|
||||
description=Adds "built in" analyzers to Elasticsearch.
|
||||
#
|
||||
# 'version': plugin's version
|
||||
version=6.8.4
|
||||
version=6.8.13
|
||||
#
|
||||
# 'name': the plugin name
|
||||
name=analysis-common
|
||||
@@ -35,7 +35,7 @@ classname=org.elasticsearch.analysis.common.CommonAnalysisPlugin
|
||||
java.version=1.8
|
||||
#
|
||||
# 'elasticsearch.version': version of elasticsearch compiled against
|
||||
elasticsearch.version=6.8.4
|
||||
elasticsearch.version=6.8.13
|
||||
### optional elements for plugins:
|
||||
#
|
||||
# 'extended.plugins': other plugins this plugin extends through SPI
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -20,7 +20,7 @@
|
||||
description=Module for ingest processors that do not require additional security permissions or have large dependencies and resources
|
||||
#
|
||||
# 'version': plugin's version
|
||||
version=6.8.4
|
||||
version=6.8.13
|
||||
#
|
||||
# 'name': the plugin name
|
||||
name=ingest-common
|
||||
@@ -35,7 +35,7 @@ classname=org.elasticsearch.ingest.common.IngestCommonPlugin
|
||||
java.version=1.8
|
||||
#
|
||||
# 'elasticsearch.version': version of elasticsearch compiled against
|
||||
elasticsearch.version=6.8.4
|
||||
elasticsearch.version=6.8.13
|
||||
### optional elements for plugins:
|
||||
#
|
||||
# 'extended.plugins': other plugins this plugin extends through SPI
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+2
-2
@@ -20,7 +20,7 @@
|
||||
description=Lucene expressions integration for Elasticsearch
|
||||
#
|
||||
# 'version': plugin's version
|
||||
version=6.8.4
|
||||
version=6.8.13
|
||||
#
|
||||
# 'name': the plugin name
|
||||
name=lang-expression
|
||||
@@ -35,7 +35,7 @@ classname=org.elasticsearch.script.expression.ExpressionPlugin
|
||||
java.version=1.8
|
||||
#
|
||||
# 'elasticsearch.version': version of elasticsearch compiled against
|
||||
elasticsearch.version=6.8.4
|
||||
elasticsearch.version=6.8.13
|
||||
### optional elements for plugins:
|
||||
#
|
||||
# 'extended.plugins': other plugins this plugin extends through SPI
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -20,7 +20,7 @@
|
||||
description=An easy, safe and fast scripting language for Elasticsearch
|
||||
#
|
||||
# 'version': plugin's version
|
||||
version=6.8.4
|
||||
version=6.8.13
|
||||
#
|
||||
# 'name': the plugin name
|
||||
name=lang-painless
|
||||
@@ -35,7 +35,7 @@ classname=org.elasticsearch.painless.PainlessPlugin
|
||||
java.version=1.8
|
||||
#
|
||||
# 'elasticsearch.version': version of elasticsearch compiled against
|
||||
elasticsearch.version=6.8.4
|
||||
elasticsearch.version=6.8.13
|
||||
### optional elements for plugins:
|
||||
#
|
||||
# 'extended.plugins': other plugins this plugin extends through SPI
|
||||
|
||||
BIN
Binary file not shown.
@@ -20,7 +20,7 @@
|
||||
description=Adds advanced field mappers
|
||||
#
|
||||
# 'version': plugin's version
|
||||
version=6.8.4
|
||||
version=6.8.13
|
||||
#
|
||||
# 'name': the plugin name
|
||||
name=mapper-extras
|
||||
@@ -35,7 +35,7 @@ classname=org.elasticsearch.index.mapper.MapperExtrasPlugin
|
||||
java.version=1.8
|
||||
#
|
||||
# 'elasticsearch.version': version of elasticsearch compiled against
|
||||
elasticsearch.version=6.8.4
|
||||
elasticsearch.version=6.8.13
|
||||
### optional elements for plugins:
|
||||
#
|
||||
# 'extended.plugins': other plugins this plugin extends through SPI
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
description=The Reindex module adds APIs to reindex from one index to another or update documents in place.
|
||||
#
|
||||
# 'version': plugin's version
|
||||
version=6.8.4
|
||||
version=6.8.13
|
||||
#
|
||||
# 'name': the plugin name
|
||||
name=reindex
|
||||
@@ -35,7 +35,7 @@ classname=org.elasticsearch.index.reindex.ReindexPlugin
|
||||
java.version=1.8
|
||||
#
|
||||
# 'elasticsearch.version': version of elasticsearch compiled against
|
||||
elasticsearch.version=6.8.4
|
||||
elasticsearch.version=6.8.13
|
||||
### optional elements for plugins:
|
||||
#
|
||||
# 'extended.plugins': other plugins this plugin extends through SPI
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@
|
||||
description=Module for URL repository
|
||||
#
|
||||
# 'version': plugin's version
|
||||
version=6.8.4
|
||||
version=6.8.13
|
||||
#
|
||||
# 'name': the plugin name
|
||||
name=repository-url
|
||||
@@ -35,7 +35,7 @@ classname=org.elasticsearch.plugin.repository.url.URLRepositoryPlugin
|
||||
java.version=1.8
|
||||
#
|
||||
# 'elasticsearch.version': version of elasticsearch compiled against
|
||||
elasticsearch.version=6.8.4
|
||||
elasticsearch.version=6.8.13
|
||||
### optional elements for plugins:
|
||||
#
|
||||
# 'extended.plugins': other plugins this plugin extends through SPI
|
||||
|
||||
Reference in New Issue
Block a user