Configure index settings with @Setting annotation.

Original Pull Request #1748
Closes #1719
This commit is contained in:
Peter-Josef Meisch 2021-03-28 13:24:52 +02:00 committed by GitHub
parent 13ab2b9e95
commit 2e9bef0edb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 1307 additions and 650 deletions

View File

@ -8,7 +8,7 @@ Spring Data Elasticsearch operates upon an Elasticsearch client that is connecte
[[elasticsearch.clients.transport]]
== Transport Client
WARNING: The well known `TransportClient` is deprecated as of Elasticsearch 7 and will be removed in Elasticsearch 8. (https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html[see the Elasticsearch documentation]). Spring Data Elasticsearch will support the `TransportClient` as long as it is available in the used
WARNING: The `TransportClient` is deprecated as of Elasticsearch 7 and will be removed in Elasticsearch 8. (https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html[see the Elasticsearch documentation]). Spring Data Elasticsearch will support the `TransportClient` as long as it is available in the used
Elasticsearch <<elasticsearch.versions,version>> but has deprecated the classes using it since version 4.0.
We strongly recommend to use the <<elasticsearch.clients.rest>> instead of the `TransportClient`.

View File

@ -6,6 +6,10 @@ This section describes breaking changes from version 4.1.x to 4.2.x and how remo
[[elasticsearch-migration-guide-4.1-4.2.deprecations]]
== Deprecations
=== @Document parameters
The parameters of the `@Document` annotation that are relevant for the index settings (`useServerConfiguration`, `shards`. `replicas`, `refreshIntervall` and `indexStoretype`) have been moved to the `@Setting` annotation. Use in `@Document` is still possible but deprecated.
[[elasticsearch-migration-guide-4.1-4.2.removal]]
== Removals

View File

@ -4,6 +4,48 @@
This chapter covers additional support for Elasticsearch operations that cannot be directly accessed via the repository interface.
It is recommended to add those operations as custom implementation as described in <<repositories.custom-implementations>> .
[[elasticsearc.misc.index.settings]]
== Index settings
When creating Elasticsearch indices with Spring Data Elasticsearch different index settings can be defined by using the `@Setting` annotation. The following arguments are available:
* `useServerConfiguration` does not send any settings parameters, so the Elasticsearch server configuration determines them.
* `settingPath` refers to a JSON file defining the settings that must be resolvable in the classpath
* `shards` the number of shards to use, defaults to _1_
* `replicas` the number of replicas, defaults to _1_
* `refreshIntervall`, defaults to _"1s"_
* `indexStoreType`, defaults to _"fs"_
It is as well possible to define https://www.elastic.co/guide/en/elasticsearch/reference/7.11/index-modules-index-sorting.html[index sorting] (check the linked Elasticsearch documentation for the possible field types and values):
====
[source,java]
----
@Document(indexName = "entities")
@Setting(
sortFields = { "secondField", "firstField" }, <.>
sortModes = { Setting.SortMode.max, Setting.SortMode.min }, <.>
sortOrders = { Setting.SortOrder.desc, Setting.SortOrder.asc },
sortMissingValues = { Setting.SortMissing._last, Setting.SortMissing._first })
class Entity {
@Nullable
@Id private String id;
@Nullable
@Field(name = "first_field", type = FieldType.Keyword)
private String firstField;
@Nullable @Field(name = "second_field", type = FieldType.Keyword)
private String secondField;
// getter and setter...
}
----
<.> when defining sort fields, use the name of the Java property (_firstField_), not the name that might be defined for Elasticsearch (_first_field_)
<.> `sortModes`, `sortOrders` and `sortMissingValues` are optional, but if they are set, the number of entries must match the number of `sortFields` elements
====
[[elasticsearch.misc.filter]]
== Filter Builder
@ -20,7 +62,7 @@ SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFilter(boolFilter().must(termFilter("id", documentId)))
.build();
Page<SampleEntity> sampleEntities = operations.searchForPage(searchQuery, SampleEntity.class, index);
----
====
@ -31,6 +73,7 @@ Page<SampleEntity> sampleEntities = operations.searchForPage(searchQuery, Sample
Elasticsearch has a scroll API for getting big result set in chunks.
This is internally used by Spring Data Elasticsearch to provide the implementations of the `<T> SearchHitsIterator<T> SearchOperations.searchForStream(Query query, Class<T> clazz, IndexCoordinates index)` method.
====
[source,java]
----
IndexCoordinates index = IndexCoordinates.of("sample-index");
@ -50,9 +93,11 @@ while (stream.hasNext()) {
stream.close();
----
====
There are no methods in the `SearchOperations` API to access the scroll id, if it should be necessary to access this, the following methods of the `ElasticsearchRestTemplate` can be used:
====
[source,java]
----
@ -77,10 +122,12 @@ while (scroll.hasSearchHits()) {
}
template.searchScrollClear(scrollId);
----
====
To use the Scroll API with repository methods, the return type must defined as `Stream` in the Elasticsearch Repository.
The implementation of the method will then use the scroll methods from the ElasticsearchTemplate.
====
[source,java]
----
interface SampleEntityRepository extends Repository<SampleEntity, String> {
@ -89,6 +136,7 @@ interface SampleEntityRepository extends Repository<SampleEntity, String> {
}
----
====
[[elasticsearch.misc.sorts]]
== Sort options
@ -97,7 +145,9 @@ In addition to the default sort options described <<repositories.paging-and-sort
If the class to be retrieved has a `GeoPoint` property named _location_, the following `Sort` would sort the results by distance to the given point:
====
[source,java]
----
Sort.by(new GeoDistanceOrder("location", new GeoPoint(48.137154, 11.5761247)))
----
====

View File

@ -36,14 +36,6 @@ The most important attributes are:
This can contain a SpEL template expression like `"log-#{T(java.time.LocalDate).now().toString()}"`
** `type`: [line-through]#the mapping type.
If not set, the lowercased simple name of the class is used.# (deprecated since version 4.0)
** `shards`: the number of shards for the index.
** `replicas`: the number of replicas for the index.
** `refreshIntervall`: Refresh interval for the index.
Used for index creation.
Default value is _"1s"_.
** `indexStoreType`: Index storage type for the index.
Used for index creation.
Default value is _"fs"_.
** `createIndex`: flag whether to create an index on repository bootstrapping.
Default value is _true_.
See <<elasticsearch.repositories.autocreation>>
@ -71,13 +63,13 @@ The mapping metadata infrastructure is defined in a separate spring-data-commons
==== Date format mapping
Properties that derive from `TemporalAccessor` or are of type `java.util.Date` must either have a `@Field` annotation
of type `FieldType.Date` or a custom converter must be registered for this type. This paragraph describes the use of
of type `FieldType.Date` or a custom converter must be registered for this type. This paragraph describes the use of
`FieldType.Date`.
There are two attributes of the `@Field` annotation that define which date format information is written to the
There are two attributes of the `@Field` annotation that define which date format information is written to the
mapping (also see https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html#built-in-date-formats[Elasticsearch Built In Formats] and https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html#custom-date-formats[Elasticsearch Custom Date Formats])
The `format` attributes is used to define at least one of the predefined formats. If it is not defined, then a
The `format` attributes is used to define at least one of the predefined formats. If it is not defined, then a
default value of __date_optional_time_ and _epoch_millis_ is used.
The `pattern` attribute can be used to add additional custom format strings. If you want to use only custom date formats, you must set the `format` property to empty `{}`.

View File

@ -21,7 +21,8 @@ The default implementations of the interfaces offer:
====
.Index management and automatic creation of indices and mappings.
The `IndexOperations` interface and the provided implementation which can be obtained from an `ElasticsearchOperations` instance - for example with a call to `operations.indexOps(clazz)`- give the user the ability to create indices, put mappings or store template and alias information in the Elasticsearch cluster.
The `IndexOperations` interface and the provided implementation which can be obtained from an `ElasticsearchOperations` instance - for example with a call to `operations.indexOps(clazz)`- give the user the ability to create indices, put mappings or store template and alias information in the Elasticsearch cluster. Details of the index that will be created
can be set by using the `@Setting` annotation, refer to <<elasticsearc.misc.index.settings>> for further information.
**None of these operations are done automatically** by the implementations of `IndexOperations` or `ElasticsearchOperations`. It is the user's responsibility to call the methods.

View File

@ -31,7 +31,7 @@ class Book {
The `@Document` annotation has an argument `createIndex`. If this argument is set to true - which is the default value - Spring Data Elasticsearch will during bootstrapping the repository support on application startup check if the index defined by the `@Document` annotation exists.
If it does not exist, the index will be created and the mappings derived from the entity's annotations (see <<elasticsearch.mapping>>) will be written to the newly created index.
If it does not exist, the index will be created and the mappings derived from the entity's annotations (see <<elasticsearch.mapping>>) will be written to the newly created index. Details of the index that will be created can be set by using the `@Setting` annotation, refer to <<elasticsearc.misc.index.settings>> for further information.
include::elasticsearch-repository-queries.adoc[leveloffset=+1]
@ -131,7 +131,7 @@ class ProductService {
public void setRepository(ProductRepository repository) {
this.repository = repository;
}
}
}
----
<1> Create a component by using the same calls as are used in the <<elasticsearch.operations>> chapter.
<2> Let the CDI framework inject the Repository into your class.

View File

@ -0,0 +1,31 @@
/*
* Copyright 2021 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;
import org.springframework.core.NestedRuntimeException;
/**
* @author Peter-Josef Meisch
*/
public class ResourceFailureException extends NestedRuntimeException {
public ResourceFailureException(String msg) {
super(msg);
}
public ResourceFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -55,29 +55,45 @@ public @interface Document {
/**
* Use server-side settings when creating the index.
*
* @deprecated since 4.2, use the {@link Setting} annotation to configure settings
*/
@Deprecated
boolean useServerConfiguration() default false;
/**
* Number of shards for the index {@link #indexName()}. Used for index creation. <br/>
* With version 4.0, the default value is changed from 5 to 1 to reflect the change in the default settings of
* Elasticsearch which changed to 1 as well in Elasticsearch 7.0.
* ComposableAnnotationsUnitTest.documentAnnotationShouldBeComposable:60
*
* @deprecated since 4.2, use the {@link Setting} annotation to configure settings
*/
@Deprecated
short shards() default 1;
/**
* Number of replicas for the index {@link #indexName()}. Used for index creation.
*
* @deprecated since 4.2, use the {@link Setting} annotation to configure settings
*/
@Deprecated
short replicas() default 1;
/**
* Refresh interval for the index {@link #indexName()}. Used for index creation.
*
* @deprecated since 4.2, use the {@link Setting} annotation to configure settings
*/
@Deprecated
String refreshInterval() default "1s";
/**
* Index storage type for the index {@link #indexName()}. Used for index creation.
*
* @deprecated since 4.2, use the {@link Setting} annotation to configure settings
*/
@Deprecated
String indexStoreType() default "fs";
/**

View File

@ -15,7 +15,11 @@
*/
package org.springframework.data.elasticsearch.annotations;
import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.data.annotation.Persistent;
@ -23,14 +27,84 @@ import org.springframework.data.annotation.Persistent;
* Elasticsearch Setting
*
* @author Mohsin Husen
* @author Peter-Josef Meisch
*/
@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Target({ ElementType.TYPE })
public @interface Setting {
/**
* Resource path for a settings configuration
*/
String settingPath() default "";
/**
* Use server-side settings when creating the index.
*/
boolean useServerConfiguration() default false;
/**
* Number of shards for the index. Used for index creation. <br/>
* With version 4.0, the default value is changed from 5 to 1 to reflect the change in the default settings of
* Elasticsearch which changed to 1 as well in Elasticsearch 7.0.
*/
short shards() default 1;
/**
* Number of replicas for the index. Used for index creation.
*/
short replicas() default 1;
/**
* Refresh interval for the index. Used for index creation.
*/
String refreshInterval() default "1s";
/**
* Index storage type for the index. Used for index creation.
*/
String indexStoreType() default "fs";
/**
* fields to define an index sorting
*
* @since 4.2
*/
String[] sortFields() default {};
/**
* defines the order for {@link #sortFields()}. If present, it must have the same number of elements
*
* @since 4.2
*/
SortOrder[] sortOrders() default {};
/**
* defines the mode for {@link #sortFields()}. If present, it must have the same number of elements
*
* @since 4.2
*/
SortMode[] sortModes() default {};
/**
* defines the missing value for {@link #sortFields()}. If present, it must have the same number of elements
*
* @since 4.2
*/
SortMissing[] sortMissingValues() default {};
enum SortOrder {
asc, desc
}
enum SortMode {
min, max
}
enum SortMissing {
_last, _first
}
}

View File

@ -29,17 +29,16 @@ import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.data.elasticsearch.core.index.MappingBuilder;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.AliasQuery;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Base implementation of {@link IndexOperations} common to Transport and Rest based Implementations of IndexOperations.
@ -90,33 +89,20 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
@Override
public boolean create() {
Document settings = null;
if (boundClass != null) {
settings = createSettings(boundClass);
}
Settings settings = boundClass != null ? createSettings(boundClass) : new Settings();
return doCreate(getIndexCoordinates(), settings, null);
}
@Override
public Document createSettings(Class<?> clazz) {
public Settings createSettings(Class<?> clazz) {
Assert.notNull(clazz, "clazz must not be null");
Document settings = null;
Setting setting = AnnotatedElementUtils.findMergedAnnotation(clazz, Setting.class);
if (setting != null) {
settings = loadSettings(setting.settingPath());
}
if (settings == null) {
settings = getRequiredPersistentEntity(clazz).getDefaultSettings();
}
return settings;
ElasticsearchPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(clazz);
String settingPath = persistentEntity.settingPath();
return hasText(settingPath) //
? Settings.parse(ResourceUtil.readFileFromClasspath(settingPath)) //
: persistentEntity.getDefaultSettings();
}
@Override
@ -125,16 +111,23 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
}
@Override
public boolean create(Document settings) {
public boolean create(Map<String, Object> settings) {
Assert.notNull(settings, "settings must not be null");
return doCreate(getIndexCoordinates(), settings, null);
}
@Override
public boolean create(Document settings, Document mapping) {
public boolean create(Map<String, Object> settings, Document mapping) {
Assert.notNull(settings, "settings must not be null");
Assert.notNull(mapping, "mapping must not be null");
return doCreate(getIndexCoordinates(), settings, mapping);
}
protected abstract boolean doCreate(IndexCoordinates index, @Nullable Document settings, @Nullable Document mapping);
protected abstract boolean doCreate(IndexCoordinates index, Map<String, Object> settings, @Nullable Document mapping);
@Override
public boolean delete() {
@ -165,16 +158,16 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
abstract protected Map<String, Object> doGetMapping(IndexCoordinates index);
@Override
public Map<String, Object> getSettings() {
public Settings getSettings() {
return getSettings(false);
}
@Override
public Map<String, Object> getSettings(boolean includeDefaults) {
public Settings getSettings(boolean includeDefaults) {
return doGetSettings(getIndexCoordinates(), includeDefaults);
}
protected abstract Map<String, Object> doGetSettings(IndexCoordinates index, boolean includeDefaults);
protected abstract Settings doGetSettings(IndexCoordinates index, boolean includeDefaults);
@Override
public void refresh() {
@ -244,10 +237,10 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
if (mappingAnnotation != null) {
String mappingPath = mappingAnnotation.mappingPath();
if (StringUtils.hasText(mappingPath)) {
if (hasText(mappingPath)) {
String mappings = ResourceUtil.readFileFromClasspath(mappingPath);
if (StringUtils.hasText(mappings)) {
if (hasText(mappings)) {
return Document.parse(mappings);
}
} else {
@ -265,7 +258,7 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
}
@Override
public Document createSettings() {
public Settings createSettings() {
return createSettings(checkForBoundClass());
}
@ -284,19 +277,5 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
public IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
return getRequiredPersistentEntity(clazz).getIndexCoordinates();
}
@Nullable
private Document loadSettings(String settingPath) {
if (hasText(settingPath)) {
String settingsFile = ResourceUtil.readFileFromClasspath(settingPath);
if (hasText(settingsFile)) {
return Document.parse(settingsFile);
}
} else {
LOGGER.info("settingPath in @Setting has to be defined. Using default instead.");
}
return null;
}
// endregion
}

View File

@ -50,6 +50,7 @@ import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest;
import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.AliasQuery;
@ -81,7 +82,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
}
@Override
protected boolean doCreate(IndexCoordinates index, @Nullable Document settings, @Nullable Document mapping) {
protected boolean doCreate(IndexCoordinates index, Map<String, Object> settings, @Nullable Document mapping) {
CreateIndexRequest request = requestFactory.createIndexRequest(index, settings, mapping);
return restTemplate.execute(client -> client.indices().create(request, RequestOptions.DEFAULT).isAcknowledged());
}
@ -192,7 +193,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
}
@Override
protected Map<String, Object> doGetSettings(IndexCoordinates index, boolean includeDefaults) {
protected Settings doGetSettings(IndexCoordinates index, boolean includeDefaults) {
Assert.notNull(index, "index must not be null");

View File

@ -42,7 +42,6 @@ import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.AliasActions;
@ -52,6 +51,7 @@ import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.MappingBuilder;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
@ -106,7 +106,7 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
if (boundClass != null) {
return createSettings(boundClass).flatMap(settings -> doCreate(index, settings, null));
} else {
return doCreate(index, null, null);
return doCreate(index, new Settings(), null);
}
}
@ -119,16 +119,23 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
}
@Override
public Mono<Boolean> create(Document settings) {
public Mono<Boolean> create(Map<String, Object> settings) {
Assert.notNull(settings, "settings must not be null");
return doCreate(getIndexCoordinates(), settings, null);
}
@Override
public Mono<Boolean> create(Document settings, Document mapping) {
throw new UnsupportedOperationException("not implemented");
public Mono<Boolean> create(Map<String, Object> settings, Document mapping) {
Assert.notNull(settings, "settings must not be null");
Assert.notNull(mapping, "mapping must not be null");
return doCreate(getIndexCoordinates(), settings, mapping);
}
private Mono<Boolean> doCreate(IndexCoordinates index, @Nullable Document settings, @Nullable Document mapping) {
private Mono<Boolean> doCreate(IndexCoordinates index, Map<String, Object> settings, @Nullable Document mapping) {
CreateIndexRequest request = requestFactory.createIndexRequest(index, settings, mapping);
return Mono.from(operations.executeWithIndicesClient(client -> client.createIndex(request)));
@ -208,24 +215,25 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
// region settings
@Override
public Mono<Document> createSettings() {
public Mono<Settings> createSettings() {
return createSettings(checkForBoundClass());
}
@Override
public Mono<Document> createSettings(Class<?> clazz) {
public Mono<Settings> createSettings(Class<?> clazz) {
Setting setting = AnnotatedElementUtils.findMergedAnnotation(clazz, Setting.class);
Assert.notNull(clazz, "clazz must not be null");
if (setting != null) {
return loadDocument(setting.settingPath(), "@Setting");
}
return Mono.just(getRequiredPersistentEntity(clazz).getDefaultSettings());
ElasticsearchPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(clazz);
String settingPath = persistentEntity.settingPath();
return hasText(settingPath) //
? loadDocument(settingPath, "@Setting") //
.map(Settings::new) //
: Mono.just(persistentEntity.getDefaultSettings());
}
@Override
public Mono<Document> getSettings(boolean includeDefaults) {
public Mono<Settings> getSettings(boolean includeDefaults) {
String indexName = getIndexCoordinates().getIndexName();
GetSettingsRequest request = requestFactory.getSettingsRequest(indexName, includeDefaults);

View File

@ -46,7 +46,6 @@ import org.elasticsearch.cluster.metadata.IndexTemplateMetadata;
import org.elasticsearch.cluster.metadata.MappingMetadata;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
@ -57,6 +56,7 @@ import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest;
import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.AliasQuery;
@ -90,7 +90,7 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
}
@Override
protected boolean doCreate(IndexCoordinates index, @Nullable Document settings, @Nullable Document mapping) {
protected boolean doCreate(IndexCoordinates index, Map<String, Object> settings, @Nullable Document mapping) {
CreateIndexRequestBuilder createIndexRequestBuilder = requestFactory.createIndexRequestBuilder(client, index,
settings, mapping);
return createIndexRequestBuilder.execute().actionGet().isAcknowledged();
@ -193,7 +193,7 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
}
@Override
protected Map<String, Object> doGetSettings(IndexCoordinates index, boolean includeDefaults) {
protected Settings doGetSettings(IndexCoordinates index, boolean includeDefaults) {
Assert.notNull(index, "index must not be null");
@ -238,8 +238,8 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
if (indexTemplateMetadata.getName().equals(getTemplateRequest.getTemplateName())) {
Document settings = Document.create();
Settings templateSettings = indexTemplateMetadata.settings();
Settings settings = new Settings();
org.elasticsearch.common.settings.Settings templateSettings = indexTemplateMetadata.settings();
templateSettings.keySet().forEach(key -> settings.put(key, templateSettings.get(key)));
Map<String, AliasData> aliases = new LinkedHashMap<>();

View File

@ -20,6 +20,7 @@ import java.util.List;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.lang.Nullable;
/**
@ -31,16 +32,16 @@ import org.springframework.lang.Nullable;
*/
public class IndexInformation {
private final String name;
@Nullable private final Document settings;
@Nullable private final Settings settings;
@Nullable private final Document mapping;
@Nullable private final List<AliasData> aliases;
public static IndexInformation of(String name, @Nullable Document settings, @Nullable Document mapping,
public static IndexInformation of(String name, @Nullable Settings settings, @Nullable Document mapping,
@Nullable List<AliasData> aliases) {
return new IndexInformation(name, settings, mapping, aliases);
}
private IndexInformation(String name, @Nullable Document settings, @Nullable Document mapping,
private IndexInformation(String name, @Nullable Settings settings, @Nullable Document mapping,
@Nullable List<AliasData> aliases) {
this.name = name;
this.settings = settings;
@ -58,7 +59,7 @@ public class IndexInformation {
}
@Nullable
public Document getSettings() {
public Settings getSettings() {
return settings;
}

View File

@ -27,6 +27,7 @@ import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest;
import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.AliasQuery;
@ -60,7 +61,7 @@ public interface IndexOperations {
* @param settings the index settings
* @return {@literal true} if the index was created
*/
boolean create(Document settings);
boolean create(Map<String, Object> settings);
/**
* Create an index for given settings and mapping.
@ -70,7 +71,7 @@ public interface IndexOperations {
* @return {@literal true} if the index was created
* @since 4.2
*/
boolean create(Document settings, Document mapping);
boolean create(Map<String, Object> settings, Document mapping);
/**
* Create an index with the settings and mapping defined for the entity this IndexOperations is bound to.
@ -161,7 +162,7 @@ public interface IndexOperations {
* @return a settings document.
* @since 4.1
*/
Document createSettings();
Settings createSettings();
/**
* Creates the index settings from the annotations on the given class
@ -170,14 +171,14 @@ public interface IndexOperations {
* @return a settings document.
* @since 4.1
*/
Document createSettings(Class<?> clazz);
Settings createSettings(Class<?> clazz);
/**
* Get the index settings.
*
* @return the settings
*/
Map<String, Object> getSettings();
Settings getSettings();
/**
* Get the index settings.
@ -185,7 +186,7 @@ public interface IndexOperations {
* @param includeDefaults whether or not to include all the default settings
* @return the settings
*/
Map<String, Object> getSettings(boolean includeDefaults);
Settings getSettings(boolean includeDefaults);
// endregion
// region aliases

View File

@ -28,6 +28,7 @@ import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest;
import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
@ -56,7 +57,7 @@ public interface ReactiveIndexOperations {
* @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if eg.
* the index already exist.
*/
Mono<Boolean> create(Document settings);
Mono<Boolean> create(Map<String, Object> settings);
/**
* Create an index for given settings and mapping.
@ -67,7 +68,7 @@ public interface ReactiveIndexOperations {
* the index already exist.
* @since 4.2
*/
Mono<Boolean> create(Document settings, Document mapping);
Mono<Boolean> create(Map<String, Object> settings, Document mapping);
/**
* Create an index with the settings and mapping defined for the entity this IndexOperations is bound to.
@ -159,7 +160,7 @@ public interface ReactiveIndexOperations {
* @return a settings document.
* @since 4.1
*/
Mono<Document> createSettings();
Mono<Settings> createSettings();
/**
* Creates the index settings from the annotations on the given class
@ -168,14 +169,14 @@ public interface ReactiveIndexOperations {
* @return a settings document.
* @since 4.1
*/
Mono<Document> createSettings(Class<?> clazz);
Mono<Settings> createSettings(Class<?> clazz);
/**
* get the settings for the index
*
* @return a {@link Mono} with a {@link Document} containing the index settings
*/
default Mono<Document> getSettings() {
default Mono<Settings> getSettings() {
return getSettings(false);
}
@ -185,7 +186,7 @@ public interface ReactiveIndexOperations {
* @param includeDefaults whether or not to include all the default settings
* @return a {@link Mono} with a {@link Document} containing the index settings
*/
Mono<Document> getSettings(boolean includeDefaults);
Mono<Settings> getSettings(boolean includeDefaults);
// endregion
// region aliases

View File

@ -27,6 +27,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.data.elasticsearch.ResourceFailureException;
import org.springframework.util.Assert;
/**
* Utility to reactively read {@link org.springframework.core.io.Resource}s.
@ -47,6 +49,8 @@ public abstract class ReactiveResourceUtil {
*/
public static Mono<String> readFileFromClasspath(String url) {
Assert.notNull(url, "url must not be null");
return DataBufferUtils
.join(DataBufferUtils.read(new ClassPathResource(url), new DefaultDataBufferFactory(), BUFFER_SIZE))
.<String> handle((it, sink) -> {
@ -65,15 +69,12 @@ public abstract class ReactiveResourceUtil {
sink.next(sb.toString());
sink.complete();
} catch (Exception e) {
LOGGER.warn(String.format("Failed to load file from url: %s: %s", url, e.getMessage()));
sink.complete();
} finally {
DataBufferUtils.release(it);
}
}).onErrorResume(throwable -> {
LOGGER.warn(String.format("Failed to load file from url: %s: %s", url, throwable.getMessage()));
return Mono.empty();
});
}).onErrorResume(
throwable -> Mono.error(new ResourceFailureException("Could not load resource from " + url, throwable)));
}
// Utility constructor

View File

@ -355,11 +355,14 @@ class RequestFactory {
// region index management
public CreateIndexRequest createIndexRequest(IndexCoordinates index, @Nullable Document settings,
@Nullable Document mapping) {
public CreateIndexRequest createIndexRequest(IndexCoordinates index, Map<String, Object> settings, @Nullable Document mapping) {
Assert.notNull(index, "index must not be null");
Assert.notNull(settings, "settings must not be null");
CreateIndexRequest request = new CreateIndexRequest(index.getIndexName());
if (settings != null && !settings.isEmpty()) {
if (!settings.isEmpty()) {
request.settings(settings);
}
@ -371,13 +374,15 @@ class RequestFactory {
}
public CreateIndexRequestBuilder createIndexRequestBuilder(Client client, IndexCoordinates index,
@Nullable Document settings, @Nullable Document mapping) {
Map<String, Object> settings, @Nullable Document mapping) {
Assert.notNull(index, "index must not be null");
Assert.notNull(settings, "settings must not be null");
String indexName = index.getIndexName();
CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(indexName);
if (settings != null && !settings.isEmpty()) {
if (!settings.isEmpty()) {
createIndexRequestBuilder.setSettings(settings);
}

View File

@ -18,10 +18,9 @@ package org.springframework.data.elasticsearch.core;
import java.io.InputStream;
import java.nio.charset.Charset;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.lang.Nullable;
import org.springframework.data.elasticsearch.ResourceFailureException;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
/**
@ -33,23 +32,20 @@ import org.springframework.util.StreamUtils;
*/
public abstract class ResourceUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceUtil.class);
/**
* Read a {@link ClassPathResource} into a {@link String}.
*
* @param url url the file url
* @return the contents of the file or null if it could not be read
* @param url url the resource
* @return the contents of the resource
*/
@Nullable
public static String readFileFromClasspath(String url) {
ClassPathResource classPathResource = new ClassPathResource(url);
try (InputStream is = classPathResource.getInputStream()) {
Assert.notNull(url, "url must not be null");
try (InputStream is = new ClassPathResource(url).getInputStream()) {
return StreamUtils.copyToString(is, Charset.defaultCharset());
} catch (Exception e) {
LOGGER.warn(String.format("Failed to load file from url: %s: %s", url, e.getMessage()));
return null;
throw new ResourceFailureException("Could not load resource from " + url, e);
}
}

View File

@ -36,9 +36,9 @@ import org.elasticsearch.cluster.metadata.AliasMetadata;
import org.elasticsearch.cluster.metadata.MappingMetadata;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -91,7 +91,7 @@ public class ResponseConverter {
List<IndexInformation> indexInformationList = new ArrayList<>();
for (String indexName : getIndexResponse.getIndices()) {
Document settings = settingsFromGetIndexResponse(getIndexResponse, indexName);
Settings settings = settingsFromGetIndexResponse(getIndexResponse, indexName);
Document mappings = mappingsFromGetIndexResponse(getIndexResponse, indexName);
List<AliasData> aliases = aliasDataFromIndexResponse(getIndexResponse, indexName);
@ -108,18 +108,18 @@ public class ResponseConverter {
* @param indexName the index name
* @return a document that represents {@link Settings}
*/
private static Document settingsFromGetIndexResponse(GetIndexResponse getIndexResponse, String indexName) {
Document document = Document.create();
private static Settings settingsFromGetIndexResponse(GetIndexResponse getIndexResponse, String indexName) {
Settings settings= new Settings();
Settings indexSettings = getIndexResponse.getSettings().get(indexName);
org.elasticsearch.common.settings.Settings indexSettings = getIndexResponse.getSettings().get(indexName);
if (!indexSettings.isEmpty()) {
for (String key : indexSettings.keySet()) {
document.put(key, indexSettings.get(key));
settings.put(key, indexSettings.get(key));
}
}
return document;
return settings;
}
/**
@ -162,7 +162,7 @@ public class ResponseConverter {
List<IndexInformation> indexInformationList = new ArrayList<>();
for (String indexName : getIndexResponse.getIndices()) {
Document settings = settingsFromGetIndexResponse(getIndexResponse, indexName);
Settings settings = settingsFromGetIndexResponse(getIndexResponse, indexName);
Document mappings = mappingsFromGetIndexResponse(getIndexResponse, indexName);
List<AliasData> aliases = aliasDataFromIndexResponse(getIndexResponse, indexName);
@ -172,19 +172,20 @@ public class ResponseConverter {
return indexInformationList;
}
private static Document settingsFromGetIndexResponse(
private static Settings settingsFromGetIndexResponse(
org.elasticsearch.action.admin.indices.get.GetIndexResponse getIndexResponse, String indexName) {
Document document = Document.create();
Settings settings = new Settings();
if (getIndexResponse.getSettings().containsKey(indexName)) {
Settings indexSettings = getIndexResponse.getSettings().get(indexName);
org.elasticsearch.common.settings.Settings indexSettings = getIndexResponse.getSettings().get(indexName);
for (String key : indexSettings.keySet()) {
document.put(key, indexSettings.get(key));
settings.put(key, indexSettings.get(key));
}
}
return document;
return settings;
}
private static Document mappingsFromGetIndexResponse(
@ -222,8 +223,8 @@ public class ResponseConverter {
if (indexTemplateMetadata.name().equals(templateName)) {
Document settings = Document.create();
Settings templateSettings = indexTemplateMetadata.settings();
Settings settings = new Settings();
org.elasticsearch.common.settings.Settings templateSettings = indexTemplateMetadata.settings();
templateSettings.keySet().forEach(key -> settings.put(key, templateSettings.get(key)));
Map<String, AliasData> aliases = new LinkedHashMap<>();
@ -253,21 +254,21 @@ public class ResponseConverter {
*
* @param response the Elasticsearch response
* @param indexName the index name
* @return settings as {@link Document}
* @return settings
*/
public static Document fromSettingsResponse(GetSettingsResponse response, String indexName) {
public static Settings fromSettingsResponse(GetSettingsResponse response, String indexName) {
Document settings = Document.create();
Settings settings = new Settings();
if (!response.getIndexToDefaultSettings().isEmpty()) {
Settings defaultSettings = response.getIndexToDefaultSettings().get(indexName);
org.elasticsearch.common.settings.Settings defaultSettings = response.getIndexToDefaultSettings().get(indexName);
for (String key : defaultSettings.keySet()) {
settings.put(key, defaultSettings.get(key));
}
}
if (!response.getIndexToSettings().isEmpty()) {
Settings customSettings = response.getIndexToSettings().get(indexName);
org.elasticsearch.common.settings.Settings customSettings = response.getIndexToSettings().get(indexName);
for (String key : customSettings.keySet()) {
settings.put(key, customSettings.get(key));
}

View File

@ -25,11 +25,12 @@ import java.util.function.LongSupplier;
import java.util.function.Supplier;
import org.springframework.data.elasticsearch.core.convert.ConversionException;
import org.springframework.data.elasticsearch.support.StringObjectMap;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* A representation of a Elasticsearch document as extended {@link Map} with {@link String} keys. All iterators preserve
* A representation of a Elasticsearch document as extended {@link StringObjectMap Map}. All iterators preserve
* original insertion order.
* <p>
* Document does not allow {@code null} keys. It allows {@literal null} values.
@ -42,7 +43,7 @@ import org.springframework.util.Assert;
* @author Roman Puchkovskiy
* @since 4.0
*/
public interface Document extends Map<String, Object> {
public interface Document extends StringObjectMap<Document> {
/**
* Create a new mutable {@link Document}.
@ -80,25 +81,19 @@ public interface Document extends Map<String, Object> {
Assert.notNull(json, "JSON must not be null");
return new MapDocument().fromJson(json);
}
@Override
default Document fromJson(String json) {
Assert.notNull(json, "JSON must not be null");
clear();
try {
return new MapDocument(MapDocument.OBJECT_MAPPER.readerFor(Map.class).readValue(json));
putAll(MapDocument.OBJECT_MAPPER.readerFor(Map.class).readValue(json));
} catch (IOException e) {
throw new ConversionException("Cannot parse JSON", e);
}
}
/**
* {@link #put(Object, Object)} the {@code key}/{@code value} tuple and return {@code this} {@link Document}.
*
* @param key key with which the specified value is to be associated. must not be {@literal null}.
* @param value value to be associated with the specified key.
* @return {@code this} {@link Document}.
*/
default Document append(String key, Object value) {
Assert.notNull(key, "Key must not be null");
put(key, value);
return this;
}
@ -122,7 +117,7 @@ public interface Document extends Map<String, Object> {
/**
* Sets the index name for this document
*
*
* @param index index name
* <p>
* The default implementation throws {@link UnsupportedOperationException}.
@ -251,212 +246,6 @@ public interface Document extends Map<String, Object> {
throw new UnsupportedOperationException();
}
/**
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
* mapping for the key. The value is casted within the method which makes it useful for calling code as it does not
* require casting on the calling side. If the value type is not assignable to {@code type}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @param type the expected return value type.
* @param <T> expected return type.
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
* the key.
* @throws ClassCastException if the value of the given key is not of {@code type T}.
*/
@Nullable
default <T> T get(Object key, Class<T> type) {
Assert.notNull(key, "Key must not be null");
Assert.notNull(type, "Type must not be null");
return type.cast(get(key));
}
/**
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
* mapping for the key. If the value type is not a {@link Boolean}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
* the key.
* @throws ClassCastException if the value of the given key is not a {@link Boolean}.
*/
@Nullable
default Boolean getBoolean(String key) {
return get(key, Boolean.class);
}
/**
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
* mapping for the key. If the value type is not a {@link Boolean}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
* for the key.
* @throws ClassCastException if the value of the given key is not a {@link Boolean}.
*/
default boolean getBooleanOrDefault(String key, boolean defaultValue) {
return getBooleanOrDefault(key, () -> defaultValue);
}
/**
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
* document contains no mapping for the key. If the value type is not a {@link Boolean}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
* contains no mapping for the key.
* @throws ClassCastException if the value of the given key is not a {@link Boolean}.
* @see BooleanSupplier
*/
default boolean getBooleanOrDefault(String key, BooleanSupplier defaultValue) {
Boolean value = getBoolean(key);
return value == null ? defaultValue.getAsBoolean() : value;
}
/**
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
* mapping for the key. If the value type is not a {@link Integer}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
* the key.
* @throws ClassCastException if the value of the given key is not a {@link Integer}.
*/
@Nullable
default Integer getInt(String key) {
return get(key, Integer.class);
}
/**
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
* mapping for the key. If the value type is not a {@link Integer}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
* for the key.
* @throws ClassCastException if the value of the given key is not a {@link Integer}.
*/
default int getIntOrDefault(String key, int defaultValue) {
return getIntOrDefault(key, () -> defaultValue);
}
/**
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
* document contains no mapping for the key. If the value type is not a {@link Integer}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
* contains no mapping for the key.
* @throws ClassCastException if the value of the given key is not a {@link Integer}.
* @see IntSupplier
*/
default int getIntOrDefault(String key, IntSupplier defaultValue) {
Integer value = getInt(key);
return value == null ? defaultValue.getAsInt() : value;
}
/**
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
* mapping for the key. If the value type is not a {@link Long}, then this method throws {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
* the key.
* @throws ClassCastException if the value of the given key is not a {@link Long}.
*/
@Nullable
default Long getLong(String key) {
return get(key, Long.class);
}
/**
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
* mapping for the key. If the value type is not a {@link Long}, then this method throws {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
* for the key.
* @throws ClassCastException if the value of the given key is not a {@link Long}.
*/
default long getLongOrDefault(String key, long defaultValue) {
return getLongOrDefault(key, () -> defaultValue);
}
/**
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
* document contains no mapping for the key. If the value type is not a {@link Long}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
* contains no mapping for the key.
* @throws ClassCastException if the value of the given key is not a {@link Long}.
* @see LongSupplier
*/
default long getLongOrDefault(String key, LongSupplier defaultValue) {
Long value = getLong(key);
return value == null ? defaultValue.getAsLong() : value;
}
/**
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
* mapping for the key. If the value type is not a {@link String}, then this method throws {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
* the key.
* @throws ClassCastException if the value of the given key is not a {@link String}.
*/
@Nullable
default String getString(String key) {
return get(key, String.class);
}
/**
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
* mapping for the key. If the value type is not a {@link String}, then this method throws {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
* for the key.
* @throws ClassCastException if the value of the given key is not a {@link String}.
*/
default String getStringOrDefault(String key, String defaultValue) {
return getStringOrDefault(key, () -> defaultValue);
}
/**
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
* document contains no mapping for the key. If the value type is not a {@link String}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
* contains no mapping for the key.
* @throws ClassCastException if the value of the given key is not a {@link String}.
* @see Supplier
*/
default String getStringOrDefault(String key, Supplier<String> defaultValue) {
String value = getString(key);
return value == null ? defaultValue.get() : value;
}
/**
* This method allows the application of a function to {@code this} {@link Document}. The function should expect a
* single {@link Document} argument and produce an {@code R} result.
@ -474,13 +263,4 @@ public interface Document extends Map<String, Object> {
return transformer.apply(this);
}
/**
* Render this {@link Document} to JSON. Auxiliary values such as Id and version are not considered within the JSON
* representation.
*
* @return a JSON representation of this document.
*/
String toJson();
}

View File

@ -458,6 +458,7 @@ public class DocumentAdapters {
}
}
@Override
public String toString() {
return getClass().getSimpleName() + '@' + this.id + '#' + this.version + ' ' + toJson();

View File

@ -21,6 +21,8 @@ import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import org.springframework.data.elasticsearch.support.DefaultStringObjectMap;
import org.springframework.data.elasticsearch.support.StringObjectMap;
import org.springframework.data.mapping.MappingException;
import org.springframework.lang.Nullable;
@ -38,7 +40,7 @@ class MapDocument implements Document {
static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final LinkedHashMap<String, Object> documentAsMap;
private final DefaultStringObjectMap<?> documentAsMap;
private @Nullable String index;
private @Nullable String id;
@ -50,8 +52,8 @@ class MapDocument implements Document {
this(new LinkedHashMap<>());
}
MapDocument(Map<String, ? extends Object> documentAsMap) {
this.documentAsMap = new LinkedHashMap<>(documentAsMap);
MapDocument(Map<String, ?> documentAsMap) {
this.documentAsMap = new DefaultStringObjectMap<>(documentAsMap);
}
@Override

View File

@ -19,6 +19,8 @@ import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.util.Map;
/**
* Request to create an index template. This is to create legacy templates (@see
* https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates-v1.html)
@ -29,13 +31,13 @@ import org.springframework.util.Assert;
public class PutTemplateRequest {
private final String name;
private final String[] indexPatterns;
@Nullable final private Document settings;
@Nullable final private Settings settings;
@Nullable final private Document mappings;
@Nullable final AliasActions aliasActions;
private final int order;
@Nullable final Integer version;
private PutTemplateRequest(String name, String[] indexPatterns, @Nullable Document settings,
private PutTemplateRequest(String name, String[] indexPatterns, @Nullable Settings settings,
@Nullable Document mappings, @Nullable AliasActions aliasActions, int order, @Nullable Integer version) {
this.name = name;
this.indexPatterns = indexPatterns;
@ -55,7 +57,7 @@ public class PutTemplateRequest {
}
@Nullable
public Document getSettings() {
public Settings getSettings() {
return settings;
}
@ -85,7 +87,7 @@ public class PutTemplateRequest {
public static final class TemplateRequestBuilder {
private final String name;
private final String[] indexPatterns;
@Nullable private Document settings;
@Nullable private Settings settings;
@Nullable private Document mappings;
@Nullable AliasActions aliasActions;
private int order = 0;
@ -100,8 +102,8 @@ public class PutTemplateRequest {
this.indexPatterns = indexPatterns;
}
public TemplateRequestBuilder withSettings(Document settings) {
this.settings = settings;
public TemplateRequestBuilder withSettings(Map<String, Object> settings) {
this.settings = new Settings(settings);
return this;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2021 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.index;
import org.springframework.data.elasticsearch.support.DefaultStringObjectMap;
import java.util.Map;
/**
* class defining the settings for an index.
*
* @author Peter-Josef Meisch
* @since 4.2
*/
public class Settings extends DefaultStringObjectMap<Settings> {
public Settings() {
}
public Settings(Map<String, Object> map) {
super(map);
}
/**
* Creates a {@link Settings} object from the given JSON String
* @param json must not be {@literal null}
* @return Settings object
*/
public static Settings parse(String json) {
return new Settings().fromJson(json);
}
@Override
public String toString() {
return "Settings: " + toJson();
}
}

View File

@ -27,13 +27,13 @@ import org.springframework.lang.Nullable;
*/
public class TemplateData {
@Nullable private final String[] indexPatterns;
@Nullable Document settings;
@Nullable Settings settings;
@Nullable Document mapping;
@Nullable private final Map<String, AliasData> aliases;
int order;
@Nullable Integer version;
private TemplateData(@Nullable String[] indexPatterns, @Nullable Document settings, @Nullable Document mapping,
private TemplateData(@Nullable String[] indexPatterns, @Nullable Settings settings, @Nullable Document mapping,
@Nullable Map<String, AliasData> aliases, int order, @Nullable Integer version) {
this.indexPatterns = indexPatterns;
this.settings = settings;
@ -53,7 +53,7 @@ public class TemplateData {
}
@Nullable
public Document getSettings() {
public Settings getSettings() {
return settings;
}
@ -77,7 +77,7 @@ public class TemplateData {
}
public static final class TemplateDataBuilder {
@Nullable Document settings;
@Nullable Settings settings;
@Nullable Document mapping;
int order;
@Nullable Integer version;
@ -91,8 +91,8 @@ public class TemplateData {
return this;
}
public TemplateDataBuilder withSettings(Document settings) {
this.settings = settings;
public TemplateDataBuilder withSettings(Map<String, Object> settings) {
this.settings = new Settings(settings);
return this;
}

View File

@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core.mapping;
import org.elasticsearch.index.VersionType;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.join.JoinField;
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
import org.springframework.data.mapping.PersistentEntity;
@ -148,14 +149,14 @@ public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, El
/**
* returns the default settings for an index.
*
* @return settings as {@link Document}
* @return settings
* @since 4.1
*/
Document getDefaultSettings();
Settings getDefaultSettings();
/**
* Resolves the routing for a bean.
*
*
* @param bean the bean to resolve the routing for
* @return routing value, may be {@literal null}
*/

View File

@ -19,16 +19,18 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.index.VersionType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Parent;
import org.springframework.data.elasticsearch.annotations.Routing;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.join.JoinField;
import org.springframework.data.mapping.MappingException;
import org.springframework.data.mapping.PropertyHandler;
@ -66,16 +68,11 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
private static final SpelExpressionParser PARSER = new SpelExpressionParser();
private @Nullable String indexName;
private boolean useServerConfiguration;
private short shards;
private short replicas;
private @Nullable String refreshInterval;
private @Nullable String indexStoreType;
private final Lazy<SettingsParameter> settingsParameter;
@Deprecated private @Nullable String parentType;
@Deprecated private @Nullable ElasticsearchPersistentProperty parentIdProperty;
private @Nullable ElasticsearchPersistentProperty seqNoPrimaryTermProperty;
private @Nullable ElasticsearchPersistentProperty joinFieldProperty;
private @Nullable String settingPath;
private @Nullable VersionType versionType;
private boolean createIndexAndMapping;
private final Map<String, ElasticsearchPersistentProperty> fieldNamePropertyCache = new ConcurrentHashMap<>();
@ -90,27 +87,20 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
super(typeInformation);
Class<T> clazz = typeInformation.getType();
org.springframework.data.elasticsearch.annotations.Document document = AnnotatedElementUtils
.findMergedAnnotation(clazz, org.springframework.data.elasticsearch.annotations.Document.class);
// need a Lazy here, because we need the persistent properties available
this.settingsParameter = Lazy.of(() -> buildSettingsParameter(clazz));
if (document != null) {
Assert.hasText(document.indexName(),
" Unknown indexName. Make sure the indexName is defined. e.g @Document(indexName=\"foo\")");
this.indexName = document.indexName();
this.useServerConfiguration = document.useServerConfiguration();
this.shards = document.shards();
this.replicas = document.replicas();
this.refreshInterval = document.refreshInterval();
this.indexStoreType = document.indexStoreType();
this.versionType = document.versionType();
this.createIndexAndMapping = document.createIndex();
Setting setting = AnnotatedElementUtils.getMergedAnnotation(clazz, Setting.class);
if (setting != null) {
this.settingPath = setting.settingPath();
}
}
Routing routingAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Routing.class);
@ -135,28 +125,28 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
@Nullable
@Override
public String getIndexStoreType() {
return indexStoreType;
return settingsParameter.get().indexStoreType;
}
@Override
public short getShards() {
return shards;
return settingsParameter.get().shards;
}
@Override
public short getReplicas() {
return replicas;
return settingsParameter.get().replicas;
}
@Override
public boolean isUseServerConfiguration() {
return useServerConfiguration;
return settingsParameter.get().useServerConfiguration;
}
@Nullable
@Override
public String getRefreshInterval() {
return refreshInterval;
return settingsParameter.get().refreshIntervall;
}
@Nullable
@ -179,11 +169,6 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
return versionType;
}
@Override
public String settingPath() {
return settingPath;
}
@Override
public boolean isCreateIndexAndMapping() {
return createIndexAndMapping;
@ -207,7 +192,10 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
Parent parentAnnotation = property.findAnnotation(Parent.class);
this.parentIdProperty = property;
this.parentType = parentAnnotation.type();
if (parentAnnotation != null) {
this.parentType = parentAnnotation.type();
}
}
if (property.isSeqNoPrimaryTermProperty()) {
@ -407,17 +395,167 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
// endregion
// region index settings
@Override
public Document getDefaultSettings() {
public String settingPath() {
return settingsParameter.get().settingPath;
}
if (isUseServerConfiguration()) {
return Document.create();
@Override
public Settings getDefaultSettings() {
return settingsParameter.get().toSettings(); //
}
private SettingsParameter buildSettingsParameter(Class<?> clazz) {
SettingsParameter settingsParameter = new SettingsParameter();
Document documentAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Document.class);
Setting settingAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Setting.class);
if (documentAnnotation != null) {
settingsParameter.useServerConfiguration = documentAnnotation.useServerConfiguration();
settingsParameter.shards = documentAnnotation.shards();
settingsParameter.replicas = documentAnnotation.replicas();
settingsParameter.refreshIntervall = documentAnnotation.refreshInterval();
settingsParameter.indexStoreType = documentAnnotation.indexStoreType();
}
Map<String, String> map = new MapBuilder<String, String>()
.put("index.number_of_shards", String.valueOf(getShards()))
.put("index.number_of_replicas", String.valueOf(getReplicas()))
.put("index.refresh_interval", getRefreshInterval()).put("index.store.type", getIndexStoreType()).map();
return Document.from(map);
if (settingAnnotation != null) {
processSettingAnnotation(settingAnnotation, settingsParameter);
}
return settingsParameter;
}
private void processSettingAnnotation(Setting settingAnnotation, SettingsParameter settingsParameter) {
settingsParameter.useServerConfiguration = settingAnnotation.useServerConfiguration();
settingsParameter.settingPath = settingAnnotation.settingPath();
settingsParameter.shards = settingAnnotation.shards();
settingsParameter.replicas = settingAnnotation.replicas();
settingsParameter.refreshIntervall = settingAnnotation.refreshInterval();
settingsParameter.indexStoreType = settingAnnotation.indexStoreType();
String[] sortFields = settingAnnotation.sortFields();
if (sortFields.length > 0) {
String[] fieldNames = new String[sortFields.length];
int index = 0;
for (String propertyName : sortFields) {
ElasticsearchPersistentProperty property = getPersistentProperty(propertyName);
if (property == null) {
throw new IllegalArgumentException("sortField property " + propertyName + " not found");
}
Field fieldAnnotation = property.getRequiredAnnotation(Field.class);
FieldType fieldType = fieldAnnotation.type();
switch (fieldType) {
case Boolean:
case Long:
case Integer:
case Short:
case Byte:
case Float:
case Half_Float:
case Scaled_Float:
case Date:
case Date_Nanos:
case Keyword:
break;
default:
throw new IllegalArgumentException("field type " + fieldType + " not allowed for sortField");
}
if (!fieldAnnotation.docValues()) {
throw new IllegalArgumentException("doc_values must be set to true for sortField");
}
fieldNames[index++] = property.getFieldName();
}
settingsParameter.sortFields = fieldNames;
Setting.SortOrder[] sortOrders = settingAnnotation.sortOrders();
if (sortOrders.length > 0) {
if (sortOrders.length != sortFields.length) {
throw new IllegalArgumentException("@Settings parameter sortFields and sortOrders must have the same size");
}
settingsParameter.sortOrders = sortOrders;
}
Setting.SortMode[] sortModes = settingAnnotation.sortModes();
if (sortModes.length > 0) {
if (sortModes.length != sortFields.length) {
throw new IllegalArgumentException("@Settings parameter sortFields and sortModes must have the same size");
}
settingsParameter.sortModes = sortModes;
}
Setting.SortMissing[] sortMissingValues = settingAnnotation.sortMissingValues();
if (sortMissingValues.length > 0) {
if (sortMissingValues.length != sortFields.length) {
throw new IllegalArgumentException(
"@Settings parameter sortFields and sortMissingValues must have the same size");
}
settingsParameter.sortMissingValues = sortMissingValues;
}
}
}
/**
* internal class to collect settings values from the {@link Document} and {@link Setting} annotations-
*/
private static class SettingsParameter {
boolean useServerConfiguration = false;
@Nullable String settingPath;
short shards;
short replicas;
@Nullable String refreshIntervall;
@Nullable String indexStoreType;
@Nullable private String[] sortFields;
@Nullable private Setting.SortOrder[] sortOrders;
@Nullable private Setting.SortMode[] sortModes;
@Nullable private Setting.SortMissing[] sortMissingValues;
Settings toSettings() {
if (useServerConfiguration) {
return new Settings();
}
Settings settings = new Settings() //
.append("index.number_of_shards", String.valueOf(shards))
.append("index.number_of_replicas", String.valueOf(replicas));
if (refreshIntervall != null) {
settings.append("index.refresh_interval", refreshIntervall);
}
if (indexStoreType != null) {
settings.append("index.store.type", indexStoreType);
}
if (sortFields != null && sortFields.length > 0) {
settings.append("index.sort.field", sortFields);
if (sortOrders != null && sortOrders.length > 0) {
settings.append("index.sort.order", sortOrders);
}
if (sortModes != null && sortModes.length > 0) {
settings.append("index.sort.mode", sortModes);
}
if (sortMissingValues != null && sortMissingValues.length > 0) {
settings.append("index.sort.missing", sortMissingValues);
}
}
return settings; //
}
}
// endregion
}

View File

@ -0,0 +1,153 @@
/*
* Copyright 2021 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.support;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import org.springframework.util.Assert;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* @author Peter-Josef Meisch
*/
public class DefaultStringObjectMap<T extends StringObjectMap<T>> implements StringObjectMap<T> {
static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final LinkedHashMap<String, Object> delegate;
public DefaultStringObjectMap() {
this(new LinkedHashMap<>());
}
public DefaultStringObjectMap(Map<String, ? extends Object> map) {
this.delegate = new LinkedHashMap<>(map);
}
@Override
public String toJson() {
try {
return OBJECT_MAPPER.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Cannot render document to JSON", e);
}
}
@Override
public T fromJson(String json) {
Assert.notNull(json, "JSON must not be null");
delegate.clear();
try {
delegate.putAll(OBJECT_MAPPER.readerFor(Map.class).readValue(json));
} catch (IOException e) {
throw new IllegalArgumentException("Cannot parse JSON", e);
}
return (T) this;
}
@Override
public int size() {
return delegate.size();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return delegate.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return delegate.containsValue(value);
}
@Override
public Object get(Object key) {
return delegate.get(key);
}
@Override
public Object getOrDefault(Object key, Object defaultValue) {
return delegate.getOrDefault(key, defaultValue);
}
@Override
public Object put(String key, Object value) {
return delegate.put(key, value);
}
@Override
public Object remove(Object key) {
return delegate.remove(key);
}
@Override
public void putAll(Map<? extends String, ?> m) {
delegate.putAll(m);
}
@Override
public void clear() {
delegate.clear();
}
@Override
public Set<String> keySet() {
return delegate.keySet();
}
@Override
public Collection<Object> values() {
return delegate.values();
}
@Override
public Set<Entry<String, Object>> entrySet() {
return delegate.entrySet();
}
@Override
public boolean equals(Object o) {
return delegate.equals(o);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public void forEach(BiConsumer<? super String, ? super Object> action) {
delegate.forEach(action);
}
@Override
public String toString() {
return "DefaultStringObjectMap: " + toJson();
}
}

View File

@ -0,0 +1,278 @@
/*
* Copyright 2021 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.support;
import java.util.Map;
import java.util.function.BooleanSupplier;
import java.util.function.IntSupplier;
import java.util.function.LongSupplier;
import java.util.function.Supplier;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Defines an interface for a Map&lt;String, Object> with additional convenience methods. All iterators must preserve
* original insertion order.
* <p>
* StringObjectMap does not allow {@code null} keys. It allows {@literal null} values.
* <p>
* Implementing classes can bei either mutable or immutable. In case a subclass is immutable, its methods may throw
* {@link UnsupportedOperationException} when calling modifying methods. *
*
* @param <M> the type extending this interface
* @author Peter-Josef Meisch
* @since 4.2
*/
public interface StringObjectMap<M extends StringObjectMap<M>> extends Map<String, Object> {
/**
* {@link #put(Object, Object)} the {@code key}/{@code value} tuple and return {@code this} object.
*
* @param key key with which the specified value is to be associated. must not be {@literal null}.
* @param value value to be associated with the specified key.
* @return {@code this} object.
*/
default M append(String key, Object value) {
Assert.notNull(key, "Key must not be null");
put(key, value);
// noinspection unchecked
return (M) this;
}
/**
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
* mapping for the key. The value is casted within the method which makes it useful for calling code as it does not
* require casting on the calling side. If the value type is not assignable to {@code type}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @param type the expected return value type.
* @param <T> expected return type.
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
* the key.
* @throws ClassCastException if the value of the given key is not of {@code type T}.
*/
@Nullable
default <T> T get(Object key, Class<T> type) {
Assert.notNull(key, "Key must not be null");
Assert.notNull(type, "Type must not be null");
return type.cast(get(key));
}
/**
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
* mapping for the key. If the value type is not a {@link Boolean}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
* the key.
* @throws ClassCastException if the value of the given key is not a {@link Boolean}.
*/
@Nullable
default Boolean getBoolean(String key) {
return get(key, Boolean.class);
}
/**
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
* mapping for the key. If the value type is not a {@link Boolean}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
* for the key.
* @throws ClassCastException if the value of the given key is not a {@link Boolean}.
*/
default boolean getBooleanOrDefault(String key, boolean defaultValue) {
return getBooleanOrDefault(key, () -> defaultValue);
}
/**
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
* document contains no mapping for the key. If the value type is not a {@link Boolean}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
* contains no mapping for the key.
* @throws ClassCastException if the value of the given key is not a {@link Boolean}.
* @see BooleanSupplier
*/
default boolean getBooleanOrDefault(String key, BooleanSupplier defaultValue) {
Boolean value = getBoolean(key);
return value == null ? defaultValue.getAsBoolean() : value;
}
/**
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
* mapping for the key. If the value type is not a {@link Integer}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
* the key.
* @throws ClassCastException if the value of the given key is not a {@link Integer}.
*/
@Nullable
default Integer getInt(String key) {
return get(key, Integer.class);
}
/**
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
* mapping for the key. If the value type is not a {@link Integer}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
* for the key.
* @throws ClassCastException if the value of the given key is not a {@link Integer}.
*/
default int getIntOrDefault(String key, int defaultValue) {
return getIntOrDefault(key, () -> defaultValue);
}
/**
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
* document contains no mapping for the key. If the value type is not a {@link Integer}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
* contains no mapping for the key.
* @throws ClassCastException if the value of the given key is not a {@link Integer}.
* @see IntSupplier
*/
default int getIntOrDefault(String key, IntSupplier defaultValue) {
Integer value = getInt(key);
return value == null ? defaultValue.getAsInt() : value;
}
/**
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
* mapping for the key. If the value type is not a {@link Long}, then this method throws {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
* the key.
* @throws ClassCastException if the value of the given key is not a {@link Long}.
*/
@Nullable
default Long getLong(String key) {
return get(key, Long.class);
}
/**
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
* mapping for the key. If the value type is not a {@link Long}, then this method throws {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
* for the key.
* @throws ClassCastException if the value of the given key is not a {@link Long}.
*/
default long getLongOrDefault(String key, long defaultValue) {
return getLongOrDefault(key, () -> defaultValue);
}
/**
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
* document contains no mapping for the key. If the value type is not a {@link Long}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
* contains no mapping for the key.
* @throws ClassCastException if the value of the given key is not a {@link Long}.
* @see LongSupplier
*/
default long getLongOrDefault(String key, LongSupplier defaultValue) {
Long value = getLong(key);
return value == null ? defaultValue.getAsLong() : value;
}
/**
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
* mapping for the key. If the value type is not a {@link String}, then this method throws {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
* the key.
* @throws ClassCastException if the value of the given key is not a {@link String}.
*/
@Nullable
default String getString(String key) {
return get(key, String.class);
}
/**
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
* mapping for the key. If the value type is not a {@link String}, then this method throws {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
* for the key.
* @throws ClassCastException if the value of the given key is not a {@link String}.
*/
default String getStringOrDefault(String key, String defaultValue) {
return getStringOrDefault(key, () -> defaultValue);
}
/**
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
* document contains no mapping for the key. If the value type is not a {@link String}, then this method throws
* {@link ClassCastException}.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
* contains no mapping for the key.
* @throws ClassCastException if the value of the given key is not a {@link String}.
* @see Supplier
*/
default String getStringOrDefault(String key, Supplier<String> defaultValue) {
String value = getString(key);
return value == null ? defaultValue.get() : value;
}
/**
* Render this {@link Document} to JSON. Auxiliary values such as Id and version are not considered within the JSON
* representation.
*
* @return a JSON representation of this document.
*/
String toJson();
/**
* initializes this object from the given JSON String.
*
* @param json must not be {@literal null}
*/
M fromJson(String json);
}

View File

@ -381,7 +381,7 @@ public class NestedObjectTests {
assertThat(books.getSearchHit(0).getContent().getId()).isEqualTo(book2.getId());
}
@Document(indexName = "test-index-book-nested-objects", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-book-nested-objects")
static class Book {
@Nullable @Id private String id;
@ -438,7 +438,7 @@ public class NestedObjectTests {
}
}
@Document(indexName = "test-index-person", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-person")
static class Person {
@Nullable @Id private String id;
@Nullable private String name;
@ -505,7 +505,7 @@ public class NestedObjectTests {
}
}
@Document(indexName = "test-index-person-multiple-level-nested", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-person-multiple-level-nested")
static class PersonMultipleLevelNested {
@Nullable @Id private String id;
@Nullable private String name;

View File

@ -26,6 +26,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.time.LocalDate;
import org.elasticsearch.index.VersionType;
import org.json.JSONException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@ -57,7 +58,7 @@ public class ComposableAnnotationsUnitTest {
assertThat(entity.getIndexCoordinates()).isEqualTo(IndexCoordinates.of("test-no-create"));
assertThat(entity.isCreateIndexAndMapping()).isFalse();
assertThat(entity.getShards()).isEqualTo((short) 42);
assertThat(entity.getVersionType()).isEqualTo(VersionType.INTERNAL);
}
@Test // DATAES-362
@ -105,7 +106,7 @@ public class ComposableAnnotationsUnitTest {
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Document(indexName = "", createIndex = false, shards = 42)
@Document(indexName = "", createIndex = false, versionType = VersionType.INTERNAL)
public @interface DocumentNoCreate {
@AliasFor(value = "indexName", annotation = Document.class)

View File

@ -73,7 +73,7 @@ public class EnableNestedElasticsearchRepositoriesTests {
assertThat(nestedRepository).isNotNull();
}
@Document(indexName = "test-index-sample-config-nested", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-config-nested")
static class SampleEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;

View File

@ -120,7 +120,7 @@ public class EnableElasticsearchRepositoriesTests implements ApplicationContextA
assertThat(nestedRepository).isNull();
}
@Document(indexName = "test-index-sample-config-not-nested", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-config-not-nested")
static class SampleEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;
@ -212,7 +212,7 @@ public class EnableElasticsearchRepositoriesTests implements ApplicationContextA
}
}
@Document(indexName = "test-index-uuid-keyed-config-not-nested", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-uuid-keyed-config-not-nested")
static class SampleEntityUUIDKeyed {
@Nullable @Id private UUID id;
@Nullable private String type;

View File

@ -79,7 +79,7 @@ public class ElasticsearchRestTemplateTests extends ElasticsearchTemplateTests {
.isInstanceOf(UncategorizedElasticsearchException.class);
}
@Document(indexName = "test-index-sample-core-rest-template", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-core-rest-template")
static class SampleEntity {
@Nullable @Id private String id;
@Nullable

View File

@ -83,6 +83,7 @@ import org.springframework.data.elasticsearch.annotations.JoinTypeRelation;
import org.springframework.data.elasticsearch.annotations.JoinTypeRelations;
import org.springframework.data.elasticsearch.annotations.MultiField;
import org.springframework.data.elasticsearch.annotations.ScriptedField;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.document.Explanation;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.data.elasticsearch.core.index.AliasAction;
@ -3006,7 +3007,7 @@ public abstract class ElasticsearchTemplateTests {
assertThat(aliases).isEmpty();
}
@Document(indexName = INDEX_2_NAME, replicas = 0)
@Document(indexName = INDEX_2_NAME)
class ResultAggregator {
private String id;
@ -3750,7 +3751,8 @@ public abstract class ElasticsearchTemplateTests {
assertThat(explanation).isNotNull();
}
@Document(indexName = INDEX_NAME_SAMPLE_ENTITY, replicas = 0, refreshInterval = "-1")
@Document(indexName = INDEX_NAME_SAMPLE_ENTITY)
@Setting(shards = 1, replicas = 0, refreshInterval = "-1")
static class SampleEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;
@ -3928,7 +3930,7 @@ public abstract class ElasticsearchTemplateTests {
}
}
@Document(indexName = "test-index-uuid-keyed-core-template", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-uuid-keyed-core-template")
private static class SampleEntityUUIDKeyed {
@Nullable @Id private UUID id;
@Nullable private String type;
@ -4010,7 +4012,7 @@ public abstract class ElasticsearchTemplateTests {
}
}
@Document(indexName = "test-index-book-core-template", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-book-core-template")
static class Book {
@Nullable @Id private String id;
@Nullable private String name;
@ -4139,8 +4141,7 @@ public abstract class ElasticsearchTemplateTests {
}
}
@Document(indexName = "test-index-version-core-template", replicas = 0, refreshInterval = "-1",
versionType = VersionType.EXTERNAL_GTE)
@Document(indexName = "test-index-version-core-template", versionType = VersionType.EXTERNAL_GTE)
private static class GTEVersionEntity {
@Nullable @Version private Long version;
@Nullable @Id private String id;
@ -4174,7 +4175,7 @@ public abstract class ElasticsearchTemplateTests {
}
}
@Document(indexName = "test-index-hetro1-core-template", replicas = 0)
@Document(indexName = "test-index-hetro1-core-template")
static class HetroEntity1 {
@Nullable @Id private String id;
@Nullable private String firstName;
@ -4214,7 +4215,7 @@ public abstract class ElasticsearchTemplateTests {
}
}
@Document(indexName = "test-index-hetro2-core-template", replicas = 0)
@Document(indexName = "test-index-hetro2-core-template")
static class HetroEntity2 {
@Nullable @Id private String id;
@ -4255,8 +4256,8 @@ public abstract class ElasticsearchTemplateTests {
}
}
@Document(indexName = "test-index-server-configuration", useServerConfiguration = true, shards = 10, replicas = 10,
refreshInterval = "-1")
@Document(indexName = "test-index-server-configuration")
@Setting(useServerConfiguration = true, shards = 10, replicas = 10, refreshInterval = "-1")
private static class UseServerConfigurationEntity {
@Nullable @Id private String id;
@ -4281,7 +4282,7 @@ public abstract class ElasticsearchTemplateTests {
}
}
@Document(indexName = "test-index-sample-mapping", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-mapping")
static class SampleMappingEntity {
@Nullable @Id private String id;

View File

@ -195,7 +195,7 @@ public class ElasticsearchTransportTemplateTests extends ElasticsearchTemplateTe
assertThat(request.request().getScript().getType()).isEqualTo(org.elasticsearch.script.ScriptType.STORED);
}
@Document(indexName = "test-index-sample-core-transport-template", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-core-transport-template")
static class SampleEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;

View File

@ -132,7 +132,7 @@ public class LogEntityTests {
/**
* Simple type to test facets
*/
@Document(indexName = "test-index-log-core", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-log-core")
static class LogEntity {
private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

View File

@ -1257,7 +1257,7 @@ public class ReactiveElasticsearchTemplateIntegrationTests {
}
}
@Document(indexName = DEFAULT_INDEX, replicas = 0, refreshInterval = "-1")
@Document(indexName = DEFAULT_INDEX)
static class SampleEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String message;

View File

@ -250,7 +250,7 @@ public class ReactiveElasticsearchTemplateUnitTests {
assertThat(captor.getValue().indicesOptions()).isEqualTo(IndicesOptions.LENIENT_EXPAND_OPEN);
}
@Document(indexName = "test-index-sample-core-reactive-template-Unit", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-core-reactive-template-Unit")
static class SampleEntity {
@Nullable @Id private String id;

View File

@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core;
import static org.assertj.core.api.Assertions.*;
import static org.skyscreamer.jsonassert.JSONAssert.*;
import org.springframework.data.elasticsearch.core.index.Settings;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@ -390,8 +391,7 @@ public class ReactiveIndexOperationsTest {
org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class)
.block();
org.springframework.data.elasticsearch.core.document.Document settings = indexOps
.createSettings(TemplateClass.class).block();
Settings settings = indexOps .createSettings(TemplateClass.class).block();
AliasActions aliasActions = new AliasActions(
new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build()));
@ -423,8 +423,7 @@ public class ReactiveIndexOperationsTest {
org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class)
.block();
org.springframework.data.elasticsearch.core.document.Document settings = indexOps
.createSettings(TemplateClass.class).block();
Settings settings = indexOps .createSettings(TemplateClass.class).block();
AliasActions aliasActions = new AliasActions(
new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build()));
@ -505,7 +504,8 @@ public class ReactiveIndexOperationsTest {
assertThat(exists).isFalse();
}
@Document(indexName = TESTINDEX, shards = 3, replicas = 2, refreshInterval = "4s")
@Document(indexName = TESTINDEX)
@Setting(shards = 3, replicas = 2, refreshInterval = "4s")
static class Entity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Text) private String text;
@ -540,7 +540,8 @@ public class ReactiveIndexOperationsTest {
}
}
@Document(indexName = TESTINDEX, useServerConfiguration = true)
@Document(indexName = TESTINDEX)
@Setting(useServerConfiguration = true)
static class EntityUseServerConfig {
@Nullable @Id private String id;
@ -570,7 +571,8 @@ public class ReactiveIndexOperationsTest {
}
}
@Document(indexName = "test-template", shards = 3, replicas = 2, refreshInterval = "5s")
@Document(indexName = "test-template")
@Setting(refreshInterval = "5s")
static class TemplateClass {
@Id @Nullable private String id;
@Field(type = FieldType.Text) @Nullable private String message;

View File

@ -60,9 +60,9 @@ class ReactiveResourceUtilTest {
}
@Test
void shouldReturnEmptyMonoOnNonExistingResource() {
void shouldErrorOnNonExistingResource() {
ReactiveResourceUtil.readFileFromClasspath("/this/should/really/not/exist") //
.as(StepVerifier::create) //
.verifyComplete();
.verifyError();
}
}

View File

@ -151,7 +151,7 @@ public class SearchAsYouTypeTests {
/**
* @author Aleksei Arsenev
*/
@Document(indexName = "test-index-core-search-as-you-type", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-core-search-as-you-type")
static class SearchAsYouTypeEntity {
public SearchAsYouTypeEntity(@Nonnull String id) {

View File

@ -130,7 +130,7 @@ public class ElasticsearchTemplateAggregationTests {
assertThat(searchHits.hasSearchHits()).isFalse();
}
@Document(indexName = "test-index-articles-core-aggregation", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-articles-core-aggregation")
static class ArticleEntity {
@Nullable @Id private String id;

View File

@ -248,7 +248,7 @@ public class ElasticsearchTemplateCompletionTests {
/**
* @author Mewes Kochheim
*/
@Document(indexName = "test-index-core-completion", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-core-completion")
static class CompletionEntity {
@Nullable @Id private String id;
@ -334,7 +334,7 @@ public class ElasticsearchTemplateCompletionTests {
/**
* @author Mewes Kochheim
*/
@Document(indexName = "test-index-annotated-completion", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-annotated-completion")
static class AnnotatedCompletionEntity {
@Nullable @Id private String id;

View File

@ -244,7 +244,7 @@ public class ElasticsearchTemplateCompletionWithContextsTests {
* @author Mewes Kochheim
* @author Robert Gruendler
*/
@Document(indexName = "test-index-context-completion", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-context-completion")
static class ContextCompletionEntity {
public static final String LANGUAGE_CATEGORY = "language";

View File

@ -1792,8 +1792,7 @@ public class MappingElasticsearchConverterUnitTests {
}
}
@org.springframework.data.elasticsearch.annotations.Document(indexName = "test-index-geo-core-entity-mapper",
replicas = 0, refreshInterval = "-1")
@org.springframework.data.elasticsearch.annotations.Document(indexName = "test-index-geo-core-entity-mapper")
static class GeoEntity {
@Nullable @Id private String id;
// geo shape - Spring Data

View File

@ -361,7 +361,7 @@ public class ElasticsearchTemplateGeoTests {
* @author Franck Marchand
* @author Mohsin Husen
*/
@Document(indexName = "test-index-author-marker-core-geo", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-author-marker-core-geo")
static class AuthorMarkerEntity {
@Nullable @Id private String id;
@Nullable private String name;
@ -436,7 +436,7 @@ public class ElasticsearchTemplateGeoTests {
}
}
@Document(indexName = "test-index-location-marker-core-geo", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-location-marker-core-geo")
static class LocationMarkerEntity {
@Nullable @Id private String id;
@Nullable private String name;

View File

@ -122,9 +122,9 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
IndexCoordinates index = IndexCoordinates.of("test-index-stock-mapping-builder");
StockPrice stockPrice = new StockPrice(); //
stockPrice.setId(id);
stockPrice.setSymbol(symbol);
stockPrice.setPrice(BigDecimal.valueOf(price));
stockPrice.setId(id);
stockPrice.setSymbol(symbol);
stockPrice.setPrice(BigDecimal.valueOf(price));
operations.index(buildIndex(stockPrice), index);
operations.indexOps(StockPrice.class).refresh();
@ -384,7 +384,7 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-book-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-book-mapping-builder")
static class Book {
@Nullable @Id private String id;
@Nullable private String name;
@ -440,7 +440,7 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-simple-recursive-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-simple-recursive-mapping-builder")
static class SimpleRecursiveEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Object,
@ -465,7 +465,7 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-copy-to-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-copy-to-mapping-builder")
static class CopyToEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Keyword, copyTo = "name") private String firstName;
@ -509,7 +509,7 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-normalizer-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-normalizer-mapping-builder")
@Setting(settingPath = "/settings/test-normalizer.json")
static class NormalizerEntity {
@Nullable @Id private String id;
@ -569,7 +569,7 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-sample-inherited-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-inherited-mapping-builder")
static class SampleInheritedEntity extends AbstractInheritedEntity {
@Nullable @Field(type = Text, index = false, store = true, analyzer = "standard") private String message;
@ -615,7 +615,7 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-stock-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-stock-mapping-builder")
static class StockPrice {
@Nullable @Id private String id;
@Nullable private String symbol;
@ -652,35 +652,41 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
static class AbstractInheritedEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Date, format = DateFormat.date_time, index = false) private Date createdDate;
@Nullable public String getId() {
@Nullable
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Nullable public Date getCreatedDate() {
@Nullable
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
}
@Document(indexName = "test-index-geo-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-geo-mapping-builder")
static class GeoEntity {
@Nullable @Id private String id;
// geo shape - Spring Data
@Nullable private Box box;
@Nullable private Circle circle;
@Nullable private Polygon polygon;
// geo point - Custom implementation + Spring Data
@Nullable @GeoPointField private Point pointA;
@Nullable private GeoPoint pointB;
@Nullable @GeoPointField private String pointC;
@Nullable @GeoPointField private double[] pointD;
// geo shape, until e have the classes for this, us a strng
@Nullable @GeoShapeField private String shape1;
@Nullable @GeoShapeField(coerce = true, ignoreMalformed = true, ignoreZValue = false,
@Nullable @Id private String id;
// geo shape - Spring Data
@Nullable private Box box;
@Nullable private Circle circle;
@Nullable private Polygon polygon;
// geo point - Custom implementation + Spring Data
@Nullable @GeoPointField private Point pointA;
@Nullable private GeoPoint pointB;
@Nullable @GeoPointField private String pointC;
@Nullable @GeoPointField private double[] pointD;
// geo shape, until e have the classes for this, us a strng
@Nullable @GeoShapeField private String shape1;
@Nullable @GeoShapeField(coerce = true, ignoreMalformed = true, ignoreZValue = false,
orientation = GeoShapeField.Orientation.clockwise) private String shape2;
@Nullable
@ -890,7 +896,8 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Nullable @Field(type = FieldType.Text, termVector = TermVector.yes) private String yes;
@Nullable @Field(type = FieldType.Text, termVector = TermVector.with_positions) private String with_positions;
@Nullable @Field(type = FieldType.Text, termVector = TermVector.with_offsets) private String with_offsets;
@Nullable @Field(type = FieldType.Text, termVector = TermVector.with_positions_offsets) private String with_positions_offsets;
@Nullable @Field(type = FieldType.Text,
termVector = TermVector.with_positions_offsets) private String with_positions_offsets;
@Nullable @Field(type = FieldType.Text,
termVector = TermVector.with_positions_payloads) private String with_positions_payloads;
@Nullable @Field(type = FieldType.Text,

View File

@ -731,7 +731,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-book-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-book-mapping-builder")
static class Book {
@Nullable @Id private String id;
@Nullable private String name;
@ -787,7 +787,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-simple-recursive-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-simple-recursive-mapping-builder")
static class SimpleRecursiveEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Object,
@ -812,7 +812,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-copy-to-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-copy-to-mapping-builder")
static class CopyToEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Keyword, copyTo = "name") private String firstName;
@ -856,7 +856,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-normalizer-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-normalizer-mapping-builder")
@Setting(settingPath = "/settings/test-normalizer.json")
static class NormalizerEntity {
@Nullable @Id private String id;
@ -915,7 +915,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-sample-inherited-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-inherited-mapping-builder")
static class SampleInheritedEntity extends AbstractInheritedEntity {
@Nullable @Field(type = Text, index = false, store = true, analyzer = "standard") private String message;
@ -930,7 +930,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-stock-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-stock-mapping-builder")
static class StockPrice {
@Nullable @Id private String id;
@Nullable private String symbol;
@ -989,7 +989,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-recursive-mapping-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-recursive-mapping-mapping-builder")
static class SampleTransientEntity {
@Nullable @Id private String id;
@ -1040,7 +1040,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
}
}
@Document(indexName = "test-index-geo-mapping-builder", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-geo-mapping-builder")
static class GeoEntity {
@Nullable @Id private String id;
// geo shape - Spring Data

View File

@ -27,6 +27,7 @@ import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.DynamicTemplates;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.MappingContextBaseTests;
import org.springframework.lang.Nullable;
@ -66,7 +67,8 @@ public class SimpleDynamicTemplatesMappingTests extends MappingContextBaseTests
/**
* @author Petr Kukral
*/
@Document(indexName = "test-dynamictemplates", indexStoreType = "memory", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-dynamictemplates")
@Setting(indexStoreType = "memory")
@DynamicTemplates(mappingPath = "/mappings/test-dynamic_templates_mappings.json")
static class SampleDynamicTemplatesEntity {
@ -78,7 +80,8 @@ public class SimpleDynamicTemplatesMappingTests extends MappingContextBaseTests
/**
* @author Petr Kukral
*/
@Document(indexName = "test-dynamictemplates", indexStoreType = "memory", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-dynamictemplates")
@Setting(indexStoreType = "memory")
@DynamicTemplates(mappingPath = "/mappings/test-dynamic_templates_mappings_two.json")
static class SampleDynamicTemplatesEntityTwo {

View File

@ -51,7 +51,7 @@ public class SimpleElasticsearchDateMappingTests extends MappingContextBaseTests
assertEquals(EXPECTED_MAPPING, mapping, false);
}
@Document(indexName = "test-index-date-mapping-core", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-date-mapping-core")
static class SampleDateMappingEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, index = false, store = true, analyzer = "standard") private String message;

View File

@ -28,6 +28,7 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
@ -51,8 +52,7 @@ public class TemplateTests {
IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care"));
org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class);
org.springframework.data.elasticsearch.core.document.Document settings = indexOps
.createSettings(TemplateClass.class);
Settings settings = indexOps.createSettings(TemplateClass.class);
AliasActions aliasActions = new AliasActions(
new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build()));
@ -84,8 +84,7 @@ public class TemplateTests {
IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care"));
org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class);
org.springframework.data.elasticsearch.core.document.Document settings = indexOps
.createSettings(TemplateClass.class);
Settings settings = indexOps.createSettings(TemplateClass.class);
AliasActions aliasActions = new AliasActions(
new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build()));
@ -166,7 +165,8 @@ public class TemplateTests {
}
@Document(indexName = "test-template", shards = 3, replicas = 2, refreshInterval = "5s")
@Document(indexName = "test-template")
@Setting(shards = 3)
static class TemplateClass {
@Id @Nullable private String id;
@Field(type = FieldType.Text) @Nullable private String message;

View File

@ -16,14 +16,18 @@
package org.springframework.data.elasticsearch.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.skyscreamer.jsonassert.JSONAssert.*;
import org.json.JSONException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.MappingContextBaseTests;
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
import org.springframework.data.mapping.MappingException;
@ -44,116 +48,162 @@ import org.springframework.util.ReflectionUtils;
*/
public class SimpleElasticsearchPersistentEntityTests extends MappingContextBaseTests {
@Test
public void shouldThrowExceptionGivenVersionPropertyIsNotLong() {
// given
TypeInformation typeInformation = ClassTypeInformation.from(EntityWithWrongVersionType.class);
SimpleElasticsearchPersistentEntity<EntityWithWrongVersionType> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
// when
assertThatThrownBy(() -> {
SimpleElasticsearchPersistentProperty persistentProperty = createProperty(entity, "version");
}).isInstanceOf(MappingException.class);
@Nested
@DisplayName("properties setup")
class PropertiesTests {
@Test
public void shouldThrowExceptionGivenVersionPropertyIsNotLong() {
TypeInformation<EntityWithWrongVersionType> typeInformation = ClassTypeInformation
.from(EntityWithWrongVersionType.class);
SimpleElasticsearchPersistentEntity<EntityWithWrongVersionType> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
assertThatThrownBy(() -> createProperty(entity, "version")).isInstanceOf(MappingException.class);
}
@Test
public void shouldThrowExceptionGivenMultipleVersionPropertiesArePresent() {
TypeInformation<EntityWithMultipleVersionField> typeInformation = ClassTypeInformation
.from(EntityWithMultipleVersionField.class);
SimpleElasticsearchPersistentEntity<EntityWithMultipleVersionField> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
SimpleElasticsearchPersistentProperty persistentProperty1 = createProperty(entity, "version1");
SimpleElasticsearchPersistentProperty persistentProperty2 = createProperty(entity, "version2");
entity.addPersistentProperty(persistentProperty1);
assertThatThrownBy(() -> entity.addPersistentProperty(persistentProperty2)).isInstanceOf(MappingException.class);
}
@Test
void shouldFindPropertiesByMappedName() {
SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext();
SimpleElasticsearchPersistentEntity<?> persistentEntity = context
.getRequiredPersistentEntity(FieldNameEntity.class);
ElasticsearchPersistentProperty persistentProperty = persistentEntity
.getPersistentPropertyWithFieldName("renamed-field");
assertThat(persistentProperty).isNotNull();
assertThat(persistentProperty.getName()).isEqualTo("renamedField");
assertThat(persistentProperty.getFieldName()).isEqualTo("renamed-field");
}
@Test
// DATAES-799
void shouldReportThatThereIsNoSeqNoPrimaryTermPropertyWhenThereIsNoSuchProperty() {
TypeInformation<EntityWithoutSeqNoPrimaryTerm> typeInformation = ClassTypeInformation
.from(EntityWithoutSeqNoPrimaryTerm.class);
SimpleElasticsearchPersistentEntity<EntityWithoutSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
assertThat(entity.hasSeqNoPrimaryTermProperty()).isFalse();
}
@Test
// DATAES-799
void shouldReportThatThereIsSeqNoPrimaryTermPropertyWhenThereIsSuchProperty() {
TypeInformation<EntityWithSeqNoPrimaryTerm> typeInformation = ClassTypeInformation
.from(EntityWithSeqNoPrimaryTerm.class);
SimpleElasticsearchPersistentEntity<EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm"));
assertThat(entity.hasSeqNoPrimaryTermProperty()).isTrue();
}
@Test
// DATAES-799
void shouldReturnSeqNoPrimaryTermPropertyWhenThereIsSuchProperty() {
TypeInformation<EntityWithSeqNoPrimaryTerm> typeInformation = ClassTypeInformation
.from(EntityWithSeqNoPrimaryTerm.class);
SimpleElasticsearchPersistentEntity<EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm"));
EntityWithSeqNoPrimaryTerm instance = new EntityWithSeqNoPrimaryTerm();
SeqNoPrimaryTerm seqNoPrimaryTerm = new SeqNoPrimaryTerm(1, 2);
ElasticsearchPersistentProperty property = entity.getSeqNoPrimaryTermProperty();
assertThat(property).isNotNull();
entity.getPropertyAccessor(instance).setProperty(property, seqNoPrimaryTerm);
assertThat(instance.seqNoPrimaryTerm).isSameAs(seqNoPrimaryTerm);
}
@Test
// DATAES-799
void shouldNotAllowMoreThanOneSeqNoPrimaryTermProperties() {
TypeInformation<EntityWithSeqNoPrimaryTerm> typeInformation = ClassTypeInformation
.from(EntityWithSeqNoPrimaryTerm.class);
SimpleElasticsearchPersistentEntity<EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm"));
assertThatThrownBy(() -> entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm2")))
.isInstanceOf(MappingException.class);
}
@Test // #1680
@DisplayName("should allow fields with id property names")
void shouldAllowFieldsWithIdPropertyNames() {
elasticsearchConverter.get().getMappingContext().getRequiredPersistentEntity(EntityWithIdNameFields.class);
}
}
@Test
public void shouldThrowExceptionGivenMultipleVersionPropertiesArePresent() {
// given
TypeInformation typeInformation = ClassTypeInformation.from(EntityWithMultipleVersionField.class);
SimpleElasticsearchPersistentEntity<EntityWithMultipleVersionField> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
@Nested
@DisplayName("index settings")
class SettingsTests {
SimpleElasticsearchPersistentProperty persistentProperty1 = createProperty(entity, "version1");
@Test // #1719
@DisplayName("should error if index sorting parameters do not have the same number of arguments")
void shouldErrorIfIndexSortingParametersDoNotHaveTheSameNumberOfArguments() {
SimpleElasticsearchPersistentProperty persistentProperty2 = createProperty(entity, "version2");
assertThatThrownBy(() -> {
elasticsearchConverter.get().getMappingContext()
.getRequiredPersistentEntity(SettingsInvalidSortParameterSizes.class).getDefaultSettings();
}).isInstanceOf(IllegalArgumentException.class);
}
entity.addPersistentProperty(persistentProperty1);
// when
assertThatThrownBy(() -> {
entity.addPersistentProperty(persistentProperty2);
}).isInstanceOf(MappingException.class);
}
@Test
void shouldFindPropertiesByMappedName() {
SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext();
SimpleElasticsearchPersistentEntity<?> persistentEntity = context
.getRequiredPersistentEntity(FieldNameEntity.class);
ElasticsearchPersistentProperty persistentProperty = persistentEntity
.getPersistentPropertyWithFieldName("renamed-field");
assertThat(persistentProperty).isNotNull();
assertThat(persistentProperty.getName()).isEqualTo("renamedField");
assertThat(persistentProperty.getFieldName()).isEqualTo("renamed-field");
}
@Test // DATAES-799
void shouldReportThatThereIsNoSeqNoPrimaryTermPropertyWhenThereIsNoSuchProperty() {
TypeInformation<EntityWithoutSeqNoPrimaryTerm> typeInformation = ClassTypeInformation
.from(EntityWithoutSeqNoPrimaryTerm.class);
SimpleElasticsearchPersistentEntity<EntityWithoutSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
assertThat(entity.hasSeqNoPrimaryTermProperty()).isFalse();
}
@Test // DATAES-799
void shouldReportThatThereIsSeqNoPrimaryTermPropertyWhenThereIsSuchProperty() {
TypeInformation<EntityWithSeqNoPrimaryTerm> typeInformation = ClassTypeInformation
.from(EntityWithSeqNoPrimaryTerm.class);
SimpleElasticsearchPersistentEntity<EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm"));
assertThat(entity.hasSeqNoPrimaryTermProperty()).isTrue();
}
@Test // DATAES-799
void shouldReturnSeqNoPrimaryTermPropertyWhenThereIsSuchProperty() {
TypeInformation<EntityWithSeqNoPrimaryTerm> typeInformation = ClassTypeInformation
.from(EntityWithSeqNoPrimaryTerm.class);
SimpleElasticsearchPersistentEntity<EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm"));
EntityWithSeqNoPrimaryTerm instance = new EntityWithSeqNoPrimaryTerm();
SeqNoPrimaryTerm seqNoPrimaryTerm = new SeqNoPrimaryTerm(1, 2);
ElasticsearchPersistentProperty property = entity.getSeqNoPrimaryTermProperty();
entity.getPropertyAccessor(instance).setProperty(property, seqNoPrimaryTerm);
assertThat(instance.seqNoPrimaryTerm).isSameAs(seqNoPrimaryTerm);
}
@Test // DATAES-799
void shouldNotAllowMoreThanOneSeqNoPrimaryTermProperties() {
TypeInformation<EntityWithSeqNoPrimaryTerm> typeInformation = ClassTypeInformation
.from(EntityWithSeqNoPrimaryTerm.class);
SimpleElasticsearchPersistentEntity<EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>(
typeInformation);
entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm"));
assertThatThrownBy(() -> entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm2")))
.isInstanceOf(MappingException.class);
}
@Test // #1680
@DisplayName("should allow fields with id property names")
void shouldAllowFieldsWithIdPropertyNames() {
elasticsearchConverter.get().getMappingContext().getRequiredPersistentEntity(EntityWithIdNameFields.class);
@Test // #1719
@DisplayName("should write sort parameters to Settings object")
void shouldWriteSortParametersToSettingsObject() throws JSONException {
String expected = "{\n" + //
" \"index.sort.field\": [\"second_field\", \"first_field\"],\n" + //
" \"index.sort.mode\": [\"max\", \"min\"],\n" + //
" \"index.sort.order\": [\"desc\",\"asc\"],\n" + //
" \"index.sort.missing\": [\"_last\",\"_first\"]\n" + //
"}\n"; //
ElasticsearchPersistentEntity<?> entity = elasticsearchConverter.get().getMappingContext()
.getRequiredPersistentEntity(SettingsValidSortParameterSizes.class);
String json = entity.getDefaultSettings().toJson();
assertEquals(expected, json, false);
}
}
// region helper functions
private static SimpleElasticsearchPersistentProperty createProperty(SimpleElasticsearchPersistentEntity<?> entity,
String field) {
String fieldName) {
TypeInformation<?> type = entity.getTypeInformation();
Property property = Property.of(type, ReflectionUtils.findField(entity.getType(), field));
java.lang.reflect.Field field = ReflectionUtils.findField(entity.getType(), fieldName);
assertThat(field).isNotNull();
Property property = Property.of(type, field);
return new SimpleElasticsearchPersistentProperty(property, entity, SimpleTypeHolder.DEFAULT, null);
}
// endregion
// region entities
private static class EntityWithWrongVersionType {
@Nullable @Version private String version;
@ -168,6 +218,7 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase
}
}
@SuppressWarnings("unused")
private static class EntityWithMultipleVersionField {
@Nullable @Version private Long version1;
@ -192,6 +243,7 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase
}
}
@SuppressWarnings("unused")
private static class FieldNameEntity {
@Nullable @Id private String id;
@Nullable @Field(name = "renamed-field") private String renamedField;
@ -199,15 +251,40 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase
private static class EntityWithoutSeqNoPrimaryTerm {}
@SuppressWarnings("unused")
private static class EntityWithSeqNoPrimaryTerm {
private SeqNoPrimaryTerm seqNoPrimaryTerm;
private SeqNoPrimaryTerm seqNoPrimaryTerm2;
@Nullable private SeqNoPrimaryTerm seqNoPrimaryTerm;
@Nullable private SeqNoPrimaryTerm seqNoPrimaryTerm2;
}
@SuppressWarnings("unused")
@Document(indexName = "fieldnames")
private static class EntityWithIdNameFields {
@Id private String theRealId;
@Field(type = FieldType.Text, name = "document") private String document;
@Field(name = "id") private String renamedId;
@Nullable @Id private String theRealId;
@Nullable @Field(type = FieldType.Text, name = "document") private String document;
@Nullable @Field(name = "id") private String renamedId;
}
@Document(indexName = "dontcare")
@Setting(sortFields = { "first-field", "second-field" }, sortModes = { Setting.SortMode.max },
sortOrders = { Setting.SortOrder.asc },
sortMissingValues = { Setting.SortMissing._last, Setting.SortMissing._last, Setting.SortMissing._first })
private static class SettingsInvalidSortParameterSizes {
@Nullable @Id private String id;
@Nullable @Field(name = "first-field", type = FieldType.Keyword) private String firstField;
@Nullable @Field(name = "second-field", type = FieldType.Keyword) private String secondField;
}
@Document(indexName = "dontcare")
// property names here, not field names
@Setting(sortFields = { "secondField", "firstField" }, sortModes = { Setting.SortMode.max, Setting.SortMode.min },
sortOrders = { Setting.SortOrder.desc, Setting.SortOrder.asc },
sortMissingValues = { Setting.SortMissing._last, Setting.SortMissing._first })
private static class SettingsValidSortParameterSizes {
@Nullable @Id private String id;
@Nullable @Field(name = "first_field", type = FieldType.Keyword) private String firstField;
@Nullable @Field(name = "second_field", type = FieldType.Keyword) private String secondField;
}
// endregion
}

View File

@ -797,17 +797,15 @@ public class CriteriaQueryIntegrationTests {
assertThat(sampleEntity1).isNotNull();
}
@Document(indexName = "test-index-sample-core-query", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-core-query")
static class SampleEntity {
@Nullable
@Id private String id;
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;
@Nullable @Field(type = Text, store = true, fielddata = true) private String message;
@Nullable private int rate;
@Nullable @Version private Long version;
public SampleEntity() {
}
public SampleEntity() {}
public SampleEntity(@Nullable String id, @Nullable String message) {
this.id = id;

View File

@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Routing;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
@ -117,7 +118,8 @@ public class ElasticsearchOperationsRoutingTests {
assertThat(searchHits.getSearchHit(0).getRouting()).isEqualTo(ID_2);
}
@Document(indexName = INDEX, shards = 5)
@Document(indexName = INDEX)
@Setting(shards = 5)
@Routing("routing")
static class RoutingEntity {
@Nullable @Id private String id;

View File

@ -29,6 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Routing;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ReactiveIndexOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
@ -115,7 +116,8 @@ public class ReactiveElasticsearchOperationsRoutingTests {
assertThat(searchHits.get(0).getRouting()).isEqualTo(ID_2);
}
@Document(indexName = INDEX, shards = 5)
@Document(indexName = INDEX)
@Setting(shards = 5)
@Routing("routing")
static class RoutingEntity {
@Nullable @Id private String id;

View File

@ -157,7 +157,7 @@ public class CdiRepositoryTests {
* @author Mohsin Husen
* @author Artur Konczak
*/
@Document(indexName = "test-index-product-cdi-repository", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-product-cdi-repository")
static class Product {
@Nullable @Id private String id;
@Nullable private List<String> title;
@ -280,7 +280,7 @@ public class CdiRepositoryTests {
}
}
@Document(indexName = "test-index-person-cdi-repository", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-person-cdi-repository")
static class Person {
@Id private String id;
@ -293,7 +293,7 @@ public class CdiRepositoryTests {
}
@Document(indexName = "test-index-book-cdi-repository", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-book-cdi-repository")
static class Book {
@Nullable @Id private String id;
@Nullable private String name;

View File

@ -79,11 +79,9 @@ public class ComplexCustomMethodRepositoryTests {
assertThat(result).isEqualTo("2+2=4");
}
@Document(indexName = "test-index-sample-repositories-complex-custommethod-autowiring", replicas = 0,
refreshInterval = "-1")
@Document(indexName = "test-index-sample-repositories-complex-custommethod-autowiring")
static class SampleEntity {
@Nullable
@Id private String id;
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;
@Nullable @Field(type = Text, store = true, fielddata = true) private String message;

View File

@ -77,7 +77,7 @@ public class ComplexCustomMethodRepositoryManualWiringTests {
assertThat(result).isEqualTo("3+3=6");
}
@Document(indexName = "test-index-sample-repository-manual-wiring", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-repository-manual-wiring")
static class SampleEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;

View File

@ -1631,7 +1631,7 @@ public abstract class CustomMethodRepositoryBaseTests {
assertThat(count).isEqualTo(20);
}
@Document(indexName = "test-index-sample-repositories-custom-method", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-repositories-custom-method")
static class SampleEntity {
@Nullable
@Id private String id;

View File

@ -121,7 +121,7 @@ public class DoubleIDRepositoryTests {
* @author Mohsin Husen
*/
@Document(indexName = "test-index-double-keyed-entity", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-double-keyed-entity")
static class DoubleIDEntity {
@Id private Double id;

View File

@ -110,7 +110,7 @@ public class SpringDataGeoRepositoryTests {
return new double[] { point.getX(), point.getY() };
}
@Document(indexName = "test-index-geo-repository", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-geo-repository")
static class GeoEntity {
@Nullable @Id private String id;
// geo shape - Spring Data

View File

@ -122,7 +122,7 @@ public class IntegerIDRepositoryTests {
* @author Mohsin Husen
*/
@Document(indexName = "test-index-integer-keyed-entity", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-integer-keyed-entity")
static class IntegerIDEntity {
@Id private Integer id;

View File

@ -96,7 +96,7 @@ public class InnerObjectTests {
assertThat(bookRepository.findById(id)).isNotNull();
}
@Document(indexName = "test-index-book", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-book")
static class Book {
@Nullable @Id private String id;
@Nullable private String name;

View File

@ -103,7 +103,7 @@ public class SpELEntityTests {
*
* @author Artur Konczak
*/
@Document(indexName = "#{'test-index-abz'+'-'+'entity'}", replicas = 0, refreshInterval = "-1")
@Document(indexName = "#{'test-index-abz'+'-'+'entity'}")
static class SpELEntity {
@Id private String id;

View File

@ -545,7 +545,7 @@ public class UUIDElasticsearchRepositoryTests {
return sampleEntities;
}
@Document(indexName = "test-index-uuid-keyed", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-uuid-keyed")
static class SampleEntityUUIDKeyed {
@Nullable @Id private UUID id;
@Nullable private String type;

View File

@ -58,7 +58,7 @@ public class ReactiveElasticsearchRepositoriesRegistrarTests {
interface ReactiveSampleEntityRepository extends ReactiveElasticsearchRepository<SampleEntity, String> {}
@Document(indexName = "test-index-sample-reactive-repositories-registrar", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-reactive-repositories-registrar")
static class SampleEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;

View File

@ -118,7 +118,7 @@ public class ElasticsearchStringQueryUnitTests {
* @author Artur Konczak
*/
@Document(indexName = "test-index-person-query-unittest", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-person-query-unittest")
static class Person {
@Nullable @Id private String id;
@ -163,7 +163,7 @@ public class ElasticsearchStringQueryUnitTests {
}
}
@Document(indexName = "test-index-book-query-unittest", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-book-query-unittest")
static class Book {
@Nullable @Id private String id;
@Nullable private String name;

View File

@ -166,7 +166,7 @@ public class ReactiveElasticsearchQueryMethodUnitTests {
* @author Artur Konczak
*/
@Document(indexName = INDEX_NAME, replicas = 0, refreshInterval = "-1")
@Document(indexName = INDEX_NAME)
static class Person {
@Nullable @Id private String id;
@ -215,7 +215,7 @@ public class ReactiveElasticsearchQueryMethodUnitTests {
}
}
@Document(indexName = "test-index-book-reactive-repository-query", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-book-reactive-repository-query")
static class Book {
@Nullable @Id private String id;
@Nullable private String name;

View File

@ -171,7 +171,7 @@ public class ReactiveElasticsearchStringQueryUnitTests {
* @author Artur Konczak
*/
@Document(indexName = "test-index-person-reactive-repository-string-query", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-person-reactive-repository-string-query")
public class Person {
@Nullable @Id private String id;
@ -219,7 +219,7 @@ public class ReactiveElasticsearchStringQueryUnitTests {
}
}
@Document(indexName = "test-index-book-reactive-repository-string-query", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-book-reactive-repository-string-query")
static class Book {
@Nullable @Id private String id;
@Nullable private String name;

View File

@ -273,7 +273,7 @@ class QueryKeywordsTests {
assertThat(products).isEmpty();
}
@Document(indexName = "test-index-product-query-keywords", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-product-query-keywords")
static class Product {
@Nullable @Id private String id;
@Nullable private String name;

View File

@ -677,7 +677,7 @@ class SimpleElasticsearchRepositoryIntegrationTests {
return sampleEntities;
}
@Document(indexName = "test-index-sample-simple-repository", replicas = 0, refreshInterval = "-1")
@Document(indexName = "test-index-sample-simple-repository")
static class SampleEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;

View File

@ -608,7 +608,7 @@ class SimpleReactiveElasticsearchRepositoryTests {
Mono<Long> retrieveCountByText(String message);
}
@Document(indexName = INDEX, replicas = 0, refreshInterval = "-1")
@Document(indexName = INDEX)
static class SampleEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;