mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-29 15:22:11 +00:00
parent
ff381c63b6
commit
11a6430a90
@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import static org.springframework.util.StringUtils.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.collect.MapBuilder;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||||
|
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.index.MappingBuilder;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base implementation of {@link IndexOperations} common to Transport and Rest based Implementations of IndexOperations.
|
||||||
|
*
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
abstract class AbstractDefaultIndexOperations implements IndexOperations {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDefaultIndexOperations.class);
|
||||||
|
|
||||||
|
protected final ElasticsearchConverter elasticsearchConverter;
|
||||||
|
protected final RequestFactory requestFactory;
|
||||||
|
|
||||||
|
public AbstractDefaultIndexOperations(ElasticsearchConverter elasticsearchConverter) {
|
||||||
|
this.elasticsearchConverter = elasticsearchConverter;
|
||||||
|
requestFactory = new RequestFactory(elasticsearchConverter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// region IndexOperations
|
||||||
|
@Override
|
||||||
|
public boolean createIndex(String indexName) {
|
||||||
|
return createIndex(indexName, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createIndex(Class<?> clazz) {
|
||||||
|
|
||||||
|
String indexName = getRequiredPersistentEntity(clazz).getIndexCoordinates().getIndexName();
|
||||||
|
if (clazz.isAnnotationPresent(Setting.class)) {
|
||||||
|
String settingPath = clazz.getAnnotation(Setting.class).settingPath();
|
||||||
|
|
||||||
|
if (hasText(settingPath)) {
|
||||||
|
String settings = ResourceUtil.readFileFromClasspath(settingPath);
|
||||||
|
|
||||||
|
if (hasText(settings)) {
|
||||||
|
return createIndex(indexName, settings);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGGER.info("settingPath in @Setting has to be defined. Using default instead.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return createIndex(indexName, getDefaultSettings(getRequiredPersistentEntity(clazz)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createIndex(Class<?> clazz, Object settings) {
|
||||||
|
return createIndex(getRequiredPersistentEntity(clazz).getIndexCoordinates().getIndexName(), settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteIndex(Class<?> clazz) {
|
||||||
|
return deleteIndex(getRequiredPersistentEntity(clazz).getIndexCoordinates().getIndexName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean indexExists(Class<?> clazz) {
|
||||||
|
return indexExists(getIndexCoordinatesFor(clazz).getIndexName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getMapping(Class<?> clazz) {
|
||||||
|
return getMapping(getIndexCoordinatesFor(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean putMapping(Class<?> clazz) {
|
||||||
|
return putMapping(clazz, buildMapping(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> boolean putMapping(Class<T> clazz, Object mapping) {
|
||||||
|
return putMapping(getIndexCoordinatesFor(clazz), mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean putMapping(IndexCoordinates index, Class<?> clazz) {
|
||||||
|
return putMapping(index, buildMapping(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getSetting(Class<?> clazz) {
|
||||||
|
return getSetting(getRequiredPersistentEntity(clazz).getIndexCoordinates().getIndexName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh(Class<?> clazz) {
|
||||||
|
refresh(getIndexCoordinatesFor(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String buildMapping(Class<?> clazz) {
|
||||||
|
|
||||||
|
// load mapping specified in Mapping annotation if present
|
||||||
|
if (clazz.isAnnotationPresent(Mapping.class)) {
|
||||||
|
String mappingPath = clazz.getAnnotation(Mapping.class).mappingPath();
|
||||||
|
|
||||||
|
if (!StringUtils.isEmpty(mappingPath)) {
|
||||||
|
String mappings = ResourceUtil.readFileFromClasspath(mappingPath);
|
||||||
|
|
||||||
|
if (!StringUtils.isEmpty(mappings)) {
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGGER.info("mappingPath in @Mapping has to be defined. Building mappings using @Field");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build mapping from field annotations
|
||||||
|
try {
|
||||||
|
return new MappingBuilder(elasticsearchConverter).buildPropertyMapping(clazz);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ElasticsearchException("Failed to build mapping for " + clazz.getSimpleName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Helper functions
|
||||||
|
private <T> Map getDefaultSettings(ElasticsearchPersistentEntity<T> persistentEntity) {
|
||||||
|
|
||||||
|
if (persistentEntity.isUseServerConfiguration())
|
||||||
|
return new HashMap();
|
||||||
|
|
||||||
|
return new MapBuilder<String, String>().put("index.number_of_shards", String.valueOf(persistentEntity.getShards()))
|
||||||
|
.put("index.number_of_replicas", String.valueOf(persistentEntity.getReplicas()))
|
||||||
|
.put("index.refresh_interval", persistentEntity.getRefreshInterval())
|
||||||
|
.put("index.store.type", persistentEntity.getIndexStoreType()).map();
|
||||||
|
}
|
||||||
|
|
||||||
|
ElasticsearchPersistentEntity<?> getRequiredPersistentEntity(Class<?> clazz) {
|
||||||
|
return elasticsearchConverter.getMappingContext().getRequiredPersistentEntity(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
|
||||||
|
return getRequiredPersistentEntity(clazz).getIndexCoordinates();
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,5 @@
|
|||||||
package org.springframework.data.elasticsearch.core;
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
import static org.springframework.util.StringUtils.*;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -14,32 +12,28 @@ import org.elasticsearch.action.search.MultiSearchRequest;
|
|||||||
import org.elasticsearch.action.search.MultiSearchResponse;
|
import org.elasticsearch.action.search.MultiSearchResponse;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.common.collect.MapBuilder;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.index.query.MoreLikeThisQueryBuilder;
|
import org.elasticsearch.index.query.MoreLikeThisQueryBuilder;
|
||||||
|
import org.elasticsearch.search.SearchHit;
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
import org.elasticsearch.search.suggest.SuggestBuilder;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.elasticsearch.ElasticsearchException;
|
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
|
||||||
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.convert.ElasticsearchConverter;
|
||||||
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
|
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
|
||||||
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
|
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
|
||||||
import org.springframework.data.elasticsearch.core.index.MappingBuilder;
|
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||||
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
|
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||||
import org.springframework.data.elasticsearch.core.query.Query;
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
|
import org.springframework.data.util.CloseableIterator;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AbstractElasticsearchTemplate
|
* AbstractElasticsearchTemplate
|
||||||
@ -49,22 +43,18 @@ import org.springframework.util.StringUtils;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractElasticsearchTemplate implements ElasticsearchOperations, ApplicationContextAware {
|
public abstract class AbstractElasticsearchTemplate implements ElasticsearchOperations, ApplicationContextAware {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractElasticsearchTemplate.class);
|
|
||||||
|
|
||||||
protected ElasticsearchConverter elasticsearchConverter;
|
protected ElasticsearchConverter elasticsearchConverter;
|
||||||
protected RequestFactory requestFactory;
|
protected RequestFactory requestFactory;
|
||||||
|
protected IndexOperations indexOperations;
|
||||||
|
|
||||||
/**
|
// region Initialization
|
||||||
* @since 4.0
|
protected void initialize(ElasticsearchConverter elasticsearchConverter, IndexOperations indexOperations) {
|
||||||
*/
|
|
||||||
public RequestFactory getRequestFactory() {
|
|
||||||
return requestFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void initialize(ElasticsearchConverter elasticsearchConverter) {
|
|
||||||
Assert.notNull(elasticsearchConverter, "elasticsearchConverter must not be null.");
|
Assert.notNull(elasticsearchConverter, "elasticsearchConverter must not be null.");
|
||||||
|
|
||||||
this.elasticsearchConverter = elasticsearchConverter;
|
this.elasticsearchConverter = elasticsearchConverter;
|
||||||
this.requestFactory = new RequestFactory(elasticsearchConverter);
|
requestFactory = new RequestFactory(elasticsearchConverter);
|
||||||
|
this.indexOperations = indexOperations;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ElasticsearchConverter createElasticsearchConverter() {
|
protected ElasticsearchConverter createElasticsearchConverter() {
|
||||||
@ -76,129 +66,54 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||||
|
|
||||||
if (elasticsearchConverter instanceof ApplicationContextAware) {
|
if (elasticsearchConverter instanceof ApplicationContextAware) {
|
||||||
((ApplicationContextAware) elasticsearchConverter).setApplicationContext(context);
|
((ApplicationContextAware) elasticsearchConverter).setApplicationContext(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
protected String buildMapping(Class<?> clazz) {
|
// region getter/setter
|
||||||
|
|
||||||
// load mapping specified in Mapping annotation if present
|
|
||||||
if (clazz.isAnnotationPresent(Mapping.class)) {
|
|
||||||
String mappingPath = clazz.getAnnotation(Mapping.class).mappingPath();
|
|
||||||
if (!StringUtils.isEmpty(mappingPath)) {
|
|
||||||
String mappings = ResourceUtil.readFileFromClasspath(mappingPath);
|
|
||||||
if (!StringUtils.isEmpty(mappings)) {
|
|
||||||
return mappings;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOGGER.info("mappingPath in @Mapping has to be defined. Building mappings using @Field");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// build mapping from field annotations
|
|
||||||
try {
|
|
||||||
MappingBuilder mappingBuilder = new MappingBuilder(elasticsearchConverter);
|
|
||||||
return mappingBuilder.buildPropertyMapping(clazz);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ElasticsearchException("Failed to build mapping for " + clazz.getSimpleName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean createIndex(String indexName) {
|
public IndexOperations getIndexOperations() {
|
||||||
return createIndexIfNotCreated(indexName);
|
return indexOperations;
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
private <T> boolean createIndexIfNotCreated(String indexName) {
|
// region DocumentOperations
|
||||||
return indexExists(indexName) || createIndex(indexName, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean createIndex(Class<T> clazz) {
|
|
||||||
return createIndexIfNotCreated(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> boolean createIndexIfNotCreated(Class<T> clazz) {
|
|
||||||
return indexExists(getPersistentEntityFor(clazz).getIndexName()) || createIndexWithSettings(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> boolean createIndexWithSettings(Class<T> clazz) {
|
|
||||||
if (clazz.isAnnotationPresent(Setting.class)) {
|
|
||||||
String settingPath = clazz.getAnnotation(Setting.class).settingPath();
|
|
||||||
if (hasText(settingPath)) {
|
|
||||||
String settings = ResourceUtil.readFileFromClasspath(settingPath);
|
|
||||||
if (hasText(settings)) {
|
|
||||||
return createIndex(getPersistentEntityFor(clazz).getIndexName(), settings);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOGGER.info("settingPath in @Setting has to be defined. Using default instead.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return createIndex(getPersistentEntityFor(clazz).getIndexName(), getDefaultSettings(getPersistentEntityFor(clazz)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean createIndex(Class<T> clazz, Object settings) {
|
|
||||||
return createIndex(getPersistentEntityFor(clazz).getIndexName(), settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(Query query, Class<?> clazz, IndexCoordinates index) {
|
public void delete(Query query, Class<?> clazz, IndexCoordinates index) {
|
||||||
|
|
||||||
Assert.notNull(query, "Query must not be null.");
|
Assert.notNull(query, "Query must not be null.");
|
||||||
|
|
||||||
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
||||||
DeleteQuery deleteQuery = new DeleteQuery();
|
DeleteQuery deleteQuery = new DeleteQuery();
|
||||||
deleteQuery.setQuery(searchRequest.source().query());
|
deleteQuery.setQuery(searchRequest.source().query());
|
||||||
|
|
||||||
delete(deleteQuery, index);
|
delete(deleteQuery, index);
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region SearchOperations
|
||||||
|
@Override
|
||||||
|
public <T> CloseableIterator<T> stream(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||||
|
long scrollTimeInMillis = TimeValue.timeValueMinutes(1).millis();
|
||||||
|
return StreamQueries.streamResults(startScroll(scrollTimeInMillis, query, clazz, index),
|
||||||
|
scrollId -> continueScroll(scrollId, scrollTimeInMillis, clazz), this::clearScroll);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Page<T> moreLikeThis(MoreLikeThisQuery query, Class<T> clazz, IndexCoordinates index) {
|
public <T> Page<T> moreLikeThis(MoreLikeThisQuery query, Class<T> clazz, IndexCoordinates index) {
|
||||||
|
|
||||||
Assert.notNull(query.getId(), "No document id defined for MoreLikeThisQuery");
|
Assert.notNull(query.getId(), "No document id defined for MoreLikeThisQuery");
|
||||||
|
|
||||||
MoreLikeThisQueryBuilder moreLikeThisQueryBuilder = requestFactory.moreLikeThisQueryBuilder(query, index);
|
MoreLikeThisQueryBuilder moreLikeThisQueryBuilder = requestFactory.moreLikeThisQueryBuilder(query, index);
|
||||||
|
|
||||||
return queryForPage(new NativeSearchQueryBuilder().withQuery(moreLikeThisQueryBuilder).build(), clazz, index);
|
return queryForPage(new NativeSearchQueryBuilder().withQuery(moreLikeThisQueryBuilder).build(), clazz, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static String[] toArray(List<String> values) {
|
|
||||||
String[] valuesAsArray = new String[values.size()];
|
|
||||||
return values.toArray(valuesAsArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ElasticsearchConverter getElasticsearchConverter() {
|
public <T> List<T> queryForList(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||||
return elasticsearchConverter;
|
return queryForPage(query, clazz, index).getContent();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElasticsearchPersistentEntity getPersistentEntityFor(Class clazz) {
|
|
||||||
Assert.isTrue(clazz.isAnnotationPresent(Document.class), "Unable to identify index name. " + clazz.getSimpleName()
|
|
||||||
+ " is not a Document. Make sure the document class is annotated with @Document(indexName=\"foo\")");
|
|
||||||
return elasticsearchConverter.getMappingContext().getRequiredPersistentEntity(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> Map getDefaultSettings(ElasticsearchPersistentEntity<T> persistentEntity) {
|
|
||||||
|
|
||||||
if (persistentEntity.isUseServerConfiguration())
|
|
||||||
return new HashMap();
|
|
||||||
|
|
||||||
return new MapBuilder<String, String>().put("index.number_of_shards", String.valueOf(persistentEntity.getShards()))
|
|
||||||
.put("index.number_of_replicas", String.valueOf(persistentEntity.getReplicas()))
|
|
||||||
.put("index.refresh_interval", persistentEntity.getRefreshInterval())
|
|
||||||
.put("index.store.type", persistentEntity.getIndexStoreType()).map();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void checkForBulkOperationFailure(BulkResponse bulkResponse) {
|
|
||||||
if (bulkResponse.hasFailures()) {
|
|
||||||
Map<String, String> failedDocuments = new HashMap<>();
|
|
||||||
for (BulkItemResponse item : bulkResponse.getItems()) {
|
|
||||||
if (item.isFailed())
|
|
||||||
failedDocuments.put(item.getId(), item.getFailureMessage());
|
|
||||||
}
|
|
||||||
throw new ElasticsearchException(
|
|
||||||
"Bulk operation has failures. Use ElasticsearchException.getFailedDocuments() for detailed messages ["
|
|
||||||
+ failedDocuments + "]",
|
|
||||||
failedDocuments);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -244,34 +159,80 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean putMapping(Class<T> clazz) {
|
|
||||||
return putMapping(clazz, buildMapping(clazz));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean putMapping(Class<T> clazz, Object mapping) {
|
|
||||||
return putMapping(getIndexCoordinatesFor(clazz), mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean putMapping(IndexCoordinates index, Class<T> clazz) {
|
|
||||||
return putMapping(index, buildMapping(clazz));
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request);
|
abstract protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request);
|
||||||
|
|
||||||
|
protected List<String> extractIds(SearchResponse response) {
|
||||||
|
List<String> ids = new ArrayList<>();
|
||||||
|
for (SearchHit hit : response.getHits()) {
|
||||||
|
if (hit != null) {
|
||||||
|
ids.add(hit.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Helper methods
|
||||||
|
@Override
|
||||||
|
public ElasticsearchConverter getElasticsearchConverter() {
|
||||||
|
return elasticsearchConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public RequestFactory getRequestFactory() {
|
||||||
|
return requestFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String[] toArray(List<String> values) {
|
||||||
|
String[] valuesAsArray = new String[values.size()];
|
||||||
|
return values.toArray(valuesAsArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public abstract SearchResponse suggest(SuggestBuilder suggestion, IndexCoordinates index);
|
public abstract SearchResponse suggest(SuggestBuilder suggestion, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param clazz
|
||||||
|
* @return the IndexCoordinates defined on the entity.
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
|
||||||
|
return getRequiredPersistentEntity(clazz).getIndexCoordinates();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkForBulkOperationFailure(BulkResponse bulkResponse) {
|
||||||
|
|
||||||
|
if (bulkResponse.hasFailures()) {
|
||||||
|
Map<String, String> failedDocuments = new HashMap<>();
|
||||||
|
for (BulkItemResponse item : bulkResponse.getItems()) {
|
||||||
|
|
||||||
|
if (item.isFailed())
|
||||||
|
failedDocuments.put(item.getId(), item.getFailureMessage());
|
||||||
|
}
|
||||||
|
throw new ElasticsearchException(
|
||||||
|
"Bulk operation has failures. Use ElasticsearchException.getFailedDocuments() for detailed messages ["
|
||||||
|
+ failedDocuments + ']',
|
||||||
|
failedDocuments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void setPersistentEntityId(Object entity, String id) {
|
protected void setPersistentEntityId(Object entity, String id) {
|
||||||
|
|
||||||
ElasticsearchPersistentEntity<?> persistentEntity = getPersistentEntityFor(entity.getClass());
|
ElasticsearchPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||||
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
|
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||||
|
|
||||||
// Only deal with text because ES generated Ids are strings !
|
// Only deal with text because ES generated Ids are strings!
|
||||||
|
|
||||||
if (idProperty != null && idProperty.getType().isAssignableFrom(String.class)) {
|
if (idProperty != null && idProperty.getType().isAssignableFrom(String.class)) {
|
||||||
persistentEntity.getPropertyAccessor(entity).setProperty(idProperty, id);
|
persistentEntity.getPropertyAccessor(entity).setProperty(idProperty, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ElasticsearchPersistentEntity<?> getRequiredPersistentEntity(Class<?> clazz) {
|
||||||
|
return elasticsearchConverter.getMappingContext().getRequiredPersistentEntity(clazz);
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,281 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import static org.elasticsearch.client.Requests.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
||||||
|
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||||
|
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||||
|
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
|
||||||
|
import org.elasticsearch.client.Request;
|
||||||
|
import org.elasticsearch.client.RequestOptions;
|
||||||
|
import org.elasticsearch.client.Response;
|
||||||
|
import org.elasticsearch.client.RestClient;
|
||||||
|
import org.elasticsearch.client.RestHighLevelClient;
|
||||||
|
import org.elasticsearch.client.indices.GetIndexRequest;
|
||||||
|
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.xcontent.DeprecationHandler;
|
||||||
|
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||||
|
import org.springframework.data.elasticsearch.core.client.support.AliasData;
|
||||||
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.AliasQuery;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link IndexOperations} implementation using the RestClient.
|
||||||
|
*
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
class DefaultIndexOperations extends AbstractDefaultIndexOperations implements IndexOperations {
|
||||||
|
|
||||||
|
private RestHighLevelClient client;
|
||||||
|
|
||||||
|
public DefaultIndexOperations(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter) {
|
||||||
|
super(elasticsearchConverter);
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createIndex(String indexName, Object settings) {
|
||||||
|
CreateIndexRequest request = requestFactory.createIndexRequest(indexName, settings);
|
||||||
|
try {
|
||||||
|
return client.indices().create(request, RequestOptions.DEFAULT).isAcknowledged();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error for creating index: " + request.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteIndex(String indexName) {
|
||||||
|
|
||||||
|
Assert.notNull(indexName, "No index defined for delete operation");
|
||||||
|
|
||||||
|
if (indexExists(indexName)) {
|
||||||
|
DeleteIndexRequest request = new DeleteIndexRequest(indexName);
|
||||||
|
try {
|
||||||
|
return client.indices().delete(request, RequestOptions.DEFAULT).isAcknowledged();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error while deleting index request: " + request.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean indexExists(String indexName) {
|
||||||
|
GetIndexRequest request = new GetIndexRequest(indexName);
|
||||||
|
try {
|
||||||
|
return client.indices().exists(request, RequestOptions.DEFAULT);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error while for indexExists request: " + request.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean putMapping(IndexCoordinates index, Object mapping) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "No index defined for putMapping()");
|
||||||
|
|
||||||
|
PutMappingRequest request = requestFactory.putMappingRequest(index, mapping);
|
||||||
|
try {
|
||||||
|
return client.indices().putMapping(request, RequestOptions.DEFAULT).isAcknowledged();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Failed to put mapping for " + index.getIndexName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getMapping(IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "No index defined for getMapping()");
|
||||||
|
|
||||||
|
RestClient restClient = client.getLowLevelClient();
|
||||||
|
try {
|
||||||
|
Request request = new Request("GET",
|
||||||
|
'/' + index.getIndexName() + "/_mapping/" + index.getTypeName() + "?include_type_name=true");
|
||||||
|
Response response = restClient.performRequest(request);
|
||||||
|
return convertMappingResponse(EntityUtils.toString(response.getEntity()), index.getTypeName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ElasticsearchException("Error while getting mapping for indexName : " + index.getIndexName()
|
||||||
|
+ " type : " + index.getTypeName() + ' ', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addAlias(AliasQuery query, IndexCoordinates index) {
|
||||||
|
IndicesAliasesRequest request = requestFactory.indicesAddAliasesRequest(query, index);
|
||||||
|
try {
|
||||||
|
return client.indices().updateAliases(request, RequestOptions.DEFAULT).isAcknowledged();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("failed to update aliases with request: " + request, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeAlias(AliasQuery query, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "No index defined for Alias");
|
||||||
|
Assert.notNull(query.getAliasName(), "No alias defined");
|
||||||
|
|
||||||
|
IndicesAliasesRequest indicesAliasesRequest = requestFactory.indicesRemoveAliasesRequest(query, index);
|
||||||
|
try {
|
||||||
|
return client.indices().updateAliases(indicesAliasesRequest, RequestOptions.DEFAULT).isAcknowledged();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException(
|
||||||
|
"failed to update aliases with indicesRemoveAliasesRequest: " + indicesAliasesRequest, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AliasMetaData> queryForAlias(String indexName) {
|
||||||
|
List<AliasMetaData> aliases = null;
|
||||||
|
RestClient restClient = client.getLowLevelClient();
|
||||||
|
Response response;
|
||||||
|
String aliasResponse;
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = restClient.performRequest(new Request("GET", '/' + indexName + "/_alias/*"));
|
||||||
|
aliasResponse = EntityUtils.toString(response.getEntity());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ElasticsearchException("Error while getting mapping for indexName : " + indexName, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertAliasResponse(aliasResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map getSetting(String indexName) {
|
||||||
|
|
||||||
|
Assert.notNull(indexName, "No index defined for getSettings");
|
||||||
|
|
||||||
|
ObjectMapper objMapper = new ObjectMapper();
|
||||||
|
Map settings = null;
|
||||||
|
RestClient restClient = client.getLowLevelClient();
|
||||||
|
try {
|
||||||
|
Response response = restClient.performRequest(new Request("GET", "/" + indexName + "/_settings"));
|
||||||
|
settings = convertSettingResponse(EntityUtils.toString(response.getEntity()), indexName);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ElasticsearchException("Error while getting settings for indexName : " + indexName, e);
|
||||||
|
}
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh(IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "No index defined for refresh()");
|
||||||
|
|
||||||
|
try {
|
||||||
|
client.indices().refresh(refreshRequest(index.getIndexNames()), RequestOptions.DEFAULT);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("failed to refresh index: " + index, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// region Helper methods
|
||||||
|
private Map<String, Object> convertMappingResponse(String mappingResponse, String type) {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String, Object> result = null;
|
||||||
|
JsonNode node = mapper.readTree(mappingResponse);
|
||||||
|
|
||||||
|
node = node.findValue("mappings").findValue(type);
|
||||||
|
result = mapper.readValue(mapper.writeValueAsString(node), HashMap.class);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Could not map alias response : " + mappingResponse, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It takes two steps to create a List<AliasMetadata> from the elasticsearch http response because the aliases field
|
||||||
|
* is actually a Map by alias name, but the alias name is on the AliasMetadata.
|
||||||
|
*
|
||||||
|
* @param aliasResponse
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<AliasMetaData> convertAliasResponse(String aliasResponse) {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
try {
|
||||||
|
JsonNode node = mapper.readTree(aliasResponse);
|
||||||
|
node = node.findValue("aliases");
|
||||||
|
|
||||||
|
if (node == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, AliasData> aliasData = mapper.readValue(mapper.writeValueAsString(node),
|
||||||
|
new TypeReference<Map<String, AliasData>>() {});
|
||||||
|
|
||||||
|
Iterable<Map.Entry<String, AliasData>> aliasIter = aliasData.entrySet();
|
||||||
|
List<AliasMetaData> aliasMetaDataList = new ArrayList<AliasMetaData>();
|
||||||
|
|
||||||
|
for (Map.Entry<String, AliasData> aliasentry : aliasIter) {
|
||||||
|
AliasData data = aliasentry.getValue();
|
||||||
|
aliasMetaDataList.add(AliasMetaData.newAliasMetaDataBuilder(aliasentry.getKey()).filter(data.getFilter())
|
||||||
|
.routing(data.getRouting()).searchRouting(data.getSearch_routing()).indexRouting(data.getIndex_routing())
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
return aliasMetaDataList;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Could not map alias response : " + aliasResponse, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> convertSettingResponse(String settingResponse, String indexName) {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Settings settings = Settings.fromXContent(XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY,
|
||||||
|
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, settingResponse));
|
||||||
|
String prefix = indexName + ".settings.";
|
||||||
|
// Backwards compatibility. TODO Change to return Settings object.
|
||||||
|
Map<String, String> result = new HashMap<String, String>();
|
||||||
|
Set<String> keySet = settings.keySet();
|
||||||
|
for (String key : keySet) {
|
||||||
|
result.put(key.substring(prefix.length()), settings.get(key));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Could not map alias response : " + settingResponse, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import static org.elasticsearch.client.Requests.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
||||||
|
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
|
||||||
|
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
|
||||||
|
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||||
|
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
|
||||||
|
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder;
|
||||||
|
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
|
||||||
|
import org.elasticsearch.client.Client;
|
||||||
|
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||||
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.AliasQuery;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link IndexOperations} implementation using the TransportClient.
|
||||||
|
*
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations implements IndexOperations {
|
||||||
|
|
||||||
|
private final Client client;
|
||||||
|
|
||||||
|
public DefaultTransportIndexOperations(Client client, ElasticsearchConverter elasticsearchConverter) {
|
||||||
|
super(elasticsearchConverter);
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createIndex(String indexName, Object settings) {
|
||||||
|
CreateIndexRequestBuilder createIndexRequestBuilder = requestFactory.createIndexRequestBuilder(client, indexName,
|
||||||
|
settings);
|
||||||
|
return createIndexRequestBuilder.execute().actionGet().isAcknowledged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteIndex(String indexName) {
|
||||||
|
|
||||||
|
Assert.notNull(indexName, "No index defined for delete operation");
|
||||||
|
|
||||||
|
if (indexExists(indexName)) {
|
||||||
|
return client.admin().indices().delete(new DeleteIndexRequest(indexName)).actionGet().isAcknowledged();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean indexExists(String indexName) {
|
||||||
|
return client.admin().indices().exists(indicesExistsRequest(indexName)).actionGet().isExists();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean putMapping(IndexCoordinates index, Object mapping) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "No index defined for putMapping()");
|
||||||
|
|
||||||
|
PutMappingRequestBuilder requestBuilder = requestFactory.putMappingRequestBuilder(client, index, mapping);
|
||||||
|
return requestBuilder.execute().actionGet().isAcknowledged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getMapping(IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "No index defined for putMapping()");
|
||||||
|
|
||||||
|
try {
|
||||||
|
return client.admin().indices()
|
||||||
|
.getMappings(new GetMappingsRequest().indices(index.getIndexNames()).types(index.getTypeNames())).actionGet()
|
||||||
|
.getMappings().get(index.getIndexName()).get(index.getTypeName()).getSourceAsMap();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ElasticsearchException("Error while getting mapping for indexName : " + index.getIndexName()
|
||||||
|
+ " type : " + index.getTypeName() + ' ' + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addAlias(AliasQuery query, IndexCoordinates index) {
|
||||||
|
IndicesAliasesRequest.AliasActions aliasAction = requestFactory.aliasAction(query, index);
|
||||||
|
return client.admin().indices().prepareAliases().addAliasAction(aliasAction).execute().actionGet().isAcknowledged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeAlias(AliasQuery query, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "No index defined for Alias");
|
||||||
|
Assert.notNull(query.getAliasName(), "No alias defined");
|
||||||
|
|
||||||
|
return client.admin().indices().prepareAliases().removeAlias(index.getIndexName(), query.getAliasName()).execute()
|
||||||
|
.actionGet().isAcknowledged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AliasMetaData> queryForAlias(String indexName) {
|
||||||
|
return client.admin().indices().getAliases(new GetAliasesRequest().indices(indexName)).actionGet().getAliases()
|
||||||
|
.get(indexName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getSetting(String indexName) {
|
||||||
|
|
||||||
|
Assert.notNull(indexName, "No index defined for getSettings");
|
||||||
|
|
||||||
|
Settings settings = client.admin().indices().getSettings(new GetSettingsRequest()).actionGet().getIndexToSettings()
|
||||||
|
.get(indexName);
|
||||||
|
return settings.keySet().stream().collect(Collectors.toMap((key) -> key, (key) -> settings.get(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh(IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "No index defined for refresh()");
|
||||||
|
|
||||||
|
client.admin().indices().refresh(refreshRequest(index.getIndexNames())).actionGet();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.update.UpdateResponse;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.BulkOptions;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The operations for the
|
||||||
|
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs.html">Elasticsearch Document APIs</a>.
|
||||||
|
*
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public interface DocumentOperations {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index an object. Will do save or update.
|
||||||
|
*
|
||||||
|
* @param query the query defining the object
|
||||||
|
* @param index the index from which the object is read.
|
||||||
|
* @return returns the document id
|
||||||
|
*/
|
||||||
|
String index(IndexQuery query, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an object from an index.
|
||||||
|
*
|
||||||
|
* @param query the query defining the id of the object to get
|
||||||
|
* @param clazz the type of the object to be returned
|
||||||
|
* @param index the index from which the object is read.
|
||||||
|
* @return the found object
|
||||||
|
*/
|
||||||
|
<T> T get(GetQuery query, Class<T> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a multiGet against elasticsearch for the given ids.
|
||||||
|
*
|
||||||
|
* @param query the query defining the ids of the objects to get
|
||||||
|
* @param clazz the type of the object to be returned
|
||||||
|
* @param index the index(es) from which the objects are read.
|
||||||
|
* @return list of objects
|
||||||
|
*/
|
||||||
|
<T> List<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk index all objects. Will do save or update.
|
||||||
|
*
|
||||||
|
* @param queries the queries to execute in bulk
|
||||||
|
*/
|
||||||
|
default void bulkIndex(List<IndexQuery> queries, IndexCoordinates index) {
|
||||||
|
bulkIndex(queries, BulkOptions.defaultOptions(), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk index all objects. Will do save or update.
|
||||||
|
*
|
||||||
|
* @param queries the queries to execute in bulk
|
||||||
|
* @param bulkOptions options to be added to the bulk request
|
||||||
|
*/
|
||||||
|
void bulkIndex(List<IndexQuery> queries, BulkOptions bulkOptions, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk update all objects. Will do update.
|
||||||
|
*
|
||||||
|
* @param queries the queries to execute in bulk
|
||||||
|
*/
|
||||||
|
default void bulkUpdate(List<UpdateQuery> queries, IndexCoordinates index) {
|
||||||
|
bulkUpdate(queries, BulkOptions.defaultOptions(), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk update all objects. Will do update.
|
||||||
|
*
|
||||||
|
* @param queries the queries to execute in bulk
|
||||||
|
* @param bulkOptions options to be added to the bulk request
|
||||||
|
*/
|
||||||
|
void bulkUpdate(List<UpdateQuery> queries, BulkOptions bulkOptions, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the one object with provided id.
|
||||||
|
*
|
||||||
|
* @param id the document ot delete
|
||||||
|
* @param index the index from which to delete
|
||||||
|
* @return documentId of the document deleted
|
||||||
|
*/
|
||||||
|
String delete(String id, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all records matching the query.
|
||||||
|
*
|
||||||
|
* @param query query defining the objects
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @param index the index from which to delete
|
||||||
|
*/
|
||||||
|
void delete(Query query, Class<?> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all records matching the query.
|
||||||
|
*
|
||||||
|
* @param query query defining the objects
|
||||||
|
* @param index the index where to delete the records
|
||||||
|
*/
|
||||||
|
void delete(DeleteQuery query, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partial update of the document.
|
||||||
|
*
|
||||||
|
* @param updateQuery query defining the update
|
||||||
|
* @param index the index where to update the records
|
||||||
|
* @return the update response
|
||||||
|
*/
|
||||||
|
UpdateResponse update(UpdateQuery updateQuery, IndexCoordinates index);
|
||||||
|
}
|
@ -17,27 +17,17 @@ package org.springframework.data.elasticsearch.core;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.elasticsearch.action.update.UpdateResponse;
|
|
||||||
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||||
import org.springframework.data.domain.Page;
|
|
||||||
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
|
|
||||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||||
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.data.elasticsearch.core.query.AliasQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.BulkOptions;
|
|
||||||
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
|
||||||
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
|
||||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
|
||||||
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
|
|
||||||
import org.springframework.data.elasticsearch.core.query.Query;
|
|
||||||
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
|
||||||
import org.springframework.data.util.CloseableIterator;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ElasticsearchOperations
|
* ElasticsearchOperations. Since 4.0 this interface only contains common helper functions, the other methods have been
|
||||||
|
* moved to the different interfaces that are extended by ElasticsearchOperations. The interfaces now reflect the <a
|
||||||
|
* href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rest-apis.html>REST API structure</a> of
|
||||||
|
* Elasticsearch.
|
||||||
*
|
*
|
||||||
* @author Rizwan Idrees
|
* @author Rizwan Idrees
|
||||||
* @author Mohsin Husen
|
* @author Mohsin Husen
|
||||||
@ -46,451 +36,280 @@ import org.springframework.lang.Nullable;
|
|||||||
* @author Dmitriy Yakovlev
|
* @author Dmitriy Yakovlev
|
||||||
* @author Peter-Josef Meisch
|
* @author Peter-Josef Meisch
|
||||||
*/
|
*/
|
||||||
public interface ElasticsearchOperations {
|
public interface ElasticsearchOperations extends DocumentOperations, SearchOperations {
|
||||||
|
|
||||||
/**
|
IndexOperations getIndexOperations();
|
||||||
* adding new alias
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param index
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
boolean addAlias(AliasQuery query, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* removing previously created alias
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param index
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
boolean removeAlias(AliasQuery query, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an index for given indexName if it does not already exist
|
|
||||||
*
|
|
||||||
* @param indexName
|
|
||||||
*/
|
|
||||||
boolean createIndex(String indexName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an index for given indexName and Settings
|
|
||||||
*
|
|
||||||
* @param indexName
|
|
||||||
* @param settings
|
|
||||||
*/
|
|
||||||
boolean createIndex(String indexName, Object settings);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an index for a class if it does not already exist
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
* @param <T>
|
|
||||||
*/
|
|
||||||
<T> boolean createIndex(Class<T> clazz);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an index for given class and Settings
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
* @param settings
|
|
||||||
*/
|
|
||||||
<T> boolean createIndex(Class<T> clazz, Object settings);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create mapping for a class
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
* @param <T>
|
|
||||||
*/
|
|
||||||
<T> boolean putMapping(Class<T> clazz);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create mapping for the given class and put the mapping to the given index
|
|
||||||
*
|
|
||||||
* @param index
|
|
||||||
* @param clazz
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
<T> boolean putMapping(IndexCoordinates index, Class<T> clazz);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create mapping for a given index
|
|
||||||
* @param index
|
|
||||||
* @param mappings
|
|
||||||
* @param index
|
|
||||||
*/
|
|
||||||
boolean putMapping(IndexCoordinates index, Object mappings);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create mapping for a class
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
* @param mappings
|
|
||||||
*/
|
|
||||||
<T> boolean putMapping(Class<T> clazz, Object mappings);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get mapping for a class
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
*/
|
|
||||||
default Map<String, Object> getMapping(Class<?> clazz) {
|
|
||||||
return getMapping(getIndexCoordinatesFor(clazz));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get mapping for a given index coordinates
|
|
||||||
*
|
|
||||||
* @param index
|
|
||||||
*/
|
|
||||||
Map<String, Object> getMapping(IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get settings for a given indexName
|
|
||||||
*
|
|
||||||
* @param indexName
|
|
||||||
*/
|
|
||||||
Map<String, Object> getSetting(String indexName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get settings for a given class
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
*/
|
|
||||||
<T> Map<String, Object> getSetting(Class<T> clazz);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get all the alias pointing to specified index
|
|
||||||
*
|
|
||||||
* @param indexName
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
List<AliasMetaData> queryForAlias(String indexName);
|
|
||||||
|
|
||||||
<T> T query(Query query, ResultsExtractor<T> resultsExtractor, Class<T> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves an object from an index
|
|
||||||
*
|
|
||||||
* @param query the query defining the id of the object to get
|
|
||||||
* @param clazz the type of the object to be returned
|
|
||||||
* @param index the index from which the object is read.
|
|
||||||
* @return the found object
|
|
||||||
*/
|
|
||||||
<T> T get(GetQuery query, Class<T> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the query against elasticsearch and return the first returned object
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param clazz
|
|
||||||
* @param index
|
|
||||||
* @return the first matching object
|
|
||||||
*/
|
|
||||||
default <T> T queryForObject(Query query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
List<T> content = queryForPage(query, clazz, index).getContent();
|
|
||||||
return content.isEmpty() ? null : content.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the query against elasticsearch and return result as {@link Page}
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param clazz
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
<T> AggregatedPage<T> queryForPage(Query query, Class<T> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the multi-search against elasticsearch and return result as {@link List} of {@link Page}
|
|
||||||
*
|
|
||||||
* @param queries
|
|
||||||
* @param clazz
|
|
||||||
* @param index
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
<T> List<Page<T>> queryForPage(List<? extends Query> queries, Class<T> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the multi-search against elasticsearch and return result as {@link List} of {@link Page}
|
|
||||||
*
|
|
||||||
* @param queries
|
|
||||||
* @param classes
|
|
||||||
* @param index
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
List<Page<?>> queryForPage(List<? extends Query> queries, List<Class<?>> classes, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the given {@link Query} against elasticsearch and return result as {@link CloseableIterator}.
|
|
||||||
* <p>
|
|
||||||
* Returns a {@link CloseableIterator} that wraps an Elasticsearch scroll context that needs to be closed in case of
|
|
||||||
* error.
|
|
||||||
*
|
|
||||||
* @param <T> element return type
|
|
||||||
* @param query
|
|
||||||
* @param clazz
|
|
||||||
* @param index
|
|
||||||
* @return
|
|
||||||
* @since 1.3
|
|
||||||
*/
|
|
||||||
<T> CloseableIterator<T> stream(Query query, Class<T> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the criteria query against elasticsearch and return result as {@link List}
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param clazz
|
|
||||||
* @param index
|
|
||||||
* @param <T>
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
<T> List<T> queryForList(Query query, Class<T> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the multi search query against elasticsearch and return result as {@link List}
|
|
||||||
*
|
|
||||||
* @param <T>
|
|
||||||
* @param queries
|
|
||||||
* @param clazz
|
|
||||||
* @param index
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
default <T> List<List<T>> queryForList(List<Query> queries, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
return queryForPage(queries, clazz, index).stream().map(Page::getContent).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the multi search query against elasticsearch and return result as {@link List}
|
|
||||||
*
|
|
||||||
* @param queries
|
|
||||||
* @param classes
|
|
||||||
* @param index
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
default List<List<?>> queryForList(List<Query> queries, List<Class<?>> classes, IndexCoordinates index) {
|
|
||||||
return queryForPage(queries, classes, index).stream().map(Page::getContent).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the query against elasticsearch and return ids
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param clazz
|
|
||||||
* @param index
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
List<String> queryForIds(Query query, Class<?> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return number of elements found by given query
|
|
||||||
*
|
|
||||||
* @param query the query to execute
|
|
||||||
* @param index the index to run the query against
|
|
||||||
* @return count
|
|
||||||
*/
|
|
||||||
default long count(Query query, IndexCoordinates index) {
|
|
||||||
return count(query, null, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return number of elements found by given query
|
|
||||||
*
|
|
||||||
* @param query the query to execute
|
|
||||||
* @param clazz the entity clazz used for property mapping
|
|
||||||
* @param index the index to run the query against
|
|
||||||
* @return count
|
|
||||||
*/
|
|
||||||
long count(Query query, @Nullable Class<?> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a multiGet against elasticsearch for the given ids
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param clazz
|
|
||||||
* @param index
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
<T> List<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Index an object. Will do save or update
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @return returns the document id
|
|
||||||
*/
|
|
||||||
String index(IndexQuery query, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Partial update of the document
|
|
||||||
*
|
|
||||||
* @param updateQuery
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
UpdateResponse update(UpdateQuery updateQuery, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bulk index all objects. Will do save or update.
|
|
||||||
*
|
|
||||||
* @param queries the queries to execute in bulk
|
|
||||||
*/
|
|
||||||
default void bulkIndex(List<IndexQuery> queries, IndexCoordinates index) {
|
|
||||||
bulkIndex(queries, BulkOptions.defaultOptions(), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bulk index all objects. Will do save or update.
|
|
||||||
*
|
|
||||||
* @param queries the queries to execute in bulk
|
|
||||||
* @param bulkOptions options to be added to the bulk request
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
void bulkIndex(List<IndexQuery> queries, BulkOptions bulkOptions, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bulk update all objects. Will do update
|
|
||||||
*
|
|
||||||
* @param queries the queries to execute in bulk
|
|
||||||
*/
|
|
||||||
default void bulkUpdate(List<UpdateQuery> queries, IndexCoordinates index) {
|
|
||||||
bulkUpdate(queries, BulkOptions.defaultOptions(), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bulk update all objects. Will do update
|
|
||||||
*
|
|
||||||
* @param queries the queries to execute in bulk
|
|
||||||
* @param bulkOptions options to be added to the bulk request
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
void bulkUpdate(List<UpdateQuery> queries, BulkOptions bulkOptions, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the one object with provided id.
|
|
||||||
*
|
|
||||||
* @param id the document ot delete
|
|
||||||
* @param index the index from which to delete
|
|
||||||
* @return documentId of the document deleted
|
|
||||||
*/
|
|
||||||
String delete(String id, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete all records matching the criteria
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param clazz
|
|
||||||
* @param index
|
|
||||||
*/
|
|
||||||
void delete(Query query, Class<?> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete all records matching the query
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param index the index where to delete the records
|
|
||||||
*/
|
|
||||||
void delete(DeleteQuery query, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes an index for given entity
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
default boolean deleteIndex(Class<?> clazz) {
|
|
||||||
return deleteIndex(getPersistentEntityFor(clazz).getIndexName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes an index for given indexName
|
|
||||||
*
|
|
||||||
* @param indexName
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
boolean deleteIndex(String indexName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check if index is exists
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
default boolean indexExists(Class<?> clazz) {
|
|
||||||
return indexExists(getIndexCoordinatesFor(clazz).getIndexName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check if index is exists for given IndexName
|
|
||||||
*
|
|
||||||
* @param indexName
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
boolean indexExists(String indexName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* refresh the index(es)
|
|
||||||
*
|
|
||||||
* @param index
|
|
||||||
*/
|
|
||||||
void refresh(IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* refresh the index
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
*/
|
|
||||||
default <T> void refresh(Class<T> clazz) {
|
|
||||||
refresh(getIndexCoordinatesFor(clazz));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns scrolled page for given query
|
|
||||||
*
|
|
||||||
* @param scrollTimeInMillis The time in millisecond for scroll feature
|
|
||||||
* {@link org.elasticsearch.action.search.SearchRequestBuilder#setScroll(org.elasticsearch.common.unit.TimeValue)}.
|
|
||||||
* @param query The search query.
|
|
||||||
* @param clazz The class of entity to retrieve.
|
|
||||||
* @param index
|
|
||||||
* @return The scan id for input query.
|
|
||||||
*/
|
|
||||||
<T> ScrolledPage<T> startScroll(long scrollTimeInMillis, Query query, Class<T> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
<T> ScrolledPage<T> continueScroll(@Nullable String scrollId, long scrollTimeInMillis, Class<T> clazz);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the search contexts associated with specified scroll ids.
|
|
||||||
*
|
|
||||||
* @param scrollId
|
|
||||||
*/
|
|
||||||
void clearScroll(String scrollId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* more like this query to search for documents that are "like" a specific document.
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param clazz
|
|
||||||
* @param index
|
|
||||||
* @param <T>
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
<T> Page<T> moreLikeThis(MoreLikeThisQuery query, Class<T> clazz, IndexCoordinates index);
|
|
||||||
|
|
||||||
ElasticsearchPersistentEntity getPersistentEntityFor(Class clazz);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Converter in use
|
|
||||||
*/
|
|
||||||
ElasticsearchConverter getElasticsearchConverter();
|
ElasticsearchConverter getElasticsearchConverter();
|
||||||
|
|
||||||
|
IndexCoordinates getIndexCoordinatesFor(Class<?> clazz);
|
||||||
|
|
||||||
|
// region IndexOperations
|
||||||
/**
|
/**
|
||||||
* @param clazz
|
* Create an index for given indexName if it does not already exist.
|
||||||
* @return the IndexCoordinates defined on the entity.
|
*
|
||||||
* @since 4.0
|
* @param indexName the name of the index
|
||||||
|
* @return {@literal true} if the index was created
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#createIndex(String) instead}
|
||||||
*/
|
*/
|
||||||
default IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
|
@Deprecated
|
||||||
ElasticsearchPersistentEntity entity = getPersistentEntityFor(clazz);
|
default boolean createIndex(String indexName) {
|
||||||
return IndexCoordinates.of(entity.getIndexName()).withTypes(entity.getIndexType());
|
return getIndexOperations().createIndex(indexName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an index for given indexName and Settings.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index
|
||||||
|
* @param settings the index settings
|
||||||
|
* @return {@literal true} if the index was created
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#createIndex(String, Object)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean createIndex(String indexName, Object settings) {
|
||||||
|
return getIndexOperations().createIndex(indexName, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an index for a class if it does not already exist.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return {@literal true} if the index was created
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#createIndex(Class)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean createIndex(Class<?> clazz) {
|
||||||
|
return getIndexOperations().createIndex(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an index for given class and Settings.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @param settings the index settings
|
||||||
|
* @return {@literal true} if the index was created
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#createIndex(Class, Object)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean createIndex(Class<?> clazz, Object settings) {
|
||||||
|
return getIndexOperations().createIndex(clazz, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an index for given entity.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return {@literal true} if the index was deleted
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#deleteIndex(Class)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean deleteIndex(Class<?> clazz) {
|
||||||
|
return getIndexOperations().deleteIndex(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an index.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index to delete
|
||||||
|
* @return {@literal true} if the index was deleted
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#deleteIndex(String)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean deleteIndex(String indexName) {
|
||||||
|
return getIndexOperations().deleteIndex(indexName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if index exists.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index
|
||||||
|
* @return {@literal true} if the index exists
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#indexExists(String)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean indexExists(String indexName) {
|
||||||
|
return getIndexOperations().indexExists(indexName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if index is exists.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return {@literal true} if the index exists
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#indexExists(Class)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean indexExists(Class<?> clazz) {
|
||||||
|
return getIndexOperations().indexExists(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create mapping for a class and store it to the index.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return {@literal true} if the mapping could be stored
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#putMapping(Class)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean putMapping(Class<?> clazz) {
|
||||||
|
return getIndexOperations().putMapping(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create mapping for the given class and put the mapping to the given index.
|
||||||
|
*
|
||||||
|
* @param index the index to store the mapping to
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return {@literal true} if the mapping could be stored
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#putMapping(IndexCoordinates, Class)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean putMapping(IndexCoordinates index, Class<?> clazz) {
|
||||||
|
return getIndexOperations().putMapping(index, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a mapping to an index.
|
||||||
|
*
|
||||||
|
* @param index the index to store the mapping to
|
||||||
|
* @param mappings can be a JSON String or a {@link Map}
|
||||||
|
* @return {@literal true} if the mapping could be stored
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#putMapping(IndexCoordinates, Object)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean putMapping(IndexCoordinates index, Object mappings) {
|
||||||
|
return getIndexOperations().putMapping(index, mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create mapping for a class Stores a mapping to an index.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @param mappings can be a JSON String or a {@link Map}
|
||||||
|
* @return {@literal true} if the mapping could be stored
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#putMapping(Class, Object)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean putMapping(Class<?> clazz, Object mappings) {
|
||||||
|
return getIndexOperations().putMapping(clazz, mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get mapping for an index defined by a class.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}.
|
||||||
|
* @return the mapping
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#getMapping(Class)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default Map<String, Object> getMapping(Class<?> clazz) {
|
||||||
|
return getIndexOperations().getMapping(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get mapping for a given index.
|
||||||
|
*
|
||||||
|
* @param index the index to read the mapping from
|
||||||
|
* @return the mapping
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#getMapping(IndexCoordinates)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default Map<String, Object> getMapping(IndexCoordinates index) {
|
||||||
|
return getIndexOperations().getMapping(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an alias.
|
||||||
|
*
|
||||||
|
* @param query query defining the alias
|
||||||
|
* @param index the index for which to add an alias
|
||||||
|
* @return true if the alias was created
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#addAlias(AliasQuery, IndexCoordinates)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean addAlias(AliasQuery query, IndexCoordinates index) {
|
||||||
|
return getIndexOperations().addAlias(query, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an alias.
|
||||||
|
*
|
||||||
|
* @param query query defining the alias
|
||||||
|
* @param index the index for which to remove an alias
|
||||||
|
* @return true if the alias was removed
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#removeAlias(AliasQuery, IndexCoordinates)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default boolean removeAlias(AliasQuery query, IndexCoordinates index) {
|
||||||
|
return getIndexOperations().removeAlias(query, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the alias informations for a specified index.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index
|
||||||
|
* @return alias information
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#queryForAlias(String)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default List<AliasMetaData> queryForAlias(String indexName) {
|
||||||
|
return getIndexOperations().queryForAlias(indexName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get settings for a given indexName.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index
|
||||||
|
* @return the settings
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#getSetting(String)} )} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default Map<String, Object> getSetting(String indexName) {
|
||||||
|
return getIndexOperations().getSetting(indexName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get settings for a given class.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return the settings
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#getSetting(Class)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default Map<String, Object> getSetting(Class<?> clazz) {
|
||||||
|
return getIndexOperations().getSetting(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the index(es).
|
||||||
|
*
|
||||||
|
* @param index the index to refresh
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#refresh(IndexCoordinates)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default void refresh(IndexCoordinates index) {
|
||||||
|
getIndexOperations().refresh(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the index.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @deprecated since 4.0, use {@link IndexOperations#refresh(Class)} instead}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default void refresh(Class<?> clazz) {
|
||||||
|
getIndexOperations().refresh(clazz);
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
}
|
}
|
||||||
|
@ -15,21 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.elasticsearch.core;
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
import static org.elasticsearch.client.Requests.*;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.http.util.EntityUtils;
|
|
||||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
|
||||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
|
||||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
|
||||||
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
|
|
||||||
import org.elasticsearch.action.bulk.BulkRequest;
|
import org.elasticsearch.action.bulk.BulkRequest;
|
||||||
import org.elasticsearch.action.delete.DeleteRequest;
|
import org.elasticsearch.action.delete.DeleteRequest;
|
||||||
import org.elasticsearch.action.get.GetRequest;
|
import org.elasticsearch.action.get.GetRequest;
|
||||||
@ -45,41 +33,29 @@ import org.elasticsearch.action.search.SearchResponse;
|
|||||||
import org.elasticsearch.action.search.SearchScrollRequest;
|
import org.elasticsearch.action.search.SearchScrollRequest;
|
||||||
import org.elasticsearch.action.update.UpdateRequest;
|
import org.elasticsearch.action.update.UpdateRequest;
|
||||||
import org.elasticsearch.action.update.UpdateResponse;
|
import org.elasticsearch.action.update.UpdateResponse;
|
||||||
import org.elasticsearch.client.Request;
|
|
||||||
import org.elasticsearch.client.RequestOptions;
|
import org.elasticsearch.client.RequestOptions;
|
||||||
import org.elasticsearch.client.Response;
|
|
||||||
import org.elasticsearch.client.RestClient;
|
|
||||||
import org.elasticsearch.client.RestHighLevelClient;
|
import org.elasticsearch.client.RestHighLevelClient;
|
||||||
import org.elasticsearch.client.indices.GetIndexRequest;
|
|
||||||
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.DeprecationHandler;
|
|
||||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
|
||||||
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
||||||
import org.elasticsearch.search.SearchHit;
|
|
||||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
import org.elasticsearch.search.suggest.SuggestBuilder;
|
||||||
import org.springframework.data.domain.Page;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.elasticsearch.ElasticsearchException;
|
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||||
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
|
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
|
||||||
import org.springframework.data.elasticsearch.core.client.support.AliasData;
|
|
||||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||||
import org.springframework.data.elasticsearch.core.document.DocumentAdapters;
|
import org.springframework.data.elasticsearch.core.document.DocumentAdapters;
|
||||||
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
|
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
|
||||||
import org.springframework.data.elasticsearch.core.query.*;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.BulkOptions;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
||||||
import org.springframework.data.elasticsearch.support.SearchHitsUtil;
|
import org.springframework.data.elasticsearch.support.SearchHitsUtil;
|
||||||
import org.springframework.data.util.CloseableIterator;
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ElasticsearchRestTemplate
|
* ElasticsearchRestTemplate
|
||||||
*
|
*
|
||||||
@ -116,6 +92,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
|||||||
|
|
||||||
private RestHighLevelClient client;
|
private RestHighLevelClient client;
|
||||||
|
|
||||||
|
// region Initialization
|
||||||
public ElasticsearchRestTemplate(RestHighLevelClient client) {
|
public ElasticsearchRestTemplate(RestHighLevelClient client) {
|
||||||
initialize(client, createElasticsearchConverter());
|
initialize(client, createElasticsearchConverter());
|
||||||
}
|
}
|
||||||
@ -127,192 +104,11 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
|||||||
private void initialize(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter) {
|
private void initialize(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter) {
|
||||||
Assert.notNull(client, "Client must not be null!");
|
Assert.notNull(client, "Client must not be null!");
|
||||||
this.client = client;
|
this.client = client;
|
||||||
initialize(elasticsearchConverter);
|
initialize(elasticsearchConverter, new DefaultIndexOperations(client, elasticsearchConverter));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addAlias(AliasQuery query, IndexCoordinates index) {
|
|
||||||
IndicesAliasesRequest request = requestFactory.indicesAddAliasesRequest(query, index);
|
|
||||||
try {
|
|
||||||
return client.indices().updateAliases(request, RequestOptions.DEFAULT).isAcknowledged();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("failed to update aliases with request: " + request, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeAlias(AliasQuery query, IndexCoordinates index) {
|
|
||||||
Assert.notNull(index, "No index defined for Alias");
|
|
||||||
Assert.notNull(query.getAliasName(), "No alias defined");
|
|
||||||
|
|
||||||
IndicesAliasesRequest indicesAliasesRequest = requestFactory.indicesRemoveAliasesRequest(query, index);
|
|
||||||
try {
|
|
||||||
return client.indices().updateAliases(indicesAliasesRequest, RequestOptions.DEFAULT).isAcknowledged();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("failed to update aliases with indicesRemoveAliasesRequest: " + indicesAliasesRequest, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean createIndex(String indexName, Object settings) {
|
|
||||||
CreateIndexRequest request = requestFactory.createIndexRequest(indexName, settings);
|
|
||||||
try {
|
|
||||||
return client.indices().create(request, RequestOptions.DEFAULT).isAcknowledged();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error for creating index: " + request.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean putMapping(IndexCoordinates index, Object mapping) {
|
|
||||||
Assert.notNull(index, "No index defined for putMapping()");
|
|
||||||
PutMappingRequest request = requestFactory.putMappingRequest(index, mapping);
|
|
||||||
try {
|
|
||||||
return client.indices().putMapping(request, RequestOptions.DEFAULT).isAcknowledged();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Failed to put mapping for " + index.getIndexName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> getMapping(IndexCoordinates index) {
|
|
||||||
Assert.notNull(index, "No index defined for getMapping()");
|
|
||||||
RestClient restClient = client.getLowLevelClient();
|
|
||||||
try {
|
|
||||||
Request request = new Request("GET",
|
|
||||||
'/' + index.getIndexName() + "/_mapping/" + index.getTypeName() + "?include_type_name=true");
|
|
||||||
Response response = restClient.performRequest(request);
|
|
||||||
return convertMappingResponse(EntityUtils.toString(response.getEntity()), index.getTypeName());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ElasticsearchException("Error while getting mapping for indexName : " + index.getIndexName()
|
|
||||||
+ " type : " + index.getTypeName() + ' ', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Object> convertMappingResponse(String mappingResponse, String type) {
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Map<String, Object> result = null;
|
|
||||||
JsonNode node = mapper.readTree(mappingResponse);
|
|
||||||
|
|
||||||
node = node.findValue("mappings").findValue(type);
|
|
||||||
result = mapper.readValue(mapper.writeValueAsString(node), HashMap.class);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Could not map alias response : " + mappingResponse, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T get(GetQuery query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
GetRequest request = requestFactory.getRequest(query, index);
|
|
||||||
try {
|
|
||||||
GetResponse response = client.get(request, RequestOptions.DEFAULT);
|
|
||||||
return elasticsearchConverter.mapDocument(DocumentAdapters.from(response), clazz);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error while getting for request: " + request.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private <T> T getObjectFromPage(Page<T> page) {
|
|
||||||
int contentSize = page.getContent().size();
|
|
||||||
Assert.isTrue(contentSize < 2, "Expected 1 but found " + contentSize + " results");
|
|
||||||
return contentSize > 0 ? page.getContent().get(0) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request) {
|
|
||||||
MultiSearchResponse response;
|
|
||||||
try {
|
|
||||||
response = client.multiSearch(request, RequestOptions.DEFAULT);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error for search request: " + request.toString(), e);
|
|
||||||
}
|
|
||||||
MultiSearchResponse.Item[] items = response.getResponses();
|
|
||||||
Assert.isTrue(items.length == request.requests().size(), "Response should has same length with queries");
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> AggregatedPage<T> queryForPage(Query query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
|
||||||
SearchResponse response;
|
|
||||||
try {
|
|
||||||
response = client.search(searchRequest, RequestOptions.DEFAULT);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error for search request: " + searchRequest.toString(), e);
|
|
||||||
}
|
|
||||||
return elasticsearchConverter.mapResults(SearchDocumentResponse.from(response), clazz, query.getPageable());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T query(Query query, ResultsExtractor<T> resultsExtractor, @Nullable Class<T> clazz, IndexCoordinates index) {
|
|
||||||
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
|
||||||
try {
|
|
||||||
SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
|
|
||||||
return resultsExtractor.extract(result);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error for search request: " + searchRequest.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> List<T> queryForList(Query query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
return queryForPage(query, clazz, index).getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> queryForIds(Query query, Class<?> clazz, IndexCoordinates index) {
|
|
||||||
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
|
||||||
try {
|
|
||||||
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
|
|
||||||
return extractIds(response);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error for search request: " + searchRequest.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> CloseableIterator<T> stream(Query query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
long scrollTimeInMillis = TimeValue.timeValueMinutes(1).millis();
|
|
||||||
return doStream(scrollTimeInMillis, startScroll(scrollTimeInMillis, query, clazz, index), clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> CloseableIterator<T> doStream(long scrollTimeInMillis, ScrolledPage<T> page, Class<T> clazz) {
|
|
||||||
return StreamQueries.streamResults(page, scrollId -> continueScroll(scrollId, scrollTimeInMillis, clazz),
|
|
||||||
this::clearScroll);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long count(Query query, Class<?> clazz, IndexCoordinates index) {
|
|
||||||
Assert.notNull(index, "index must not be null");
|
|
||||||
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
|
||||||
searchRequest.source().size(0);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return SearchHitsUtil.getTotalCount(client.search(searchRequest, RequestOptions.DEFAULT).getHits());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error for search request: " + searchRequest.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> List<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
Assert.notNull(index, "index must not be null");
|
|
||||||
Assert.notEmpty(query.getIds(), "No Id define for Query");
|
|
||||||
MultiGetRequest request = requestFactory.multiGetRequest(query, index);
|
|
||||||
try {
|
|
||||||
MultiGetResponse result = client.mget(request, RequestOptions.DEFAULT);
|
|
||||||
return elasticsearchConverter.mapDocuments(DocumentAdapters.from(result), clazz);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error while multiget for request: " + request.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region DocumentOperations
|
||||||
@Override
|
@Override
|
||||||
public String index(IndexQuery query, IndexCoordinates index) {
|
public String index(IndexQuery query, IndexCoordinates index) {
|
||||||
IndexRequest request = requestFactory.indexRequest(query, index);
|
IndexRequest request = requestFactory.indexRequest(query, index);
|
||||||
@ -330,17 +126,34 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UpdateResponse update(UpdateQuery query, IndexCoordinates index) {
|
public <T> T get(GetQuery query, Class<T> clazz, IndexCoordinates index) {
|
||||||
UpdateRequest request = requestFactory.updateRequest(query, index);
|
GetRequest request = requestFactory.getRequest(query, index);
|
||||||
try {
|
try {
|
||||||
return client.update(request, RequestOptions.DEFAULT);
|
GetResponse response = client.get(request, RequestOptions.DEFAULT);
|
||||||
|
return elasticsearchConverter.mapDocument(DocumentAdapters.from(response), clazz);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ElasticsearchException("Error while update for request: " + request.toString(), e);
|
throw new ElasticsearchException("Error while getting for request: " + request.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> List<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "index must not be null");
|
||||||
|
Assert.notEmpty(query.getIds(), "No Id define for Query");
|
||||||
|
|
||||||
|
MultiGetRequest request = requestFactory.multiGetRequest(query, index);
|
||||||
|
try {
|
||||||
|
MultiGetResponse result = client.mget(request, RequestOptions.DEFAULT);
|
||||||
|
return elasticsearchConverter.mapDocuments(DocumentAdapters.from(result), clazz);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error while multiget for request: " + request.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bulkIndex(List<IndexQuery> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
public void bulkIndex(List<IndexQuery> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
||||||
|
|
||||||
Assert.notNull(queries, "List of IndexQuery must not be null");
|
Assert.notNull(queries, "List of IndexQuery must not be null");
|
||||||
Assert.notNull(bulkOptions, "BulkOptions must not be null");
|
Assert.notNull(bulkOptions, "BulkOptions must not be null");
|
||||||
|
|
||||||
@ -349,48 +162,16 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bulkUpdate(List<UpdateQuery> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
public void bulkUpdate(List<UpdateQuery> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
||||||
|
|
||||||
Assert.notNull(queries, "List of UpdateQuery must not be null");
|
Assert.notNull(queries, "List of UpdateQuery must not be null");
|
||||||
Assert.notNull(bulkOptions, "BulkOptions must not be null");
|
Assert.notNull(bulkOptions, "BulkOptions must not be null");
|
||||||
|
|
||||||
doBulkOperation(queries, bulkOptions, index);
|
doBulkOperation(queries, bulkOptions, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doBulkOperation(List<?> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
|
||||||
BulkRequest bulkRequest = requestFactory.bulkRequest(queries, bulkOptions, index);
|
|
||||||
try {
|
|
||||||
checkForBulkOperationFailure(client.bulk(bulkRequest, RequestOptions.DEFAULT));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error while bulk for request: " + bulkRequest.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean indexExists(String indexName) {
|
|
||||||
GetIndexRequest request = new GetIndexRequest(indexName);
|
|
||||||
try {
|
|
||||||
return client.indices().exists(request, RequestOptions.DEFAULT);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error while for indexExists request: " + request.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean deleteIndex(String indexName) {
|
|
||||||
Assert.notNull(indexName, "No index defined for delete operation");
|
|
||||||
if (indexExists(indexName)) {
|
|
||||||
DeleteIndexRequest request = new DeleteIndexRequest(indexName);
|
|
||||||
try {
|
|
||||||
return client.indices().delete(request, RequestOptions.DEFAULT).isAcknowledged();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Error while deleting index request: " + request.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String delete(String id, IndexCoordinates index) {
|
public String delete(String id, IndexCoordinates index) {
|
||||||
DeleteRequest request = new DeleteRequest(index.getIndexName(), index.getTypeName(), id);
|
DeleteRequest request = new DeleteRequest(index.getIndexName(), id);
|
||||||
try {
|
try {
|
||||||
return client.delete(request, RequestOptions.DEFAULT).getId();
|
return client.delete(request, RequestOptions.DEFAULT).getId();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -408,9 +189,82 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpdateResponse update(UpdateQuery query, IndexCoordinates index) {
|
||||||
|
UpdateRequest request = requestFactory.updateRequest(query, index);
|
||||||
|
try {
|
||||||
|
return client.update(request, RequestOptions.DEFAULT);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error while update for request: " + request.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doBulkOperation(List<?> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
||||||
|
BulkRequest bulkRequest = requestFactory.bulkRequest(queries, bulkOptions, index);
|
||||||
|
try {
|
||||||
|
checkForBulkOperationFailure(client.bulk(bulkRequest, RequestOptions.DEFAULT));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error while bulk for request: " + bulkRequest.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region SearchOperations
|
||||||
|
@Override
|
||||||
|
public long count(Query query, Class<?> clazz, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "index must not be null");
|
||||||
|
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
||||||
|
|
||||||
|
searchRequest.source().size(0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return SearchHitsUtil.getTotalCount(client.search(searchRequest, RequestOptions.DEFAULT).getHits());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error for search request: " + searchRequest.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T query(Query query, ResultsExtractor<T> resultsExtractor, @Nullable Class<T> clazz,
|
||||||
|
IndexCoordinates index) {
|
||||||
|
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
||||||
|
try {
|
||||||
|
SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
|
||||||
|
return resultsExtractor.extract(result);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error for search request: " + searchRequest.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> AggregatedPage<T> queryForPage(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||||
|
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
||||||
|
SearchResponse response;
|
||||||
|
try {
|
||||||
|
response = client.search(searchRequest, RequestOptions.DEFAULT);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error for search request: " + searchRequest.toString(), e);
|
||||||
|
}
|
||||||
|
return elasticsearchConverter.mapResults(SearchDocumentResponse.from(response), clazz, query.getPageable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> queryForIds(Query query, Class<?> clazz, IndexCoordinates index) {
|
||||||
|
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
||||||
|
try {
|
||||||
|
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
|
||||||
|
return extractIds(response);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error for search request: " + searchRequest.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> ScrolledPage<T> startScroll(long scrollTimeInMillis, Query query, Class<T> clazz, IndexCoordinates index) {
|
public <T> ScrolledPage<T> startScroll(long scrollTimeInMillis, Query query, Class<T> clazz, IndexCoordinates index) {
|
||||||
|
|
||||||
Assert.notNull(query.getPageable(), "Query.pageable is required for scan & scroll");
|
Assert.notNull(query.getPageable(), "Query.pageable is required for scan & scroll");
|
||||||
|
|
||||||
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
|
||||||
searchRequest.scroll(TimeValue.timeValueMillis(scrollTimeInMillis));
|
searchRequest.scroll(TimeValue.timeValueMillis(scrollTimeInMillis));
|
||||||
|
|
||||||
@ -422,7 +276,6 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> ScrolledPage<T> continueScroll(@Nullable String scrollId, long scrollTimeInMillis, Class<T> clazz) {
|
public <T> ScrolledPage<T> continueScroll(@Nullable String scrollId, long scrollTimeInMillis, Class<T> clazz) {
|
||||||
SearchScrollRequest request = new SearchScrollRequest(scrollId);
|
SearchScrollRequest request = new SearchScrollRequest(scrollId);
|
||||||
request.scroll(TimeValue.timeValueMillis(scrollTimeInMillis));
|
request.scroll(TimeValue.timeValueMillis(scrollTimeInMillis));
|
||||||
@ -447,119 +300,6 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Map getSetting(Class<T> clazz) {
|
|
||||||
return getSetting(getPersistentEntityFor(clazz).getIndexName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override // TODO change interface to return Settings.
|
|
||||||
public Map getSetting(String indexName) {
|
|
||||||
Assert.notNull(indexName, "No index defined for getSettings");
|
|
||||||
ObjectMapper objMapper = new ObjectMapper();
|
|
||||||
Map settings = null;
|
|
||||||
RestClient restClient = client.getLowLevelClient();
|
|
||||||
try {
|
|
||||||
Response response = restClient.performRequest(new Request("GET", "/" + indexName + "/_settings"));
|
|
||||||
settings = convertSettingResponse(EntityUtils.toString(response.getEntity()), indexName);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ElasticsearchException("Error while getting settings for indexName : " + indexName, e);
|
|
||||||
}
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, String> convertSettingResponse(String settingResponse, String indexName) {
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Settings settings = Settings.fromXContent(XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY,
|
|
||||||
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, settingResponse));
|
|
||||||
String prefix = indexName + ".settings.";
|
|
||||||
// Backwards compatibility. TODO Change to return Settings object.
|
|
||||||
Map<String, String> result = new HashMap<String, String>();
|
|
||||||
Set<String> keySet = settings.keySet();
|
|
||||||
for (String key : keySet) {
|
|
||||||
result.put(key.substring(prefix.length()), settings.get(key));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Could not map alias response : " + settingResponse, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void refresh(IndexCoordinates index) {
|
|
||||||
Assert.notNull(index, "No index defined for refresh()");
|
|
||||||
try {
|
|
||||||
client.indices().refresh(refreshRequest(index.getIndexNames()), RequestOptions.DEFAULT);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("failed to refresh index: " + index, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<AliasMetaData> queryForAlias(String indexName) {
|
|
||||||
List<AliasMetaData> aliases = null;
|
|
||||||
RestClient restClient = client.getLowLevelClient();
|
|
||||||
Response response;
|
|
||||||
String aliasResponse;
|
|
||||||
|
|
||||||
try {
|
|
||||||
response = restClient.performRequest(new Request("GET", '/' + indexName + "/_alias/*"));
|
|
||||||
aliasResponse = EntityUtils.toString(response.getEntity());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ElasticsearchException("Error while getting mapping for indexName : " + indexName, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return convertAliasResponse(aliasResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* It takes two steps to create a List<AliasMetadata> from the elasticsearch http response because the aliases field
|
|
||||||
* is actually a Map by alias name, but the alias name is on the AliasMetadata.
|
|
||||||
*
|
|
||||||
* @param aliasResponse
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private List<AliasMetaData> convertAliasResponse(String aliasResponse) {
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
|
|
||||||
try {
|
|
||||||
JsonNode node = mapper.readTree(aliasResponse);
|
|
||||||
node = node.findValue("aliases");
|
|
||||||
|
|
||||||
if (node == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, AliasData> aliasData = mapper.readValue(mapper.writeValueAsString(node),
|
|
||||||
new TypeReference<Map<String, AliasData>>() {});
|
|
||||||
|
|
||||||
Iterable<Map.Entry<String, AliasData>> aliasIter = aliasData.entrySet();
|
|
||||||
List<AliasMetaData> aliasMetaDataList = new ArrayList<AliasMetaData>();
|
|
||||||
|
|
||||||
for (Map.Entry<String, AliasData> aliasentry : aliasIter) {
|
|
||||||
AliasData data = aliasentry.getValue();
|
|
||||||
aliasMetaDataList.add(AliasMetaData.newAliasMetaDataBuilder(aliasentry.getKey()).filter(data.getFilter())
|
|
||||||
.routing(data.getRouting()).searchRouting(data.getSearch_routing()).indexRouting(data.getIndex_routing())
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
return aliasMetaDataList;
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ElasticsearchException("Could not map alias response : " + aliasResponse, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> extractIds(SearchResponse response) {
|
|
||||||
List<String> ids = new ArrayList<>();
|
|
||||||
for (SearchHit hit : response.getHits()) {
|
|
||||||
if (hit != null) {
|
|
||||||
ids.add(hit.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SearchResponse suggest(SuggestBuilder suggestion, IndexCoordinates index) {
|
public SearchResponse suggest(SuggestBuilder suggestion, IndexCoordinates index) {
|
||||||
SearchRequest searchRequest = new SearchRequest(index.getIndexNames());
|
SearchRequest searchRequest = new SearchRequest(index.getIndexNames());
|
||||||
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
|
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
|
||||||
@ -571,5 +311,20 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ElasticsearchException("Could not execute search request : " + searchRequest.toString(), e);
|
throw new ElasticsearchException("Could not execute search request : " + searchRequest.toString(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request) {
|
||||||
|
MultiSearchResponse response;
|
||||||
|
try {
|
||||||
|
response = client.multiSearch(request, RequestOptions.DEFAULT);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Error for search request: " + request.toString(), e);
|
||||||
|
}
|
||||||
|
MultiSearchResponse.Item[] items = response.getResponses();
|
||||||
|
Assert.isTrue(items.length == request.requests().size(), "Response should has same length with queries");
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
}
|
}
|
||||||
|
@ -15,21 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.elasticsearch.core;
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
import static org.elasticsearch.client.Requests.*;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.elasticsearch.action.ActionFuture;
|
import org.elasticsearch.action.ActionFuture;
|
||||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
|
||||||
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
|
|
||||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
|
|
||||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
|
||||||
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
|
|
||||||
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder;
|
|
||||||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
|
|
||||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
||||||
import org.elasticsearch.action.get.GetRequestBuilder;
|
import org.elasticsearch.action.get.GetRequestBuilder;
|
||||||
import org.elasticsearch.action.get.GetResponse;
|
import org.elasticsearch.action.get.GetResponse;
|
||||||
@ -42,23 +30,16 @@ import org.elasticsearch.action.search.SearchResponse;
|
|||||||
import org.elasticsearch.action.update.UpdateRequestBuilder;
|
import org.elasticsearch.action.update.UpdateRequestBuilder;
|
||||||
import org.elasticsearch.action.update.UpdateResponse;
|
import org.elasticsearch.action.update.UpdateResponse;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
|
||||||
import org.elasticsearch.search.SearchHit;
|
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
import org.elasticsearch.search.suggest.SuggestBuilder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.data.domain.Page;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.elasticsearch.ElasticsearchException;
|
|
||||||
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
|
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
|
||||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||||
import org.springframework.data.elasticsearch.core.document.DocumentAdapters;
|
import org.springframework.data.elasticsearch.core.document.DocumentAdapters;
|
||||||
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
|
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
|
||||||
import org.springframework.data.elasticsearch.core.query.AliasQuery;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.BulkOptions;
|
import org.springframework.data.elasticsearch.core.query.BulkOptions;
|
||||||
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
||||||
@ -66,7 +47,6 @@ import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
|||||||
import org.springframework.data.elasticsearch.core.query.Query;
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
||||||
import org.springframework.data.elasticsearch.support.SearchHitsUtil;
|
import org.springframework.data.elasticsearch.support.SearchHitsUtil;
|
||||||
import org.springframework.data.util.CloseableIterator;
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@ -100,13 +80,13 @@ import org.springframework.util.Assert;
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||||
|
|
||||||
private static final Logger QUERY_LOGGER = LoggerFactory
|
private static final Logger QUERY_LOGGER = LoggerFactory
|
||||||
.getLogger("org.springframework.data.elasticsearch.core.QUERY");
|
.getLogger("org.springframework.data.elasticsearch.core.QUERY");
|
||||||
|
|
||||||
private Client client;
|
private Client client;
|
||||||
private String searchTimeout;
|
private String searchTimeout;
|
||||||
|
|
||||||
|
// region Initialization
|
||||||
public ElasticsearchTemplate(Client client) {
|
public ElasticsearchTemplate(Client client) {
|
||||||
initialize(client, createElasticsearchConverter());
|
initialize(client, createElasticsearchConverter());
|
||||||
}
|
}
|
||||||
@ -118,132 +98,21 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
|||||||
private void initialize(Client client, ElasticsearchConverter elasticsearchConverter) {
|
private void initialize(Client client, ElasticsearchConverter elasticsearchConverter) {
|
||||||
Assert.notNull(client, "Client must not be null!");
|
Assert.notNull(client, "Client must not be null!");
|
||||||
this.client = client;
|
this.client = client;
|
||||||
initialize(elasticsearchConverter);
|
initialize(elasticsearchConverter, new DefaultTransportIndexOperations(client, elasticsearchConverter));
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region getter/setter
|
||||||
|
public String getSearchTimeout() {
|
||||||
|
return searchTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSearchTimeout(String searchTimeout) {
|
public void setSearchTimeout(String searchTimeout) {
|
||||||
this.searchTimeout = searchTimeout;
|
this.searchTimeout = searchTimeout;
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
@Override
|
// region DocumentOperations
|
||||||
public boolean addAlias(AliasQuery query, IndexCoordinates index) {
|
|
||||||
IndicesAliasesRequest.AliasActions aliasAction = requestFactory.aliasAction(query, index);
|
|
||||||
return client.admin().indices().prepareAliases().addAliasAction(aliasAction).execute().actionGet().isAcknowledged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeAlias(AliasQuery query, IndexCoordinates index) {
|
|
||||||
Assert.notNull(index, "No index defined for Alias");
|
|
||||||
Assert.notNull(query.getAliasName(), "No alias defined");
|
|
||||||
return client.admin().indices().prepareAliases().removeAlias(index.getIndexName(), query.getAliasName()).execute()
|
|
||||||
.actionGet().isAcknowledged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean createIndex(String indexName, Object settings) {
|
|
||||||
CreateIndexRequestBuilder createIndexRequestBuilder = requestFactory.createIndexRequestBuilder(client, indexName,
|
|
||||||
settings);
|
|
||||||
return createIndexRequestBuilder.execute().actionGet().isAcknowledged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean putMapping(IndexCoordinates index, Object mapping) {
|
|
||||||
Assert.notNull(index, "No index defined for putMapping()");
|
|
||||||
PutMappingRequestBuilder requestBuilder = requestFactory.putMappingRequestBuilder(client, index, mapping);
|
|
||||||
return requestBuilder.execute().actionGet().isAcknowledged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> getMapping(IndexCoordinates index) {
|
|
||||||
Assert.notNull(index, "No index defined for putMapping()");
|
|
||||||
try {
|
|
||||||
return client.admin().indices()
|
|
||||||
.getMappings(new GetMappingsRequest().indices(index.getIndexNames()).types(index.getTypeNames())).actionGet()
|
|
||||||
.getMappings().get(index.getIndexName()).get(index.getTypeName()).getSourceAsMap();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ElasticsearchException("Error while getting mapping for indexName : " + index.getIndexName()
|
|
||||||
+ " type : " + index.getTypeName() + ' ' + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T get(GetQuery query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
GetRequestBuilder getRequestBuilder = requestFactory.getRequestBuilder(client, query, index);
|
|
||||||
GetResponse response = getRequestBuilder.execute().actionGet();
|
|
||||||
T entity = elasticsearchConverter.mapDocument(DocumentAdapters.from(response), clazz);
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private <T> T getObjectFromPage(Page<T> page) {
|
|
||||||
int contentSize = page.getContent().size();
|
|
||||||
Assert.isTrue(contentSize < 2, "Expected 1 but found " + contentSize + " results");
|
|
||||||
return contentSize > 0 ? page.getContent().get(0) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request) {
|
|
||||||
ActionFuture<MultiSearchResponse> future = client.multiSearch(request);
|
|
||||||
MultiSearchResponse response = future.actionGet();
|
|
||||||
MultiSearchResponse.Item[] items = response.getResponses();
|
|
||||||
Assert.isTrue(items.length == request.requests().size(), "Response should have same length with queries");
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T query(Query query, ResultsExtractor<T> resultsExtractor, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, query, clazz, index);
|
|
||||||
SearchResponse response = getSearchResponse(searchRequestBuilder);
|
|
||||||
return resultsExtractor.extract(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> List<T> queryForList(Query query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
return queryForPage(query, clazz, index).getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> queryForIds(Query query, Class<?> clazz, IndexCoordinates index) {
|
|
||||||
SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, query, clazz, index);
|
|
||||||
SearchResponse response = getSearchResponse(searchRequestBuilder);
|
|
||||||
return extractIds(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> AggregatedPage<T> queryForPage(Query query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, query, clazz, index);
|
|
||||||
SearchResponse response = getSearchResponse(searchRequestBuilder);
|
|
||||||
return elasticsearchConverter.mapResults(SearchDocumentResponse.from(response), clazz, query.getPageable());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> CloseableIterator<T> stream(Query query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
long scrollTimeInMillis = TimeValue.timeValueMinutes(1).millis();
|
|
||||||
return doStream(scrollTimeInMillis, startScroll(scrollTimeInMillis, query, clazz, index), clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> CloseableIterator<T> doStream(long scrollTimeInMillis, ScrolledPage<T> page, Class<T> clazz) {
|
|
||||||
return StreamQueries.streamResults(page, scrollId -> continueScroll(scrollId, scrollTimeInMillis, clazz),
|
|
||||||
this::clearScroll);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long count(Query query, @Nullable Class<?> clazz, IndexCoordinates index) {
|
|
||||||
Assert.notNull(index, "index must not be null");
|
|
||||||
SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, query, clazz, index);
|
|
||||||
searchRequestBuilder.setSize(0);
|
|
||||||
|
|
||||||
return SearchHitsUtil.getTotalCount(getSearchResponse(searchRequestBuilder).getHits());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> List<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index) {
|
|
||||||
Assert.notNull(index, "index must not be null");
|
|
||||||
Assert.notEmpty(query.getIds(), "No Id define for Query");
|
|
||||||
MultiGetRequestBuilder builder = requestFactory.multiGetRequestBuilder(client, query, index);
|
|
||||||
return elasticsearchConverter.mapDocuments(DocumentAdapters.from(builder.execute().actionGet()), clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String index(IndexQuery query, IndexCoordinates index) {
|
public String index(IndexQuery query, IndexCoordinates index) {
|
||||||
IndexRequestBuilder indexRequestBuilder = requestFactory.indexRequestBuilder(client, query, index);
|
IndexRequestBuilder indexRequestBuilder = requestFactory.indexRequestBuilder(client, query, index);
|
||||||
@ -256,13 +125,27 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UpdateResponse update(UpdateQuery query, IndexCoordinates index) {
|
public <T> T get(GetQuery query, Class<T> clazz, IndexCoordinates index) {
|
||||||
UpdateRequestBuilder updateRequestBuilder = requestFactory.updateRequestBuilderFor(client, query, index);
|
GetRequestBuilder getRequestBuilder = requestFactory.getRequestBuilder(client, query, index);
|
||||||
return updateRequestBuilder.execute().actionGet();
|
GetResponse response = getRequestBuilder.execute().actionGet();
|
||||||
|
T entity = elasticsearchConverter.mapDocument(DocumentAdapters.from(response), clazz);
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> List<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "index must not be null");
|
||||||
|
Assert.notEmpty(query.getIds(), "No Id define for Query");
|
||||||
|
|
||||||
|
MultiGetRequestBuilder builder = requestFactory.multiGetRequestBuilder(client, query, index);
|
||||||
|
|
||||||
|
return elasticsearchConverter.mapDocuments(DocumentAdapters.from(builder.execute().actionGet()), clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bulkIndex(List<IndexQuery> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
public void bulkIndex(List<IndexQuery> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
||||||
|
|
||||||
Assert.notNull(queries, "List of IndexQuery must not be null");
|
Assert.notNull(queries, "List of IndexQuery must not be null");
|
||||||
Assert.notNull(bulkOptions, "BulkOptions must not be null");
|
Assert.notNull(bulkOptions, "BulkOptions must not be null");
|
||||||
|
|
||||||
@ -271,31 +154,13 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bulkUpdate(List<UpdateQuery> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
public void bulkUpdate(List<UpdateQuery> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
||||||
|
|
||||||
Assert.notNull(queries, "List of UpdateQuery must not be null");
|
Assert.notNull(queries, "List of UpdateQuery must not be null");
|
||||||
Assert.notNull(bulkOptions, "BulkOptions must not be null");
|
Assert.notNull(bulkOptions, "BulkOptions must not be null");
|
||||||
|
|
||||||
doBulkOperation(queries, bulkOptions, index);
|
doBulkOperation(queries, bulkOptions, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doBulkOperation(List<?> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
|
||||||
BulkRequestBuilder bulkRequest = requestFactory.bulkRequestBuilder(client, queries, bulkOptions, index);
|
|
||||||
checkForBulkOperationFailure(bulkRequest.execute().actionGet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean indexExists(String indexName) {
|
|
||||||
return client.admin().indices().exists(indicesExistsRequest(indexName)).actionGet().isExists();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean deleteIndex(String indexName) {
|
|
||||||
Assert.notNull(indexName, "No index defined for delete operation");
|
|
||||||
if (indexExists(indexName)) {
|
|
||||||
return client.admin().indices().delete(new DeleteIndexRequest(indexName)).actionGet().isAcknowledged();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String delete(String id, IndexCoordinates index) {
|
public String delete(String id, IndexCoordinates index) {
|
||||||
return client.prepareDelete(index.getIndexName(), index.getTypeName(), id).execute().actionGet().getId();
|
return client.prepareDelete(index.getIndexName(), index.getTypeName(), id).execute().actionGet().getId();
|
||||||
@ -306,9 +171,55 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
|||||||
requestFactory.deleteByQueryRequestBuilder(client, deleteQuery, index).get();
|
requestFactory.deleteByQueryRequestBuilder(client, deleteQuery, index).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpdateResponse update(UpdateQuery query, IndexCoordinates index) {
|
||||||
|
UpdateRequestBuilder updateRequestBuilder = requestFactory.updateRequestBuilderFor(client, query, index);
|
||||||
|
return updateRequestBuilder.execute().actionGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doBulkOperation(List<?> queries, BulkOptions bulkOptions, IndexCoordinates index) {
|
||||||
|
BulkRequestBuilder bulkRequest = requestFactory.bulkRequestBuilder(client, queries, bulkOptions, index);
|
||||||
|
checkForBulkOperationFailure(bulkRequest.execute().actionGet());
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region SearchOperations
|
||||||
|
@Override
|
||||||
|
public long count(Query query, @Nullable Class<?> clazz, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "index must not be null");
|
||||||
|
|
||||||
|
SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, query, clazz, index);
|
||||||
|
searchRequestBuilder.setSize(0);
|
||||||
|
|
||||||
|
return SearchHitsUtil.getTotalCount(getSearchResponse(searchRequestBuilder).getHits());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T query(Query query, ResultsExtractor<T> resultsExtractor, Class<T> clazz, IndexCoordinates index) {
|
||||||
|
SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, query, clazz, index);
|
||||||
|
SearchResponse response = getSearchResponse(searchRequestBuilder);
|
||||||
|
return resultsExtractor.extract(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> AggregatedPage<T> queryForPage(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||||
|
SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, query, clazz, index);
|
||||||
|
SearchResponse response = getSearchResponse(searchRequestBuilder);
|
||||||
|
return elasticsearchConverter.mapResults(SearchDocumentResponse.from(response), clazz, query.getPageable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> queryForIds(Query query, Class<?> clazz, IndexCoordinates index) {
|
||||||
|
SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, query, clazz, index);
|
||||||
|
SearchResponse response = getSearchResponse(searchRequestBuilder);
|
||||||
|
return extractIds(response);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> ScrolledPage<T> startScroll(long scrollTimeInMillis, Query query, Class<T> clazz, IndexCoordinates index) {
|
public <T> ScrolledPage<T> startScroll(long scrollTimeInMillis, Query query, Class<T> clazz, IndexCoordinates index) {
|
||||||
Assert.notNull(query.getPageable(), "Query.pageable is required for scan & scroll");
|
Assert.notNull(query.getPageable(), "Query.pageable is required for scan & scroll");
|
||||||
|
|
||||||
SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, query, clazz, index);
|
SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, query, clazz, index);
|
||||||
searchRequestBuilder.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis));
|
searchRequestBuilder.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis));
|
||||||
SearchResponse response = getSearchResponse(searchRequestBuilder);
|
SearchResponse response = getSearchResponse(searchRequestBuilder);
|
||||||
@ -327,6 +238,20 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
|||||||
client.prepareClearScroll().addScrollId(scrollId).execute().actionGet();
|
client.prepareClearScroll().addScrollId(scrollId).execute().actionGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SearchResponse suggest(SuggestBuilder suggestion, IndexCoordinates index) {
|
||||||
|
return client.prepareSearch(index.getIndexNames()).suggest(suggestion).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request) {
|
||||||
|
ActionFuture<MultiSearchResponse> future = client.multiSearch(request);
|
||||||
|
MultiSearchResponse response = future.actionGet();
|
||||||
|
MultiSearchResponse.Item[] items = response.getResponses();
|
||||||
|
Assert.isTrue(items.length == request.requests().size(), "Response should have same length with queries");
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
private SearchResponse getSearchResponse(SearchRequestBuilder requestBuilder) {
|
private SearchResponse getSearchResponse(SearchRequestBuilder requestBuilder) {
|
||||||
|
|
||||||
if (QUERY_LOGGER.isDebugEnabled()) {
|
if (QUERY_LOGGER.isDebugEnabled()) {
|
||||||
@ -338,44 +263,5 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
|||||||
private SearchResponse getSearchResponseWithTimeout(ActionFuture<SearchResponse> response) {
|
private SearchResponse getSearchResponseWithTimeout(ActionFuture<SearchResponse> response) {
|
||||||
return searchTimeout == null ? response.actionGet() : response.actionGet(searchTimeout);
|
return searchTimeout == null ? response.actionGet() : response.actionGet(searchTimeout);
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
@Override
|
|
||||||
public <T> Map<String, Object> getSetting(Class<T> clazz) {
|
|
||||||
return getSetting(getPersistentEntityFor(clazz).getIndexName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> getSetting(String indexName) {
|
|
||||||
Assert.notNull(indexName, "No index defined for getSettings");
|
|
||||||
Settings settings = client.admin().indices().getSettings(new GetSettingsRequest()).actionGet().getIndexToSettings()
|
|
||||||
.get(indexName);
|
|
||||||
return settings.keySet().stream().collect(Collectors.toMap((key) -> key, (key) -> settings.get(key)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void refresh(IndexCoordinates index) {
|
|
||||||
Assert.notNull(index, "No index defined for refresh()");
|
|
||||||
client.admin().indices().refresh(refreshRequest(index.getIndexNames())).actionGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<AliasMetaData> queryForAlias(String indexName) {
|
|
||||||
return client.admin().indices().getAliases(new GetAliasesRequest().indices(indexName)).actionGet().getAliases()
|
|
||||||
.get(indexName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> extractIds(SearchResponse response) {
|
|
||||||
List<String> ids = new ArrayList<>();
|
|
||||||
for (SearchHit hit : response.getHits()) {
|
|
||||||
if (hit != null) {
|
|
||||||
ids.add(hit.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SearchResponse suggest(SuggestBuilder suggestion, IndexCoordinates index) {
|
|
||||||
return client.prepareSearch(index.getIndexNames()).suggest(suggestion).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import java.util.Map;
|
|||||||
import org.springframework.core.convert.ConversionService;
|
import org.springframework.core.convert.ConversionService;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.mapping.IdentifierAccessor;
|
import org.springframework.data.mapping.IdentifierAccessor;
|
||||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
@ -127,7 +128,7 @@ class EntityOperations {
|
|||||||
|
|
||||||
if (StringUtils.isEmpty(index)) {
|
if (StringUtils.isEmpty(index)) {
|
||||||
Assert.notNull(entity, "Cannot determine index name");
|
Assert.notNull(entity, "Cannot determine index name");
|
||||||
return entity.getIndexName();
|
return entity.getIndexCoordinates().getIndexName();
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
@ -137,7 +138,7 @@ class EntityOperations {
|
|||||||
|
|
||||||
if (StringUtils.isEmpty(type)) {
|
if (StringUtils.isEmpty(type)) {
|
||||||
Assert.notNull(entity, "Cannot determine index type");
|
Assert.notNull(entity, "Cannot determine index type");
|
||||||
return entity.getIndexType();
|
return entity.getIndexCoordinates().getTypeName();
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
|
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.AliasQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The operations for the
|
||||||
|
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices.html">Elasticsearch Index APIs</a>.
|
||||||
|
*
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public interface IndexOperations {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an index for given indexName.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index
|
||||||
|
* @return {@literal true} if the index was created
|
||||||
|
*/
|
||||||
|
boolean createIndex(String indexName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an index for given indexName and Settings.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index
|
||||||
|
* @param settings the index settings
|
||||||
|
* @return {@literal true} if the index was created
|
||||||
|
*/
|
||||||
|
boolean createIndex(String indexName, Object settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an index for a class.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return {@literal true} if the index was created
|
||||||
|
*/
|
||||||
|
boolean createIndex(Class<?> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an index for given class and Settings.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @param settings the index settings
|
||||||
|
* @return {@literal true} if the index was created
|
||||||
|
*/
|
||||||
|
boolean createIndex(Class<?> clazz, Object settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an index for given entity.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return {@literal true} if the index was deleted
|
||||||
|
*/
|
||||||
|
boolean deleteIndex(Class<?> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an index.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index to delete
|
||||||
|
* @return {@literal true} if the index was deleted
|
||||||
|
*/
|
||||||
|
boolean deleteIndex(String indexName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if index exists.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index
|
||||||
|
* @return {@literal true} if the index exists
|
||||||
|
*/
|
||||||
|
boolean indexExists(String indexName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if index is exists.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return {@literal true} if the index exists
|
||||||
|
*/
|
||||||
|
boolean indexExists(Class<?> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create mapping for a class and store it to the index.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return {@literal true} if the mapping could be stored
|
||||||
|
*/
|
||||||
|
boolean putMapping(Class<?> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create mapping for the given class and put the mapping to the given index.
|
||||||
|
*
|
||||||
|
* @param index the index to store the mapping to
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return {@literal true} if the mapping could be stored
|
||||||
|
*/
|
||||||
|
boolean putMapping(IndexCoordinates index, Class<?> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a mapping to an index.
|
||||||
|
*
|
||||||
|
* @param index the index to store the mapping to
|
||||||
|
* @param mappings can be a JSON String or a {@link Map}
|
||||||
|
* @return {@literal true} if the mapping could be stored
|
||||||
|
*/
|
||||||
|
boolean putMapping(IndexCoordinates index, Object mappings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create mapping for a class Stores a mapping to an index.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @param mappings can be a JSON String or a {@link Map}
|
||||||
|
* @return {@literal true} if the mapping could be stored
|
||||||
|
*/
|
||||||
|
<T> boolean putMapping(Class<T> clazz, Object mappings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get mapping for an index defined by a class.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}.
|
||||||
|
* @return the mapping
|
||||||
|
*/
|
||||||
|
Map<String, Object> getMapping(Class<?> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get mapping for a given index.
|
||||||
|
*
|
||||||
|
* @param index the index to read the mapping from
|
||||||
|
* @return the mapping
|
||||||
|
*/
|
||||||
|
Map<String, Object> getMapping(IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an alias.
|
||||||
|
*
|
||||||
|
* @param query query defining the alias
|
||||||
|
* @param index the index for which to add an alias
|
||||||
|
* @return true if the alias was created
|
||||||
|
*/
|
||||||
|
boolean addAlias(AliasQuery query, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an alias.
|
||||||
|
*
|
||||||
|
* @param query query defining the alias
|
||||||
|
* @param index the index for which to remove an alias
|
||||||
|
* @return true if the alias was removed
|
||||||
|
*/
|
||||||
|
boolean removeAlias(AliasQuery query, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the alias informations for a specified index.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index
|
||||||
|
* @return alias information
|
||||||
|
*/
|
||||||
|
List<AliasMetaData> queryForAlias(String indexName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get settings for a given indexName.
|
||||||
|
*
|
||||||
|
* @param indexName the name of the index
|
||||||
|
* @return the settings
|
||||||
|
*/
|
||||||
|
Map<String, Object> getSetting(String indexName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get settings for a given class.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
* @return the settings
|
||||||
|
*/
|
||||||
|
Map<String, Object> getSetting(Class<?> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the index(es).
|
||||||
|
*
|
||||||
|
* @param index the index to refresh
|
||||||
|
*/
|
||||||
|
void refresh(IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the index.
|
||||||
|
*
|
||||||
|
* @param clazz The entity class, must be annotated with
|
||||||
|
* {@link org.springframework.data.elasticsearch.annotations.Document}
|
||||||
|
*/
|
||||||
|
void refresh(Class<?> clazz);
|
||||||
|
}
|
@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reactive operations for the
|
||||||
|
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs.html">Elasticsearch Document APIs</a>.
|
||||||
|
*
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public interface ReactiveDocumentOperations {
|
||||||
|
/**
|
||||||
|
* Index the given entity, once available, extracting index and type from entity metadata.
|
||||||
|
*
|
||||||
|
* @param entityPublisher must not be {@literal null}.
|
||||||
|
* @param <T>
|
||||||
|
* @return a {@link Mono} emitting the saved entity.
|
||||||
|
*/
|
||||||
|
default <T> Mono<T> save(Mono<? extends T> entityPublisher) {
|
||||||
|
|
||||||
|
Assert.notNull(entityPublisher, "EntityPublisher must not be null!");
|
||||||
|
return entityPublisher.flatMap(this::save);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index the given entity extracting index and type from entity metadata.
|
||||||
|
*
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @param <T>
|
||||||
|
* @return a {@link Mono} emitting the saved entity.
|
||||||
|
*/
|
||||||
|
<T> Mono<T> save(T entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index the entity, once available, under the given {@literal type} in the given {@literal index}. If the
|
||||||
|
* {@literal index} is {@literal null} or empty the index name provided via entity metadata is used. Same for the
|
||||||
|
* {@literal type}.
|
||||||
|
*
|
||||||
|
* @param entityPublisher must not be {@literal null}.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @param <T>
|
||||||
|
* @return a {@link Mono} emitting the saved entity.
|
||||||
|
*/
|
||||||
|
default <T> Mono<T> save(Mono<? extends T> entityPublisher, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(entityPublisher, "EntityPublisher must not be null!");
|
||||||
|
return entityPublisher.flatMap(it -> save(it, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index the entity under the given {@literal type} in the given {@literal index}. If the {@literal index} is
|
||||||
|
* {@literal null} or empty the index name provided via entity metadata is used. Same for the {@literal type}.
|
||||||
|
*
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @param <T>
|
||||||
|
* @return a {@link Mono} emitting the saved entity.
|
||||||
|
*/
|
||||||
|
<T> Mono<T> save(T entity, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the document with the given {@literal id} mapped onto the given {@literal entityType}.
|
||||||
|
*
|
||||||
|
* @param id the {@literal _id} of the document to fetch.
|
||||||
|
* @param entityType the domain type used for mapping the document.
|
||||||
|
* @param <T>
|
||||||
|
* @return {@link Mono#empty()} if not found.
|
||||||
|
*/
|
||||||
|
<T> Mono<T> findById(String id, Class<T> entityType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the entity with given {@literal id}.
|
||||||
|
*
|
||||||
|
* @param id must not be {@literal null}.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @param <T>
|
||||||
|
* @return the {@link Mono} emitting the entity or signalling completion if none found.
|
||||||
|
*/
|
||||||
|
<T> Mono<T> findById(String id, Class<T> entityType, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an entity with given {@literal id} exists.
|
||||||
|
*
|
||||||
|
* @param id the {@literal _id} of the document to look for.
|
||||||
|
* @param entityType the domain type used.
|
||||||
|
* @return a {@link Mono} emitting {@literal true} if a matching document exists, {@literal false} otherwise.
|
||||||
|
*/
|
||||||
|
Mono<Boolean> exists(String id, Class<?> entityType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an entity with given {@literal id} exists.
|
||||||
|
*
|
||||||
|
* @param id the {@literal _id} of the document to look for.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @return a {@link Mono} emitting {@literal true} if a matching document exists, {@literal false} otherwise.
|
||||||
|
*/
|
||||||
|
Mono<Boolean> exists(String id, Class<?> entityType, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the given entity extracting index and type from entity metadata.
|
||||||
|
*
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @return a {@link Mono} emitting the {@literal id} of the removed document.
|
||||||
|
*/
|
||||||
|
Mono<String> delete(Object entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the given entity extracting index and type from entity metadata.
|
||||||
|
*
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @return a {@link Mono} emitting the {@literal id} of the removed document.
|
||||||
|
*/
|
||||||
|
Mono<String> delete(Object entity, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the entity with given {@literal id}.
|
||||||
|
*
|
||||||
|
* @param id must not be {@literal null}.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @return a {@link Mono} emitting the {@literal id} of the removed document.
|
||||||
|
*/
|
||||||
|
default Mono<String> deleteById(String id, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(index, "Index must not be null!");
|
||||||
|
|
||||||
|
return deleteById(id, Object.class, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the entity with given {@literal id} extracting index and type from entity metadata.
|
||||||
|
*
|
||||||
|
* @param id must not be {@literal null}.
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @return a {@link Mono} emitting the {@literal id} of the removed document.
|
||||||
|
*/
|
||||||
|
Mono<String> deleteById(String id, Class<?> entityType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the entity with given {@literal id} extracting index and type from entity metadata.
|
||||||
|
*
|
||||||
|
* @param id must not be {@literal null}.
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @return a {@link Mono} emitting the {@literal id} of the removed document.
|
||||||
|
*/
|
||||||
|
Mono<String> deleteById(String id, Class<?> entityType, IndexCoordinates index);
|
||||||
|
/**
|
||||||
|
* Delete the documents matching the given {@link Query} extracting index and type from entity metadata.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @return a {@link Mono} emitting the number of the removed documents.
|
||||||
|
*/
|
||||||
|
Mono<Long> deleteBy(Query query, Class<?> entityType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the documents matching the given {@link Query} extracting index and type from entity metadata.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @return a {@link Mono} emitting the number of the removed documents.
|
||||||
|
*/
|
||||||
|
Mono<Long> deleteBy(Query query, Class<?> entityType, IndexCoordinates index);
|
||||||
|
}
|
@ -15,19 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.elasticsearch.core;
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
import reactor.core.publisher.Flux;
|
|
||||||
import reactor.core.publisher.Mono;
|
|
||||||
|
|
||||||
import org.elasticsearch.index.query.QueryBuilders;
|
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
|
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
|
||||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.query.Query;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.StringQuery;
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that specifies a basic set of Elasticsearch operations executed in a reactive way.
|
* Interface that specifies a basic set of Elasticsearch operations executed in a reactive way.
|
||||||
@ -41,7 +34,7 @@ import org.springframework.util.Assert;
|
|||||||
* @author Peter-Josef Meisch
|
* @author Peter-Josef Meisch
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public interface ReactiveElasticsearchOperations {
|
public interface ReactiveElasticsearchOperations extends ReactiveDocumentOperations, ReactiveSearchOperations {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute within a {@link ClientCallback} managing resources and translating errors.
|
* Execute within a {@link ClientCallback} managing resources and translating errors.
|
||||||
@ -52,261 +45,6 @@ public interface ReactiveElasticsearchOperations {
|
|||||||
*/
|
*/
|
||||||
<T> Publisher<T> execute(ClientCallback<Publisher<T>> callback);
|
<T> Publisher<T> execute(ClientCallback<Publisher<T>> callback);
|
||||||
|
|
||||||
/**
|
|
||||||
* Index the given entity, once available, extracting index and type from entity metadata.
|
|
||||||
*
|
|
||||||
* @param entityPublisher must not be {@literal null}.
|
|
||||||
* @param <T>
|
|
||||||
* @return a {@link Mono} emitting the saved entity.
|
|
||||||
*/
|
|
||||||
default <T> Mono<T> save(Mono<? extends T> entityPublisher) {
|
|
||||||
|
|
||||||
Assert.notNull(entityPublisher, "EntityPublisher must not be null!");
|
|
||||||
return entityPublisher.flatMap(this::save);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Index the given entity extracting index and type from entity metadata.
|
|
||||||
*
|
|
||||||
* @param entity must not be {@literal null}.
|
|
||||||
* @param <T>
|
|
||||||
* @return a {@link Mono} emitting the saved entity.
|
|
||||||
*/
|
|
||||||
default <T> Mono<T> save(T entity) {
|
|
||||||
return save(entity, getIndexCoordinatesFor(entity.getClass()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Index the entity, once available, under the given {@literal type} in the given {@literal index}. If the
|
|
||||||
* {@literal index} is {@literal null} or empty the index name provided via entity metadata is used. Same for the
|
|
||||||
* {@literal type}.
|
|
||||||
*
|
|
||||||
* @param entityPublisher must not be {@literal null}.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @param <T>
|
|
||||||
* @return a {@link Mono} emitting the saved entity.
|
|
||||||
*/
|
|
||||||
default <T> Mono<T> save(Mono<? extends T> entityPublisher, IndexCoordinates index) {
|
|
||||||
|
|
||||||
Assert.notNull(entityPublisher, "EntityPublisher must not be null!");
|
|
||||||
return entityPublisher.flatMap(it -> save(it, index));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Index the entity under the given {@literal type} in the given {@literal index}. If the {@literal index} is
|
|
||||||
* {@literal null} or empty the index name provided via entity metadata is used. Same for the {@literal type}.
|
|
||||||
*
|
|
||||||
* @param entity must not be {@literal null}.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @param <T>
|
|
||||||
* @return a {@link Mono} emitting the saved entity.
|
|
||||||
*/
|
|
||||||
<T> Mono<T> save(T entity, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the document with the given {@literal id} mapped onto the given {@literal entityType}.
|
|
||||||
*
|
|
||||||
* @param id the {@literal _id} of the document to fetch.
|
|
||||||
* @param entityType the domain type used for mapping the document.
|
|
||||||
* @param <T>
|
|
||||||
* @return {@link Mono#empty()} if not found.
|
|
||||||
*/
|
|
||||||
default <T> Mono<T> findById(String id, Class<T> entityType) {
|
|
||||||
return findById(id, entityType, getIndexCoordinatesFor(entityType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch the entity with given {@literal id}.
|
|
||||||
*
|
|
||||||
* @param id must not be {@literal null}.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @param <T>
|
|
||||||
* @return the {@link Mono} emitting the entity or signalling completion if none found.
|
|
||||||
*/
|
|
||||||
<T> Mono<T> findById(String id, Class<T> entityType, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an entity with given {@literal id} exists.
|
|
||||||
*
|
|
||||||
* @param id the {@literal _id} of the document to look for.
|
|
||||||
* @param entityType the domain type used.
|
|
||||||
* @return a {@link Mono} emitting {@literal true} if a matching document exists, {@literal false} otherwise.
|
|
||||||
*/
|
|
||||||
default Mono<Boolean> exists(String id, Class<?> entityType) {
|
|
||||||
return exists(id, entityType, getIndexCoordinatesFor(entityType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an entity with given {@literal id} exists.
|
|
||||||
*
|
|
||||||
* @param id the {@literal _id} of the document to look for.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @return a {@link Mono} emitting {@literal true} if a matching document exists, {@literal false} otherwise.
|
|
||||||
*/
|
|
||||||
Mono<Boolean> exists(String id, Class<?> entityType, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search the index for entities matching the given {@link Query query}. <br />
|
|
||||||
* {@link Pageable#isUnpaged() Unpaged} queries may overrule elasticsearch server defaults for page size by either
|
|
||||||
* delegating to the scroll API or using a max {@link org.elasticsearch.search.builder.SearchSourceBuilder#size(int)
|
|
||||||
* size}.
|
|
||||||
*
|
|
||||||
* @param query must not be {@literal null}.
|
|
||||||
* @param entityType must not be {@literal null}.
|
|
||||||
* @param <T>
|
|
||||||
* @return a {@link Flux} emitting matching entities one by one.
|
|
||||||
*/
|
|
||||||
default <T> Flux<T> find(Query query, Class<T> entityType) {
|
|
||||||
return find(query, entityType, entityType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search the index for entities matching the given {@link Query query}. <br />
|
|
||||||
* {@link Pageable#isUnpaged() Unpaged} queries may overrule elasticsearch server defaults for page size by either *
|
|
||||||
* delegating to the scroll API or using a max {@link org.elasticsearch.search.builder.SearchSourceBuilder#size(int) *
|
|
||||||
* size}.
|
|
||||||
*
|
|
||||||
* @param query must not be {@literal null}.
|
|
||||||
* @param entityType The entity type for mapping the query. Must not be {@literal null}.
|
|
||||||
* @param returnType The mapping target type. Must not be {@literal null}. Th
|
|
||||||
* @param <T>
|
|
||||||
* @return a {@link Flux} emitting matching entities one by one.
|
|
||||||
*/
|
|
||||||
default <T> Flux<T> find(Query query, Class<?> entityType, Class<T> returnType) {
|
|
||||||
return find(query, entityType, returnType, getIndexCoordinatesFor(entityType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search the index for entities matching the given {@link Query query}.
|
|
||||||
*
|
|
||||||
* @param query must not be {@literal null}.
|
|
||||||
* @param entityType must not be {@literal null}.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @param <T>
|
|
||||||
* @returnm a {@link Flux} emitting matching entities one by one.
|
|
||||||
*/
|
|
||||||
default <T> Flux<T> find(Query query, Class<T> entityType, IndexCoordinates index) {
|
|
||||||
return find(query, entityType, entityType, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search the index for entities matching the given {@link Query query}.
|
|
||||||
*
|
|
||||||
* @param query must not be {@literal null}.
|
|
||||||
* @param entityType must not be {@literal null}.
|
|
||||||
* @param resultType the projection result type.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @param <T>
|
|
||||||
* @return a {@link Flux} emitting matching entities one by one.
|
|
||||||
*/
|
|
||||||
<T> Flux<T> find(Query query, Class<?> entityType, Class<T> resultType, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count the number of documents matching the given {@link Query}.
|
|
||||||
*
|
|
||||||
* @param entityType must not be {@literal null}.
|
|
||||||
* @return a {@link Mono} emitting the nr of matching documents.
|
|
||||||
*/
|
|
||||||
default Mono<Long> count(Class<?> entityType) {
|
|
||||||
return count(new StringQuery(QueryBuilders.matchAllQuery().toString()), entityType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count the number of documents matching the given {@link Query}.
|
|
||||||
*
|
|
||||||
* @param query must not be {@literal null}.
|
|
||||||
* @param entityType must not be {@literal null}.
|
|
||||||
* @return a {@link Mono} emitting the nr of matching documents.
|
|
||||||
*/
|
|
||||||
default Mono<Long> count(Query query, Class<?> entityType) {
|
|
||||||
return count(query, entityType, getIndexCoordinatesFor(entityType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count the number of documents matching the given {@link Query}.
|
|
||||||
*
|
|
||||||
* @param query must not be {@literal null}.
|
|
||||||
* @param entityType must not be {@literal null}.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @return a {@link Mono} emitting the nr of matching documents.
|
|
||||||
*/
|
|
||||||
Mono<Long> count(Query query, Class<?> entityType, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given entity extracting index and type from entity metadata.
|
|
||||||
*
|
|
||||||
* @param entity must not be {@literal null}.
|
|
||||||
* @return a {@link Mono} emitting the {@literal id} of the removed document.
|
|
||||||
*/
|
|
||||||
default Mono<String> delete(Object entity) {
|
|
||||||
return delete(entity, getIndexCoordinatesFor(entity.getClass()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given entity extracting index and type from entity metadata.
|
|
||||||
*
|
|
||||||
* @param entity must not be {@literal null}.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @return a {@link Mono} emitting the {@literal id} of the removed document.
|
|
||||||
*/
|
|
||||||
Mono<String> delete(Object entity, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the entity with given {@literal id}.
|
|
||||||
*
|
|
||||||
* @param id must not be {@literal null}.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @return a {@link Mono} emitting the {@literal id} of the removed document.
|
|
||||||
*/
|
|
||||||
default Mono<String> deleteById(String id, IndexCoordinates index) {
|
|
||||||
|
|
||||||
Assert.notNull(index, "Index must not be null!");
|
|
||||||
|
|
||||||
return deleteById(id, Object.class, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the entity with given {@literal id} extracting index and type from entity metadata.
|
|
||||||
*
|
|
||||||
* @param id must not be {@literal null}.
|
|
||||||
* @param entityType must not be {@literal null}.
|
|
||||||
* @return a {@link Mono} emitting the {@literal id} of the removed document.
|
|
||||||
*/
|
|
||||||
default Mono<String> deleteById(String id, Class<?> entityType) {
|
|
||||||
return deleteById(id, entityType, getIndexCoordinatesFor(entityType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the entity with given {@literal id} extracting index and type from entity metadata.
|
|
||||||
*
|
|
||||||
* @param id must not be {@literal null}.
|
|
||||||
* @param entityType must not be {@literal null}.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @return a {@link Mono} emitting the {@literal id} of the removed document.
|
|
||||||
*/
|
|
||||||
Mono<String> deleteById(String id, Class<?> entityType, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the documents matching the given {@link Query} extracting index and type from entity metadata.
|
|
||||||
*
|
|
||||||
* @param query must not be {@literal null}.
|
|
||||||
* @param entityType must not be {@literal null}.
|
|
||||||
* @return a {@link Mono} emitting the number of the removed documents.
|
|
||||||
*/
|
|
||||||
default Mono<Long> deleteBy(Query query, Class<?> entityType) {
|
|
||||||
return deleteBy(query, entityType, getIndexCoordinatesFor(entityType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the documents matching the given {@link Query} extracting index and type from entity metadata.
|
|
||||||
*
|
|
||||||
* @param query must not be {@literal null}.
|
|
||||||
* @param entityType must not be {@literal null}.
|
|
||||||
* @param index the target index, must not be {@literal null}
|
|
||||||
* @return a {@link Mono} emitting the number of the removed documents.
|
|
||||||
*/
|
|
||||||
Mono<Long> deleteBy(Query query, Class<?> entityType, IndexCoordinates index);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the {@link ElasticsearchConverter} used.
|
* Get the {@link ElasticsearchConverter} used.
|
||||||
*
|
*
|
||||||
@ -322,10 +60,7 @@ public interface ReactiveElasticsearchOperations {
|
|||||||
* @return the IndexCoordinates defined on the entity.
|
* @return the IndexCoordinates defined on the entity.
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
default IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
|
IndexCoordinates getIndexCoordinatesFor(Class<?> clazz);
|
||||||
ElasticsearchPersistentEntity entity = getPersistentEntityFor(clazz);
|
|
||||||
return IndexCoordinates.of(entity.getIndexName()).withTypes(entity.getIndexType());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback interface to be used with {@link #execute(ClientCallback)} for operating directly on
|
* Callback interface to be used with {@link #execute(ClientCallback)} for operating directly on
|
||||||
|
@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.core;
|
|||||||
|
|
||||||
import static org.elasticsearch.index.VersionType.*;
|
import static org.elasticsearch.index.VersionType.*;
|
||||||
|
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
@ -48,7 +49,6 @@ import org.elasticsearch.search.sort.SortOrder;
|
|||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.elasticsearch.NoSuchIndexException;
|
import org.springframework.data.elasticsearch.NoSuchIndexException;
|
||||||
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
|
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
|
||||||
@ -93,6 +93,7 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
private @Nullable RefreshPolicy refreshPolicy = RefreshPolicy.IMMEDIATE;
|
private @Nullable RefreshPolicy refreshPolicy = RefreshPolicy.IMMEDIATE;
|
||||||
private @Nullable IndicesOptions indicesOptions = IndicesOptions.strictExpandOpenAndForbidClosedIgnoreThrottled();
|
private @Nullable IndicesOptions indicesOptions = IndicesOptions.strictExpandOpenAndForbidClosedIgnoreThrottled();
|
||||||
|
|
||||||
|
// region Initialization
|
||||||
public ReactiveElasticsearchTemplate(ReactiveElasticsearchClient client) {
|
public ReactiveElasticsearchTemplate(ReactiveElasticsearchClient client) {
|
||||||
this(client, new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext()));
|
this(client, new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext()));
|
||||||
}
|
}
|
||||||
@ -109,19 +110,12 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
this.operations = new EntityOperations(this.mappingContext);
|
this.operations = new EntityOperations(this.mappingContext);
|
||||||
this.requestFactory = new RequestFactory(converter);
|
this.requestFactory = new RequestFactory(converter);
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region DocumentOperations
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#exctute(ClientCallback)
|
* @see org.springframework.data.elasticsearch.core.ReactiveDElasticsearchOperations#index(Object, IndexCoordinates)
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public <T> Publisher<T> execute(ClientCallback<Publisher<T>> callback) {
|
|
||||||
return Flux.defer(() -> callback.doWithClient(getClient())).onErrorMap(this::translateException);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#index(Object, IndexCoordinates)
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> Mono<T> save(T entity, IndexCoordinates index) {
|
public <T> Mono<T> save(T entity, IndexCoordinates index) {
|
||||||
@ -136,6 +130,51 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Mono<T> save(T entity) {
|
||||||
|
return save(entity, getIndexCoordinatesFor(entity.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customization hook on the actual execution result {@link Publisher}. <br />
|
||||||
|
* You know what you're doing here? Well fair enough, go ahead on your own risk.
|
||||||
|
*
|
||||||
|
* @param request the already prepared {@link IndexRequest} ready to be executed.
|
||||||
|
* @return a {@link Mono} emitting the result of the operation.
|
||||||
|
*/
|
||||||
|
protected Mono<IndexResponse> doIndex(IndexRequest request) {
|
||||||
|
return Mono.from(execute(client -> client.index(request)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customization hook on the actual execution result {@link Publisher}. <br />
|
||||||
|
*
|
||||||
|
* @param request the already prepared {@link GetRequest} ready to be executed.
|
||||||
|
* @return a {@link Mono} emitting the result of the operation.
|
||||||
|
*/
|
||||||
|
protected Mono<GetResult> doFindById(GetRequest request) {
|
||||||
|
|
||||||
|
return Mono.from(execute(client -> client.get(request))) //
|
||||||
|
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Boolean> exists(String id, Class<?> entityType) {
|
||||||
|
return exists(id, entityType, getIndexCoordinatesFor(entityType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customization hook on the actual execution result {@link Publisher}. <br />
|
||||||
|
*
|
||||||
|
* @param request the already prepared {@link GetRequest} ready to be executed.
|
||||||
|
* @return a {@link Mono} emitting the result of the operation.
|
||||||
|
*/
|
||||||
|
protected Mono<Boolean> doExists(GetRequest request) {
|
||||||
|
|
||||||
|
return Mono.from(execute(client -> client.exists(request))) //
|
||||||
|
.onErrorReturn(NoSuchIndexException.class, false);
|
||||||
|
}
|
||||||
|
|
||||||
private Mono<IndexResponse> doIndex(Object value, AdaptibleEntity<?> entity, IndexCoordinates index) {
|
private Mono<IndexResponse> doIndex(Object value, AdaptibleEntity<?> entity, IndexCoordinates index) {
|
||||||
|
|
||||||
return Mono.defer(() -> {
|
return Mono.defer(() -> {
|
||||||
@ -162,6 +201,11 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Mono<T> findById(String id, Class<T> entityType) {
|
||||||
|
return findById(id, entityType, getIndexCoordinatesFor(entityType));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#findById(String, Class, IndexCoordinates)
|
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#findById(String, Class, IndexCoordinates)
|
||||||
@ -200,6 +244,179 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
return Mono.defer(() -> doExists(new GetRequest(index.getIndexName(), index.getTypeName(), id)));
|
return Mono.defer(() -> doExists(new GetRequest(index.getIndexName(), index.getTypeName(), id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#delete(Object, String, String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Mono<String> delete(Object entity, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Entity<?> elasticsearchEntity = operations.forEntity(entity);
|
||||||
|
|
||||||
|
return Mono.defer(() -> doDeleteById(entity, converter.convertId(elasticsearchEntity.getId()),
|
||||||
|
elasticsearchEntity.getPersistentEntity(), index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#delete(String, Class, IndexCoordinates)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Mono<String> deleteById(String id, Class<?> entityType, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(id, "Id must not be null!");
|
||||||
|
|
||||||
|
return doDeleteById(null, id, getPersistentEntityFor(entityType), index);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<String> delete(Object entity) {
|
||||||
|
return delete(entity, getIndexCoordinatesFor(entity.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<String> deleteById(String id, Class<?> entityType) {
|
||||||
|
return deleteById(id, entityType, getIndexCoordinatesFor(entityType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mono<String> doDeleteById(@Nullable Object source, String id, ElasticsearchPersistentEntity<?> entity,
|
||||||
|
IndexCoordinates index) {
|
||||||
|
|
||||||
|
return Mono.defer(() -> {
|
||||||
|
|
||||||
|
return doDelete(prepareDeleteRequest(source, new DeleteRequest(index.getIndexName(), index.getTypeName(), id)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#deleteBy(Query, Class, IndexCoordinates)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Mono<Long> deleteBy(Query query, Class<?> entityType, IndexCoordinates index) {
|
||||||
|
|
||||||
|
Assert.notNull(query, "Query must not be null!");
|
||||||
|
|
||||||
|
return doDeleteBy(query, getPersistentEntityFor(entityType), index).map(BulkByScrollResponse::getDeleted)
|
||||||
|
.publishNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Long> deleteBy(Query query, Class<?> entityType) {
|
||||||
|
return deleteBy(query, entityType, getIndexCoordinatesFor(entityType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Flux<BulkByScrollResponse> doDeleteBy(Query query, ElasticsearchPersistentEntity<?> entity,
|
||||||
|
IndexCoordinates index) {
|
||||||
|
|
||||||
|
return Flux.defer(() -> {
|
||||||
|
DeleteByQueryRequest request = new DeleteByQueryRequest(index.getIndexNames());
|
||||||
|
request.types(index.getTypeNames());
|
||||||
|
request.setQuery(mappedQuery(query, entity));
|
||||||
|
|
||||||
|
return doDeleteBy(prepareDeleteByRequest(request));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customization hook on the actual execution result {@link Publisher}. <br />
|
||||||
|
*
|
||||||
|
* @param request the already prepared {@link DeleteRequest} ready to be executed.
|
||||||
|
* @return a {@link Mono} emitting the result of the operation.
|
||||||
|
*/
|
||||||
|
protected Mono<String> doDelete(DeleteRequest request) {
|
||||||
|
|
||||||
|
return Mono.from(execute(client -> client.delete(request))) //
|
||||||
|
|
||||||
|
.flatMap(it -> {
|
||||||
|
|
||||||
|
if (HttpStatus.valueOf(it.status().getStatus()).equals(HttpStatus.NOT_FOUND)) {
|
||||||
|
return Mono.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Mono.just(it.getId());
|
||||||
|
}) //
|
||||||
|
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customization hook on the actual execution result {@link Publisher}. <br />
|
||||||
|
*
|
||||||
|
* @param request the already prepared {@link DeleteByQueryRequest} ready to be executed.
|
||||||
|
* @return a {@link Mono} emitting the result of the operation.
|
||||||
|
*/
|
||||||
|
protected Mono<BulkByScrollResponse> doDeleteBy(DeleteByQueryRequest request) {
|
||||||
|
|
||||||
|
return Mono.from(execute(client -> client.deleteBy(request))) //
|
||||||
|
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customization hook to modify a generated {@link DeleteRequest} prior to its execution. Eg. by setting the
|
||||||
|
* {@link WriteRequest#setRefreshPolicy(String) refresh policy} if applicable.
|
||||||
|
*
|
||||||
|
* @param source the source object the {@link DeleteRequest} was derived from. My be {@literal null} if using the
|
||||||
|
* {@literal id} directly.
|
||||||
|
* @param request the generated {@link DeleteRequest}.
|
||||||
|
* @return never {@literal null}.
|
||||||
|
*/
|
||||||
|
protected DeleteRequest prepareDeleteRequest(@Nullable Object source, DeleteRequest request) {
|
||||||
|
return prepareWriteRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customization hook to modify a generated {@link DeleteByQueryRequest} prior to its execution. Eg. by setting the
|
||||||
|
* {@link WriteRequest#setRefreshPolicy(String) refresh policy} if applicable.
|
||||||
|
*
|
||||||
|
* @param request the generated {@link DeleteByQueryRequest}.
|
||||||
|
* @return never {@literal null}.
|
||||||
|
*/
|
||||||
|
protected DeleteByQueryRequest prepareDeleteByRequest(DeleteByQueryRequest request) {
|
||||||
|
|
||||||
|
if (refreshPolicy != null && !RefreshPolicy.NONE.equals(refreshPolicy)) {
|
||||||
|
request = request.setRefresh(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indicesOptions != null) {
|
||||||
|
request = request.setIndicesOptions(indicesOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customization hook to modify a generated {@link IndexRequest} prior to its execution. Eg. by setting the
|
||||||
|
* {@link WriteRequest#setRefreshPolicy(String) refresh policy} if applicable.
|
||||||
|
*
|
||||||
|
* @param source the source object the {@link IndexRequest} was derived from.
|
||||||
|
* @param request the generated {@link IndexRequest}.
|
||||||
|
* @return never {@literal null}.
|
||||||
|
*/
|
||||||
|
protected IndexRequest prepareIndexRequest(Object source, IndexRequest request) {
|
||||||
|
return prepareWriteRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre process the write request before it is sent to the server, eg. by setting the
|
||||||
|
* {@link WriteRequest#setRefreshPolicy(String) refresh policy} if applicable.
|
||||||
|
*
|
||||||
|
* @param request must not be {@literal null}.
|
||||||
|
* @param <R>
|
||||||
|
* @return the processed {@link WriteRequest}.
|
||||||
|
*/
|
||||||
|
protected <R extends WriteRequest<R>> R prepareWriteRequest(R request) {
|
||||||
|
|
||||||
|
if (refreshPolicy == null) {
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
return request.setRefreshPolicy(refreshPolicy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region SearchOperations
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#find(Query, Class, Class, IndexCoordinates)
|
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#find(Query, Class, Class, IndexCoordinates)
|
||||||
@ -210,6 +427,11 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
return doFind(query, entityType, index).map(it -> converter.mapDocument(DocumentAdapters.from(it), resultType));
|
return doFind(query, entityType, index).map(it -> converter.mapDocument(DocumentAdapters.from(it), resultType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Flux<T> find(Query query, Class<?> entityType, Class<T> returnType) {
|
||||||
|
return find(query, entityType, returnType, getIndexCoordinatesFor(entityType));
|
||||||
|
}
|
||||||
|
|
||||||
private Flux<SearchHit> doFind(Query query, Class<?> clazz, IndexCoordinates index) {
|
private Flux<SearchHit> doFind(Query query, Class<?> clazz, IndexCoordinates index) {
|
||||||
|
|
||||||
return Flux.defer(() -> {
|
return Flux.defer(() -> {
|
||||||
@ -227,6 +449,11 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Long> count(Query query, Class<?> entityType) {
|
||||||
|
return count(query, entityType, getIndexCoordinatesFor(entityType));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Long> count(Query query, Class<?> entityType, IndexCoordinates index) {
|
public Mono<Long> count(Query query, Class<?> entityType, IndexCoordinates index) {
|
||||||
return doCount(query, getPersistentEntityFor(entityType), index);
|
return doCount(query, getPersistentEntityFor(entityType), index);
|
||||||
@ -279,235 +506,6 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#delete(Object, String, String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Mono<String> delete(Object entity, IndexCoordinates index) {
|
|
||||||
|
|
||||||
Entity<?> elasticsearchEntity = operations.forEntity(entity);
|
|
||||||
|
|
||||||
return Mono.defer(() -> doDeleteById(entity, converter.convertId(elasticsearchEntity.getId()),
|
|
||||||
elasticsearchEntity.getPersistentEntity(), index));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#delete(String, Class, IndexCoordinates)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Mono<String> deleteById(String id, Class<?> entityType, IndexCoordinates index) {
|
|
||||||
|
|
||||||
Assert.notNull(id, "Id must not be null!");
|
|
||||||
|
|
||||||
return doDeleteById(null, id, getPersistentEntityFor(entityType), index);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private Mono<String> doDeleteById(@Nullable Object source, String id, ElasticsearchPersistentEntity<?> entity,
|
|
||||||
IndexCoordinates index) {
|
|
||||||
|
|
||||||
return Mono.defer(() -> {
|
|
||||||
|
|
||||||
return doDelete(prepareDeleteRequest(source, new DeleteRequest(index.getIndexName(), index.getTypeName(), id)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#deleteBy(Query, Class, IndexCoordinates)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Mono<Long> deleteBy(Query query, Class<?> entityType, IndexCoordinates index) {
|
|
||||||
|
|
||||||
Assert.notNull(query, "Query must not be null!");
|
|
||||||
|
|
||||||
return doDeleteBy(query, getPersistentEntityFor(entityType), index).map(BulkByScrollResponse::getDeleted)
|
|
||||||
.publishNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Flux<BulkByScrollResponse> doDeleteBy(Query query, ElasticsearchPersistentEntity<?> entity,
|
|
||||||
IndexCoordinates index) {
|
|
||||||
|
|
||||||
return Flux.defer(() -> {
|
|
||||||
DeleteByQueryRequest request = new DeleteByQueryRequest(index.getIndexNames());
|
|
||||||
request.types(index.getTypeNames());
|
|
||||||
request.setQuery(mappedQuery(query, entity));
|
|
||||||
|
|
||||||
return doDeleteBy(prepareDeleteByRequest(request));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Property Setters / Getters
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the default {@link RefreshPolicy} to apply when writing to Elasticsearch.
|
|
||||||
*
|
|
||||||
* @param refreshPolicy can be {@literal null}.
|
|
||||||
*/
|
|
||||||
public void setRefreshPolicy(@Nullable RefreshPolicy refreshPolicy) {
|
|
||||||
this.refreshPolicy = refreshPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the default {@link IndicesOptions} for {@link SearchRequest search requests}.
|
|
||||||
*
|
|
||||||
* @param indicesOptions can be {@literal null}.
|
|
||||||
*/
|
|
||||||
public void setIndicesOptions(@Nullable IndicesOptions indicesOptions) {
|
|
||||||
this.indicesOptions = indicesOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#getElasticsearchConverter()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public ElasticsearchConverter getElasticsearchConverter() {
|
|
||||||
return converter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Customization Hooks
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the {@link ReactiveElasticsearchClient} to operate upon.
|
|
||||||
*
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
protected ReactiveElasticsearchClient getClient() {
|
|
||||||
return this.client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pre process the write request before it is sent to the server, eg. by setting the
|
|
||||||
* {@link WriteRequest#setRefreshPolicy(String) refresh policy} if applicable.
|
|
||||||
*
|
|
||||||
* @param request must not be {@literal null}.
|
|
||||||
* @param <R>
|
|
||||||
* @return the processed {@link WriteRequest}.
|
|
||||||
*/
|
|
||||||
protected <R extends WriteRequest<R>> R prepareWriteRequest(R request) {
|
|
||||||
|
|
||||||
if (refreshPolicy == null) {
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
return request.setRefreshPolicy(refreshPolicy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customization hook to modify a generated {@link IndexRequest} prior to its execution. Eg. by setting the
|
|
||||||
* {@link WriteRequest#setRefreshPolicy(String) refresh policy} if applicable.
|
|
||||||
*
|
|
||||||
* @param source the source object the {@link IndexRequest} was derived from.
|
|
||||||
* @param request the generated {@link IndexRequest}.
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
protected IndexRequest prepareIndexRequest(Object source, IndexRequest request) {
|
|
||||||
return prepareWriteRequest(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customization hook to modify a generated {@link SearchRequest} prior to its execution. Eg. by setting the
|
|
||||||
* {@link SearchRequest#indicesOptions(IndicesOptions) indices options} if applicable.
|
|
||||||
*
|
|
||||||
* @param request the generated {@link CountRequest}.
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
protected CountRequest prepareCountRequest(CountRequest request) {
|
|
||||||
|
|
||||||
if (indicesOptions == null) {
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
return request.indicesOptions(indicesOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customization hook to modify a generated {@link SearchRequest} prior to its execution. Eg. by setting the
|
|
||||||
* {@link SearchRequest#indicesOptions(IndicesOptions) indices options} if applicable.
|
|
||||||
*
|
|
||||||
* @param request the generated {@link SearchRequest}.
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
protected SearchRequest prepareSearchRequest(SearchRequest request) {
|
|
||||||
|
|
||||||
if (indicesOptions == null) {
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
return request.indicesOptions(indicesOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customization hook to modify a generated {@link DeleteRequest} prior to its execution. Eg. by setting the
|
|
||||||
* {@link WriteRequest#setRefreshPolicy(String) refresh policy} if applicable.
|
|
||||||
*
|
|
||||||
* @param source the source object the {@link DeleteRequest} was derived from. My be {@literal null} if using the
|
|
||||||
* {@literal id} directly.
|
|
||||||
* @param request the generated {@link DeleteRequest}.
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
protected DeleteRequest prepareDeleteRequest(@Nullable Object source, DeleteRequest request) {
|
|
||||||
return prepareWriteRequest(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customization hook to modify a generated {@link DeleteByQueryRequest} prior to its execution. Eg. by setting the
|
|
||||||
* {@link WriteRequest#setRefreshPolicy(String) refresh policy} if applicable.
|
|
||||||
*
|
|
||||||
* @param request the generated {@link DeleteByQueryRequest}.
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
protected DeleteByQueryRequest prepareDeleteByRequest(DeleteByQueryRequest request) {
|
|
||||||
|
|
||||||
if (refreshPolicy != null && !RefreshPolicy.NONE.equals(refreshPolicy)) {
|
|
||||||
request = request.setRefresh(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indicesOptions != null) {
|
|
||||||
request = request.setIndicesOptions(indicesOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customization hook on the actual execution result {@link Publisher}. <br />
|
|
||||||
* You know what you're doing here? Well fair enough, go ahead on your own risk.
|
|
||||||
*
|
|
||||||
* @param request the already prepared {@link IndexRequest} ready to be executed.
|
|
||||||
* @return a {@link Mono} emitting the result of the operation.
|
|
||||||
*/
|
|
||||||
protected Mono<IndexResponse> doIndex(IndexRequest request) {
|
|
||||||
return Mono.from(execute(client -> client.index(request)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customization hook on the actual execution result {@link Publisher}. <br />
|
|
||||||
*
|
|
||||||
* @param request the already prepared {@link GetRequest} ready to be executed.
|
|
||||||
* @return a {@link Mono} emitting the result of the operation.
|
|
||||||
*/
|
|
||||||
protected Mono<GetResult> doFindById(GetRequest request) {
|
|
||||||
|
|
||||||
return Mono.from(execute(client -> client.get(request))) //
|
|
||||||
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customization hook on the actual execution result {@link Publisher}. <br />
|
|
||||||
*
|
|
||||||
* @param request the already prepared {@link GetRequest} ready to be executed.
|
|
||||||
* @return a {@link Mono} emitting the result of the operation.
|
|
||||||
*/
|
|
||||||
protected Mono<Boolean> doExists(GetRequest request) {
|
|
||||||
|
|
||||||
return Mono.from(execute(client -> client.exists(request))) //
|
|
||||||
.onErrorReturn(NoSuchIndexException.class, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Customization hook on the actual execution result {@link Publisher}. <br />
|
* Customization hook on the actual execution result {@link Publisher}. <br />
|
||||||
*
|
*
|
||||||
@ -556,41 +554,35 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
|
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Nullable
|
||||||
* Customization hook on the actual execution result {@link Publisher}. <br />
|
private QueryBuilder mappedFilterQuery(Query query, ElasticsearchPersistentEntity<?> entity) {
|
||||||
*
|
|
||||||
* @param request the already prepared {@link DeleteRequest} ready to be executed.
|
|
||||||
* @return a {@link Mono} emitting the result of the operation.
|
|
||||||
*/
|
|
||||||
protected Mono<String> doDelete(DeleteRequest request) {
|
|
||||||
|
|
||||||
return Mono.from(execute(client -> client.delete(request))) //
|
if (query instanceof NativeSearchQuery) {
|
||||||
|
return ((NativeSearchQuery) query).getFilter();
|
||||||
|
}
|
||||||
|
|
||||||
.flatMap(it -> {
|
return null;
|
||||||
|
|
||||||
if (HttpStatus.valueOf(it.status().getStatus()).equals(HttpStatus.NOT_FOUND)) {
|
|
||||||
return Mono.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Mono.just(it.getId());
|
|
||||||
}) //
|
|
||||||
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private QueryBuilder mappedQuery(Query query, ElasticsearchPersistentEntity<?> entity) {
|
||||||
* Customization hook on the actual execution result {@link Publisher}. <br />
|
|
||||||
*
|
|
||||||
* @param request the already prepared {@link DeleteByQueryRequest} ready to be executed.
|
|
||||||
* @return a {@link Mono} emitting the result of the operation.
|
|
||||||
*/
|
|
||||||
protected Mono<BulkByScrollResponse> doDeleteBy(DeleteByQueryRequest request) {
|
|
||||||
|
|
||||||
return Mono.from(execute(client -> client.deleteBy(request))) //
|
// TODO: we need to actually map the fields to the according field names!
|
||||||
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
|
|
||||||
|
QueryBuilder elasticsearchQuery = null;
|
||||||
|
|
||||||
|
if (query instanceof CriteriaQuery) {
|
||||||
|
elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(((CriteriaQuery) query).getCriteria());
|
||||||
|
} else if (query instanceof StringQuery) {
|
||||||
|
elasticsearchQuery = new WrapperQueryBuilder(((StringQuery) query).getSource());
|
||||||
|
} else if (query instanceof NativeSearchQuery) {
|
||||||
|
elasticsearchQuery = ((NativeSearchQuery) query).getQuery();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(String.format("Unknown query type '%s'.", query.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return elasticsearchQuery != null ? elasticsearchQuery : QueryBuilders.matchAllQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
// private helpers
|
|
||||||
|
|
||||||
private static List<FieldSortBuilder> sort(Query query, ElasticsearchPersistentEntity<?> entity) {
|
private static List<FieldSortBuilder> sort(Query query, ElasticsearchPersistentEntity<?> entity) {
|
||||||
|
|
||||||
if (query.getSort() == null || query.getSort().isUnsorted()) {
|
if (query.getSort() == null || query.getSort().isUnsorted()) {
|
||||||
@ -618,33 +610,82 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
return mappedSort;
|
return mappedSort;
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryBuilder mappedQuery(Query query, ElasticsearchPersistentEntity<?> entity) {
|
/**
|
||||||
|
* Customization hook to modify a generated {@link SearchRequest} prior to its execution. Eg. by setting the
|
||||||
|
* {@link SearchRequest#indicesOptions(IndicesOptions) indices options} if applicable.
|
||||||
|
*
|
||||||
|
* @param request the generated {@link CountRequest}.
|
||||||
|
* @return never {@literal null}.
|
||||||
|
*/
|
||||||
|
protected CountRequest prepareCountRequest(CountRequest request) {
|
||||||
|
|
||||||
// TODO: we need to actually map the fields to the according field names!
|
if (indicesOptions == null) {
|
||||||
|
return request;
|
||||||
QueryBuilder elasticsearchQuery = null;
|
|
||||||
|
|
||||||
if (query instanceof CriteriaQuery) {
|
|
||||||
elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(((CriteriaQuery) query).getCriteria());
|
|
||||||
} else if (query instanceof StringQuery) {
|
|
||||||
elasticsearchQuery = new WrapperQueryBuilder(((StringQuery) query).getSource());
|
|
||||||
} else if (query instanceof NativeSearchQuery) {
|
|
||||||
elasticsearchQuery = ((NativeSearchQuery) query).getQuery();
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(String.format("Unknown query type '%s'.", query.getClass()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return elasticsearchQuery != null ? elasticsearchQuery : QueryBuilders.matchAllQuery();
|
return request.indicesOptions(indicesOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
/**
|
||||||
private QueryBuilder mappedFilterQuery(Query query, ElasticsearchPersistentEntity<?> entity) {
|
* Customization hook to modify a generated {@link SearchRequest} prior to its execution. Eg. by setting the
|
||||||
|
* {@link SearchRequest#indicesOptions(IndicesOptions) indices options} if applicable.
|
||||||
|
*
|
||||||
|
* @param request the generated {@link SearchRequest}.
|
||||||
|
* @return never {@literal null}.
|
||||||
|
*/
|
||||||
|
protected SearchRequest prepareSearchRequest(SearchRequest request) {
|
||||||
|
|
||||||
if (query instanceof NativeSearchQuery) {
|
if (indicesOptions == null) {
|
||||||
return ((NativeSearchQuery) query).getFilter();
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return request.indicesOptions(indicesOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Helper methods
|
||||||
|
// Property Setters / Getters
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default {@link RefreshPolicy} to apply when writing to Elasticsearch.
|
||||||
|
*
|
||||||
|
* @param refreshPolicy can be {@literal null}.
|
||||||
|
*/
|
||||||
|
public void setRefreshPolicy(@Nullable RefreshPolicy refreshPolicy) {
|
||||||
|
this.refreshPolicy = refreshPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default {@link IndicesOptions} for {@link SearchRequest search requests}.
|
||||||
|
*
|
||||||
|
* @param indicesOptions can be {@literal null}.
|
||||||
|
*/
|
||||||
|
public void setIndicesOptions(@Nullable IndicesOptions indicesOptions) {
|
||||||
|
this.indicesOptions = indicesOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#exctute(ClientCallback)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> Publisher<T> execute(ClientCallback<Publisher<T>> callback) {
|
||||||
|
return Flux.defer(() -> callback.doWithClient(getClient())).onErrorMap(this::translateException);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#getElasticsearchConverter()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ElasticsearchConverter getElasticsearchConverter() {
|
||||||
|
return converter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
|
||||||
|
return getPersistentEntityFor(clazz).getIndexCoordinates();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -661,4 +702,16 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
|||||||
|
|
||||||
return potentiallyTranslatedException != null ? potentiallyTranslatedException : throwable;
|
return potentiallyTranslatedException != null ? potentiallyTranslatedException : throwable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the {@link ReactiveElasticsearchClient} to operate upon.
|
||||||
|
*
|
||||||
|
* @return never {@literal null}.
|
||||||
|
*/
|
||||||
|
protected ReactiveElasticsearchClient getClient() {
|
||||||
|
return this.client;
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.StringQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reactive operations for the
|
||||||
|
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search.html">Elasticsearch Document
|
||||||
|
* APIs</a>.
|
||||||
|
*
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public interface ReactiveSearchOperations {
|
||||||
|
/**
|
||||||
|
* Search the index for entities matching the given {@link Query query}. <br />
|
||||||
|
* {@link Pageable#isUnpaged() Unpaged} queries may overrule elasticsearch server defaults for page size by either
|
||||||
|
* delegating to the scroll API or using a max {@link org.elasticsearch.search.builder.SearchSourceBuilder#size(int)
|
||||||
|
* size}.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @param <T>
|
||||||
|
* @return a {@link Flux} emitting matching entities one by one.
|
||||||
|
*/
|
||||||
|
default <T> Flux<T> find(Query query, Class<T> entityType) {
|
||||||
|
return find(query, entityType, entityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search the index for entities matching the given {@link Query query}. <br />
|
||||||
|
* {@link Pageable#isUnpaged() Unpaged} queries may overrule elasticsearch server defaults for page size by either *
|
||||||
|
* delegating to the scroll API or using a max {@link org.elasticsearch.search.builder.SearchSourceBuilder#size(int) *
|
||||||
|
* size}.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param entityType The entity type for mapping the query. Must not be {@literal null}.
|
||||||
|
* @param returnType The mapping target type. Must not be {@literal null}. Th
|
||||||
|
* @param <T>
|
||||||
|
* @return a {@link Flux} emitting matching entities one by one.
|
||||||
|
*/
|
||||||
|
<T> Flux<T> find(Query query, Class<?> entityType, Class<T> returnType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search the index for entities matching the given {@link Query query}.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @param <T>
|
||||||
|
* @returnm a {@link Flux} emitting matching entities one by one.
|
||||||
|
*/
|
||||||
|
default <T> Flux<T> find(Query query, Class<T> entityType, IndexCoordinates index) {
|
||||||
|
return find(query, entityType, entityType, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search the index for entities matching the given {@link Query query}.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @param resultType the projection result type.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @param <T>
|
||||||
|
* @return a {@link Flux} emitting matching entities one by one.
|
||||||
|
*/
|
||||||
|
<T> Flux<T> find(Query query, Class<?> entityType, Class<T> resultType, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of documents matching the given {@link Query}.
|
||||||
|
*
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @return a {@link Mono} emitting the nr of matching documents.
|
||||||
|
*/
|
||||||
|
default Mono<Long> count(Class<?> entityType) {
|
||||||
|
return count(new StringQuery(QueryBuilders.matchAllQuery().toString()), entityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of documents matching the given {@link Query}.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @return a {@link Mono} emitting the nr of matching documents.
|
||||||
|
*/
|
||||||
|
Mono<Long> count(Query query, Class<?> entityType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of documents matching the given {@link Query}.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @param index the target index, must not be {@literal null}
|
||||||
|
* @return a {@link Mono} emitting the nr of matching documents.
|
||||||
|
*/
|
||||||
|
Mono<Long> count(Query query, Class<?> entityType, IndexCoordinates index);
|
||||||
|
|
||||||
|
}
|
@ -66,6 +66,7 @@ import org.springframework.data.elasticsearch.ElasticsearchException;
|
|||||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.*;
|
import org.springframework.data.elasticsearch.core.query.*;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
|
import org.elasticsearch.search.suggest.SuggestBuilder;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
|
import org.springframework.data.util.CloseableIterator;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The operations for the
|
||||||
|
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search.html">Elasticsearch Document
|
||||||
|
* APIs</a>.
|
||||||
|
*
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public interface SearchOperations {
|
||||||
|
/**
|
||||||
|
* Return number of elements found by given query.
|
||||||
|
*
|
||||||
|
* @param query the query to execute
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return count
|
||||||
|
*/
|
||||||
|
default long count(Query query, IndexCoordinates index) {
|
||||||
|
return count(query, null, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return number of elements found by given query
|
||||||
|
*
|
||||||
|
* @param query the query to execute
|
||||||
|
* @param clazz the entity clazz used for property mapping
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return count
|
||||||
|
*/
|
||||||
|
long count(Query query, @Nullable Class<?> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
<T> T query(Query query, ResultsExtractor<T> resultsExtractor, Class<T> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the query against elasticsearch and return the first returned object.
|
||||||
|
*
|
||||||
|
* @param query the query to execute
|
||||||
|
* @param clazz the entity clazz used for property mapping
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return the first matching object
|
||||||
|
*/
|
||||||
|
default <T> T queryForObject(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||||
|
List<T> content = queryForPage(query, clazz, index).getContent();
|
||||||
|
return content.isEmpty() ? null : content.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the query against elasticsearch and return result as {@link Page}.
|
||||||
|
*
|
||||||
|
* @param query the query to execute
|
||||||
|
* @param clazz the entity clazz used for property mapping
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return a page with aggregations
|
||||||
|
*/
|
||||||
|
<T> AggregatedPage<T> queryForPage(Query query, Class<T> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the multi-search against elasticsearch and return result as {@link List} of {@link Page}
|
||||||
|
*
|
||||||
|
* @param queries the queries
|
||||||
|
* @param clazz the entity clazz used for property mapping
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return list of pages with the results
|
||||||
|
*/
|
||||||
|
<T> List<Page<T>> queryForPage(List<? extends Query> queries, Class<T> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the multi-search against elasticsearch and return result as {@link List} of {@link Page}
|
||||||
|
*
|
||||||
|
* @param queries the queries
|
||||||
|
* @param classes the entity classes used for the queries
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return list of pages with the results
|
||||||
|
*/
|
||||||
|
List<Page<?>> queryForPage(List<? extends Query> queries, List<Class<?>> classes, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the given {@link Query} against elasticsearch and return result as {@link CloseableIterator}.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* @param <T> element return type
|
||||||
|
* @param query the query to execute
|
||||||
|
* @param clazz the entity clazz used for property mapping
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return a {@link CloseableIterator} that wraps an Elasticsearch scroll context that needs to be closed in case of *
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
|
<T> CloseableIterator<T> stream(Query query, Class<T> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the criteria query against elasticsearch and return result as {@link List}
|
||||||
|
*
|
||||||
|
* @param query the query to execute
|
||||||
|
* @param clazz the entity clazz used for property mapping
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @param <T> element return type
|
||||||
|
* @return list of found objects
|
||||||
|
*/
|
||||||
|
<T> List<T> queryForList(Query query, Class<T> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the multi search query against elasticsearch and return result as {@link List}
|
||||||
|
*
|
||||||
|
* @param queries the queries to execute
|
||||||
|
* @param clazz the entity clazz used for property mapping
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @param <T> element return type
|
||||||
|
* @return list of found objects
|
||||||
|
*/
|
||||||
|
default <T> List<List<T>> queryForList(List<Query> queries, Class<T> clazz, IndexCoordinates index) {
|
||||||
|
return queryForPage(queries, clazz, index).stream().map(Page::getContent).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the multi search query against elasticsearch and return result as {@link List}
|
||||||
|
*
|
||||||
|
* @param queries the queries to execute
|
||||||
|
* @param classes the entity classes used for property mapping
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return list of list of found objects
|
||||||
|
*/
|
||||||
|
default List<List<?>> queryForList(List<Query> queries, List<Class<?>> classes, IndexCoordinates index) {
|
||||||
|
return queryForPage(queries, classes, index).stream().map(Page::getContent).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the query against elasticsearch and return ids
|
||||||
|
*
|
||||||
|
* @param query the query to execute
|
||||||
|
* @param clazz the entity clazz used for property mapping
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return list of found object ids
|
||||||
|
*/
|
||||||
|
List<String> queryForIds(Query query, Class<?> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns scrolled page for given query
|
||||||
|
*
|
||||||
|
* @param scrollTimeInMillis duration of the scroll time
|
||||||
|
* @param query The search query.
|
||||||
|
* @param clazz The class of entity to retrieve.
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return scrolled page result
|
||||||
|
*/
|
||||||
|
<T> ScrolledPage<T> startScroll(long scrollTimeInMillis, Query query, Class<T> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
<T> ScrolledPage<T> continueScroll(@Nullable String scrollId, long scrollTimeInMillis, Class<T> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the search contexts associated with specified scroll ids.
|
||||||
|
*
|
||||||
|
* @param scrollId the scroll id
|
||||||
|
*/
|
||||||
|
void clearScroll(String scrollId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* more like this query to search for documents that are "like" a specific document.
|
||||||
|
*
|
||||||
|
* @param query the query to execute
|
||||||
|
* @param clazz the entity clazz used for property mapping
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @param <T> element return type
|
||||||
|
* @return page with the results
|
||||||
|
*/
|
||||||
|
<T> Page<T> moreLikeThis(MoreLikeThisQuery query, Class<T> clazz, IndexCoordinates index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does a suggest query
|
||||||
|
*
|
||||||
|
* @param suggestion the query
|
||||||
|
* @param index the index to run the query against
|
||||||
|
* @return the suggest response
|
||||||
|
*/
|
||||||
|
SearchResponse suggest(SuggestBuilder suggestion, IndexCoordinates index);
|
||||||
|
}
|
@ -31,16 +31,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.data.annotation.Transient;
|
import org.springframework.data.annotation.Transient;
|
||||||
import org.springframework.data.elasticsearch.annotations.CompletionContext;
|
import org.springframework.data.elasticsearch.annotations.*;
|
||||||
import org.springframework.data.elasticsearch.annotations.CompletionField;
|
|
||||||
import org.springframework.data.elasticsearch.annotations.DynamicMapping;
|
|
||||||
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.GeoPointField;
|
|
||||||
import org.springframework.data.elasticsearch.annotations.InnerField;
|
|
||||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
|
||||||
import org.springframework.data.elasticsearch.annotations.MultiField;
|
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
||||||
import org.springframework.data.elasticsearch.core.ResourceUtil;
|
import org.springframework.data.elasticsearch.core.ResourceUtil;
|
||||||
import org.springframework.data.elasticsearch.core.completion.Completion;
|
import org.springframework.data.elasticsearch.core.completion.Completion;
|
||||||
@ -111,7 +102,7 @@ public class MappingBuilder {
|
|||||||
ElasticsearchPersistentEntity<?> entity = elasticsearchConverter.getMappingContext()
|
ElasticsearchPersistentEntity<?> entity = elasticsearchConverter.getMappingContext()
|
||||||
.getRequiredPersistentEntity(clazz);
|
.getRequiredPersistentEntity(clazz);
|
||||||
|
|
||||||
XContentBuilder builder = jsonBuilder().startObject().startObject(entity.getIndexType());
|
XContentBuilder builder = jsonBuilder().startObject().startObject(entity.getIndexCoordinates().getTypeName());
|
||||||
|
|
||||||
// Dynamic templates
|
// Dynamic templates
|
||||||
addDynamicTemplatesMapping(builder, entity);
|
addDynamicTemplatesMapping(builder, entity);
|
||||||
|
@ -32,9 +32,7 @@ import org.springframework.lang.Nullable;
|
|||||||
*/
|
*/
|
||||||
public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, ElasticsearchPersistentProperty> {
|
public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, ElasticsearchPersistentProperty> {
|
||||||
|
|
||||||
String getIndexName();
|
IndexCoordinates getIndexCoordinates();
|
||||||
|
|
||||||
String getIndexType();
|
|
||||||
|
|
||||||
short getShards();
|
short getShards();
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.data.elasticsearch.core;
|
package org.springframework.data.elasticsearch.core.mapping;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
@ -102,8 +102,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
|||||||
context.setRootObject(applicationContext);
|
context.setRootObject(applicationContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private String getIndexName() {
|
||||||
public String getIndexName() {
|
|
||||||
|
|
||||||
if (indexName != null) {
|
if (indexName != null) {
|
||||||
Expression expression = parser.parseExpression(indexName, ParserContext.TEMPLATE_EXPRESSION);
|
Expression expression = parser.parseExpression(indexName, ParserContext.TEMPLATE_EXPRESSION);
|
||||||
@ -113,8 +112,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
|||||||
return getTypeInformation().getType().getSimpleName();
|
return getTypeInformation().getType().getSimpleName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private String getIndexType() {
|
||||||
public String getIndexType() {
|
|
||||||
|
|
||||||
if (indexType != null) {
|
if (indexType != null) {
|
||||||
Expression expression = parser.parseExpression(indexType, ParserContext.TEMPLATE_EXPRESSION);
|
Expression expression = parser.parseExpression(indexType, ParserContext.TEMPLATE_EXPRESSION);
|
||||||
@ -124,6 +122,11 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IndexCoordinates getIndexCoordinates() {
|
||||||
|
return IndexCoordinates.of(getIndexName()).withTypes(getIndexType());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIndexStoreType() {
|
public String getIndexStoreType() {
|
||||||
return indexStoreType;
|
return indexStoreType;
|
||||||
|
@ -19,6 +19,7 @@ import org.elasticsearch.index.query.QueryBuilder;
|
|||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
import org.springframework.data.repository.NoRepositoryBean;
|
import org.springframework.data.repository.NoRepositoryBean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,7 +47,7 @@ public interface ElasticsearchRepository<T, ID> extends ElasticsearchCrudReposit
|
|||||||
|
|
||||||
Page<T> search(QueryBuilder query, Pageable pageable);
|
Page<T> search(QueryBuilder query, Pageable pageable);
|
||||||
|
|
||||||
Page<T> search(NativeSearchQuery searchQuery);
|
Page<T> search(Query searchQuery);
|
||||||
|
|
||||||
Page<T> searchSimilar(T entity, String[] fields, Pageable pageable);
|
Page<T> searchSimilar(T entity, String[] fields, Pageable pageable);
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ import reactor.core.publisher.Mono;
|
|||||||
|
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||||
|
@ -17,7 +17,7 @@ package org.springframework.data.elasticsearch.repository.query;
|
|||||||
|
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||||
import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator;
|
import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator;
|
||||||
|
@ -20,7 +20,7 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import org.springframework.core.convert.support.GenericConversionService;
|
import org.springframework.core.convert.support.GenericConversionService;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.convert.DateTimeConverters;
|
import org.springframework.data.elasticsearch.core.convert.DateTimeConverters;
|
||||||
import org.springframework.data.elasticsearch.core.query.StringQuery;
|
import org.springframework.data.elasticsearch.core.query.StringQuery;
|
||||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
package org.springframework.data.elasticsearch.repository.query;
|
package org.springframework.data.elasticsearch.repository.query;
|
||||||
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.query.Query;
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
import org.springframework.data.repository.query.ResultProcessor;
|
import org.springframework.data.repository.query.ResultProcessor;
|
||||||
|
@ -38,12 +38,12 @@ public class SimpleElasticsearchEntityMetadata<T> implements ElasticsearchEntity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIndexName() {
|
public String getIndexName() {
|
||||||
return entity.getIndexName();
|
return entity.getIndexCoordinates().getIndexName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIndexTypeName() {
|
public String getIndexTypeName() {
|
||||||
return entity.getIndexType();
|
return entity.getIndexCoordinates().getTypeName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -35,14 +35,19 @@ import org.springframework.data.domain.PageImpl;
|
|||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.data.elasticsearch.core.DocumentOperations;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.IndexOperations;
|
||||||
|
import org.springframework.data.elasticsearch.core.SearchOperations;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
|
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||||
import org.springframework.data.util.Streamable;
|
import org.springframework.data.util.Streamable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
@ -66,21 +71,23 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
|
|
||||||
static final Logger LOGGER = LoggerFactory.getLogger(AbstractElasticsearchRepository.class);
|
static final Logger LOGGER = LoggerFactory.getLogger(AbstractElasticsearchRepository.class);
|
||||||
|
|
||||||
protected ElasticsearchOperations elasticsearchOperations;
|
protected ElasticsearchOperations operations;
|
||||||
|
protected IndexOperations indexOperations;
|
||||||
|
|
||||||
protected Class<T> entityClass;
|
protected Class<T> entityClass;
|
||||||
protected ElasticsearchEntityInformation<T, ID> entityInformation;
|
protected ElasticsearchEntityInformation<T, ID> entityInformation;
|
||||||
|
|
||||||
public AbstractElasticsearchRepository() {}
|
public AbstractElasticsearchRepository() {}
|
||||||
|
|
||||||
public AbstractElasticsearchRepository(ElasticsearchOperations elasticsearchOperations) {
|
public AbstractElasticsearchRepository(ElasticsearchOperations operations) {
|
||||||
Assert.notNull(elasticsearchOperations, "ElasticsearchOperations must not be null!");
|
Assert.notNull(operations, "ElasticsearchOperations must not be null.");
|
||||||
|
this.operations = operations;
|
||||||
this.setElasticsearchOperations(elasticsearchOperations);
|
this.indexOperations = operations.getIndexOperations();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbstractElasticsearchRepository(ElasticsearchEntityInformation<T, ID> metadata,
|
public AbstractElasticsearchRepository(ElasticsearchEntityInformation<T, ID> metadata,
|
||||||
ElasticsearchOperations elasticsearchOperations) {
|
ElasticsearchOperations operations) {
|
||||||
this(elasticsearchOperations);
|
this(operations);
|
||||||
|
|
||||||
Assert.notNull(metadata, "ElasticsearchEntityInformation must not be null!");
|
Assert.notNull(metadata, "ElasticsearchEntityInformation must not be null!");
|
||||||
|
|
||||||
@ -97,22 +104,25 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createIndex() {
|
private void createIndex() {
|
||||||
elasticsearchOperations.createIndex(getEntityClass());
|
indexOperations.createIndex(getEntityClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putMapping() {
|
private void putMapping() {
|
||||||
elasticsearchOperations.putMapping(getEntityClass());
|
indexOperations.putMapping(getEntityClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean createIndexAndMapping() {
|
private boolean createIndexAndMapping() {
|
||||||
return elasticsearchOperations.getPersistentEntityFor(getEntityClass()).isCreateIndexAndMapping();
|
|
||||||
|
final ElasticsearchPersistentEntity<?> entity = operations.getElasticsearchConverter()
|
||||||
|
.getMappingContext().getRequiredPersistentEntity(getEntityClass());
|
||||||
|
return entity.isCreateIndexAndMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<T> findById(ID id) {
|
public Optional<T> findById(ID id) {
|
||||||
GetQuery query = new GetQuery();
|
GetQuery query = new GetQuery();
|
||||||
query.setId(stringIdRepresentation(id));
|
query.setId(stringIdRepresentation(id));
|
||||||
return Optional.ofNullable(elasticsearchOperations.get(query, getEntityClass(), getIndexCoordinates()));
|
return Optional.ofNullable(operations.get(query, getEntityClass(), getIndexCoordinates()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -128,7 +138,7 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
@Override
|
@Override
|
||||||
public Page<T> findAll(Pageable pageable) {
|
public Page<T> findAll(Pageable pageable) {
|
||||||
NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).withPageable(pageable).build();
|
NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).withPageable(pageable).build();
|
||||||
return elasticsearchOperations.queryForPage(query, getEntityClass(), getIndexCoordinates());
|
return operations.queryForPage(query, getEntityClass(), getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -140,27 +150,27 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
}
|
}
|
||||||
NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQuery())
|
NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQuery())
|
||||||
.withPageable(PageRequest.of(0, itemCount, sort)).build();
|
.withPageable(PageRequest.of(0, itemCount, sort)).build();
|
||||||
return elasticsearchOperations.queryForPage(query, getEntityClass(), getIndexCoordinates());
|
return operations.queryForPage(query, getEntityClass(), getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterable<T> findAllById(Iterable<ID> ids) {
|
public Iterable<T> findAllById(Iterable<ID> ids) {
|
||||||
Assert.notNull(ids, "ids can't be null.");
|
Assert.notNull(ids, "ids can't be null.");
|
||||||
NativeSearchQuery query = new NativeSearchQueryBuilder().withIds(stringIdsRepresentation(ids)).build();
|
NativeSearchQuery query = new NativeSearchQueryBuilder().withIds(stringIdsRepresentation(ids)).build();
|
||||||
return elasticsearchOperations.multiGet(query, getEntityClass(), getIndexCoordinates());
|
return operations.multiGet(query, getEntityClass(), getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long count() {
|
public long count() {
|
||||||
NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build();
|
NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build();
|
||||||
return elasticsearchOperations.count(query, getEntityClass(), getIndexCoordinates());
|
return operations.count(query, getEntityClass(), getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S extends T> S save(S entity) {
|
public <S extends T> S save(S entity) {
|
||||||
Assert.notNull(entity, "Cannot save 'null' entity.");
|
Assert.notNull(entity, "Cannot save 'null' entity.");
|
||||||
elasticsearchOperations.index(createIndexQuery(entity), getIndexCoordinates());
|
operations.index(createIndexQuery(entity), getIndexCoordinates());
|
||||||
elasticsearchOperations.refresh(getIndexCoordinates());
|
indexOperations.refresh(getIndexCoordinates());
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +187,7 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
@Override
|
@Override
|
||||||
public <S extends T> S indexWithoutRefresh(S entity) {
|
public <S extends T> S indexWithoutRefresh(S entity) {
|
||||||
Assert.notNull(entity, "Cannot save 'null' entity.");
|
Assert.notNull(entity, "Cannot save 'null' entity.");
|
||||||
elasticsearchOperations.index(createIndexQuery(entity), getIndexCoordinates());
|
operations.index(createIndexQuery(entity), getIndexCoordinates());
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,8 +198,8 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
if (!queries.isEmpty()) {
|
if (!queries.isEmpty()) {
|
||||||
elasticsearchOperations.bulkIndex(queries, getIndexCoordinates());
|
operations.bulkIndex(queries, getIndexCoordinates());
|
||||||
elasticsearchOperations.refresh(getIndexCoordinates());
|
indexOperations.refresh(getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
return entities;
|
return entities;
|
||||||
@ -203,24 +213,24 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
@Override
|
@Override
|
||||||
public Iterable<T> search(QueryBuilder query) {
|
public Iterable<T> search(QueryBuilder query) {
|
||||||
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(query).build();
|
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(query).build();
|
||||||
int count = (int) elasticsearchOperations.count(searchQuery, getEntityClass(), getIndexCoordinates());
|
int count = (int) operations.count(searchQuery, getEntityClass(), getIndexCoordinates());
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
return new PageImpl<>(Collections.<T> emptyList());
|
return new PageImpl<>(Collections.<T> emptyList());
|
||||||
}
|
}
|
||||||
searchQuery.setPageable(PageRequest.of(0, count));
|
searchQuery.setPageable(PageRequest.of(0, count));
|
||||||
return elasticsearchOperations.queryForPage(searchQuery, getEntityClass(), getIndexCoordinates());
|
return operations.queryForPage(searchQuery, getEntityClass(), getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<T> search(QueryBuilder query, Pageable pageable) {
|
public Page<T> search(QueryBuilder query, Pageable pageable) {
|
||||||
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(query).withPageable(pageable).build();
|
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(query).withPageable(pageable).build();
|
||||||
return elasticsearchOperations.queryForPage(searchQuery, getEntityClass(), getIndexCoordinates());
|
return operations.queryForPage(searchQuery, getEntityClass(), getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<T> search(NativeSearchQuery query) {
|
public Page<T> search(Query query) {
|
||||||
return elasticsearchOperations.queryForPage(query, getEntityClass(), getIndexCoordinates());
|
return operations.queryForPage(query, getEntityClass(), getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -235,22 +245,22 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
query.addFields(fields);
|
query.addFields(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
return elasticsearchOperations.moreLikeThis(query, getEntityClass(), getIndexCoordinates());
|
return operations.moreLikeThis(query, getEntityClass(), getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteById(ID id) {
|
public void deleteById(ID id) {
|
||||||
Assert.notNull(id, "Cannot delete entity with id 'null'.");
|
Assert.notNull(id, "Cannot delete entity with id 'null'.");
|
||||||
IndexCoordinates indexCoordinates = getIndexCoordinates();
|
IndexCoordinates indexCoordinates = getIndexCoordinates();
|
||||||
elasticsearchOperations.delete(stringIdRepresentation(id), indexCoordinates);
|
operations.delete(stringIdRepresentation(id), indexCoordinates);
|
||||||
elasticsearchOperations.refresh(indexCoordinates);
|
indexOperations.refresh(indexCoordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(T entity) {
|
public void delete(T entity) {
|
||||||
Assert.notNull(entity, "Cannot delete 'null' entity.");
|
Assert.notNull(entity, "Cannot delete 'null' entity.");
|
||||||
deleteById(extractIdFromBean(entity));
|
deleteById(extractIdFromBean(entity));
|
||||||
elasticsearchOperations.refresh(getIndexCoordinates());
|
indexOperations.refresh(getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -266,13 +276,13 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
DeleteQuery deleteQuery = new DeleteQuery();
|
DeleteQuery deleteQuery = new DeleteQuery();
|
||||||
deleteQuery.setQuery(matchAllQuery());
|
deleteQuery.setQuery(matchAllQuery());
|
||||||
IndexCoordinates indexCoordinates = getIndexCoordinates();
|
IndexCoordinates indexCoordinates = getIndexCoordinates();
|
||||||
elasticsearchOperations.delete(deleteQuery, indexCoordinates);
|
operations.delete(deleteQuery, indexCoordinates);
|
||||||
elasticsearchOperations.refresh(indexCoordinates);
|
indexOperations.refresh(indexCoordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
elasticsearchOperations.refresh(getEntityClass());
|
indexOperations.refresh(getEntityClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IndexQuery createIndexQuery(T entity) {
|
private IndexQuery createIndexQuery(T entity) {
|
||||||
@ -326,11 +336,6 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
this.entityClass = entityClass;
|
this.entityClass = entityClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setElasticsearchOperations(ElasticsearchOperations elasticsearchOperations) {
|
|
||||||
Assert.notNull(elasticsearchOperations, "ElasticsearchOperations must not be null.");
|
|
||||||
this.elasticsearchOperations = elasticsearchOperations;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ID extractIdFromBean(T entity) {
|
protected ID extractIdFromBean(T entity) {
|
||||||
return entityInformation.getId(entity);
|
return entityInformation.getId(entity);
|
||||||
}
|
}
|
||||||
@ -356,6 +361,6 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
|
|||||||
}
|
}
|
||||||
|
|
||||||
private IndexCoordinates getIndexCoordinates() {
|
private IndexCoordinates getIndexCoordinates() {
|
||||||
return elasticsearchOperations.getIndexCoordinatesFor(getEntityClass());
|
return operations.getIndexCoordinatesFor(getEntityClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package org.springframework.data.elasticsearch.repository.support;
|
package org.springframework.data.elasticsearch.repository.support;
|
||||||
|
|
||||||
import org.elasticsearch.index.VersionType;
|
import org.elasticsearch.index.VersionType;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.repository.core.EntityInformation;
|
import org.springframework.data.repository.core.EntityInformation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,14 +26,13 @@ import org.springframework.data.repository.core.EntityInformation;
|
|||||||
* @author Mohsin Husen
|
* @author Mohsin Husen
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Ivan Greene
|
* @author Ivan Greene
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
*/
|
*/
|
||||||
public interface ElasticsearchEntityInformation<T, ID> extends EntityInformation<T, ID> {
|
public interface ElasticsearchEntityInformation<T, ID> extends EntityInformation<T, ID> {
|
||||||
|
|
||||||
String getIdAttribute();
|
String getIdAttribute();
|
||||||
|
|
||||||
String getIndexName();
|
IndexCoordinates getIndexCoordinates();
|
||||||
|
|
||||||
String getType();
|
|
||||||
|
|
||||||
Long getVersion(T entity);
|
Long getVersion(T entity);
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package org.springframework.data.elasticsearch.repository.support;
|
package org.springframework.data.elasticsearch.repository.support;
|
||||||
|
|
||||||
import org.elasticsearch.index.VersionType;
|
import org.elasticsearch.index.VersionType;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||||
import org.springframework.data.repository.core.support.PersistentEntityInformation;
|
import org.springframework.data.repository.core.support.PersistentEntityInformation;
|
||||||
@ -39,21 +40,19 @@ public class MappingElasticsearchEntityInformation<T, ID> extends PersistentEnti
|
|||||||
implements ElasticsearchEntityInformation<T, ID> {
|
implements ElasticsearchEntityInformation<T, ID> {
|
||||||
|
|
||||||
private final ElasticsearchPersistentEntity<T> entityMetadata;
|
private final ElasticsearchPersistentEntity<T> entityMetadata;
|
||||||
private final String indexName;
|
private final IndexCoordinates indexCoordinates;
|
||||||
private final String type;
|
|
||||||
private final VersionType versionType;
|
private final VersionType versionType;
|
||||||
|
|
||||||
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity) {
|
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity) {
|
||||||
this(entity, entity.getIndexName(), entity.getIndexType(), entity.getVersionType());
|
this(entity, entity.getIndexCoordinates(), entity.getVersionType());
|
||||||
}
|
}
|
||||||
|
|
||||||
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity, String indexName, String type,
|
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity,
|
||||||
VersionType versionType) {
|
IndexCoordinates indexCoordinates, VersionType versionType) {
|
||||||
super(entity);
|
super(entity);
|
||||||
|
|
||||||
this.entityMetadata = entity;
|
this.entityMetadata = entity;
|
||||||
this.indexName = indexName;
|
this.indexCoordinates = indexCoordinates;
|
||||||
this.type = type;
|
|
||||||
this.versionType = versionType;
|
this.versionType = versionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,14 +61,10 @@ public class MappingElasticsearchEntityInformation<T, ID> extends PersistentEnti
|
|||||||
return entityMetadata.getRequiredIdProperty().getFieldName();
|
return entityMetadata.getRequiredIdProperty().getFieldName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getIndexName() {
|
|
||||||
return indexName != null ? indexName : entityMetadata.getIndexName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType() {
|
public IndexCoordinates getIndexCoordinates() {
|
||||||
return type != null ? type : entityMetadata.getIndexType();
|
return indexCoordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -115,9 +115,8 @@ public class ReactiveElasticsearchRepositoryFactory extends ReactiveRepositoryFa
|
|||||||
@Nullable RepositoryInformation information) {
|
@Nullable RepositoryInformation information) {
|
||||||
|
|
||||||
ElasticsearchPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(domainClass);
|
ElasticsearchPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(domainClass);
|
||||||
|
return new MappingElasticsearchEntityInformation<>((ElasticsearchPersistentEntity<T>) entity,
|
||||||
return new MappingElasticsearchEntityInformation<>((ElasticsearchPersistentEntity<T>) entity, entity.getIndexName(),
|
entity.getIndexCoordinates(), entity.getVersionType());
|
||||||
entity.getIndexType(), entity.getVersionType());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +20,6 @@ import reactor.core.publisher.Mono;
|
|||||||
|
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
|
||||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.query.Query;
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;
|
import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;
|
||||||
@ -35,7 +34,6 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
|
|||||||
|
|
||||||
private final ElasticsearchEntityInformation<T, ID> entityInformation;
|
private final ElasticsearchEntityInformation<T, ID> entityInformation;
|
||||||
private final ReactiveElasticsearchOperations elasticsearchOperations;
|
private final ReactiveElasticsearchOperations elasticsearchOperations;
|
||||||
private final IndexCoordinates index;
|
|
||||||
|
|
||||||
public SimpleReactiveElasticsearchRepository(ElasticsearchEntityInformation<T, ID> entityInformation,
|
public SimpleReactiveElasticsearchRepository(ElasticsearchEntityInformation<T, ID> entityInformation,
|
||||||
ReactiveElasticsearchOperations elasticsearchOperations) {
|
ReactiveElasticsearchOperations elasticsearchOperations) {
|
||||||
@ -45,20 +43,19 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
|
|||||||
|
|
||||||
this.entityInformation = entityInformation;
|
this.entityInformation = entityInformation;
|
||||||
this.elasticsearchOperations = elasticsearchOperations;
|
this.elasticsearchOperations = elasticsearchOperations;
|
||||||
this.index = IndexCoordinates.of(entityInformation.getIndexName()).withTypes(entityInformation.getType());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<T> findAll(Sort sort) {
|
public Flux<T> findAll(Sort sort) {
|
||||||
|
|
||||||
return elasticsearchOperations.find(Query.findAll().addSort(sort), entityInformation.getJavaType(), index);
|
return elasticsearchOperations.find(Query.findAll().addSort(sort), entityInformation.getJavaType(), entityInformation.getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S extends T> Mono<S> save(S entity) {
|
public <S extends T> Mono<S> save(S entity) {
|
||||||
|
|
||||||
Assert.notNull(entity, "Entity must not be null!");
|
Assert.notNull(entity, "Entity must not be null!");
|
||||||
return elasticsearchOperations.save(entity, index);
|
return elasticsearchOperations.save(entity, entityInformation.getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -79,7 +76,7 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
|
|||||||
public Mono<T> findById(ID id) {
|
public Mono<T> findById(ID id) {
|
||||||
|
|
||||||
Assert.notNull(id, "Id must not be null!");
|
Assert.notNull(id, "Id must not be null!");
|
||||||
return elasticsearchOperations.findById(convertId(id), entityInformation.getJavaType(), index);
|
return elasticsearchOperations.findById(convertId(id), entityInformation.getJavaType(), entityInformation.getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -93,7 +90,7 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
|
|||||||
public Mono<Boolean> existsById(ID id) {
|
public Mono<Boolean> existsById(ID id) {
|
||||||
|
|
||||||
Assert.notNull(id, "Id must not be null!");
|
Assert.notNull(id, "Id must not be null!");
|
||||||
return elasticsearchOperations.exists(convertId(id), entityInformation.getJavaType(), index);
|
return elasticsearchOperations.exists(convertId(id), entityInformation.getJavaType(), entityInformation.getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -106,7 +103,7 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
|
|||||||
@Override
|
@Override
|
||||||
public Flux<T> findAll() {
|
public Flux<T> findAll() {
|
||||||
|
|
||||||
return elasticsearchOperations.find(Query.findAll(), entityInformation.getJavaType(), index);
|
return elasticsearchOperations.find(Query.findAll(), entityInformation.getJavaType(), entityInformation.getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -127,14 +124,14 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
|
|||||||
@Override
|
@Override
|
||||||
public Mono<Long> count() {
|
public Mono<Long> count() {
|
||||||
|
|
||||||
return elasticsearchOperations.count(Query.findAll(), entityInformation.getJavaType(), index);
|
return elasticsearchOperations.count(Query.findAll(), entityInformation.getJavaType(), entityInformation.getIndexCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> deleteById(ID id) {
|
public Mono<Void> deleteById(ID id) {
|
||||||
|
|
||||||
Assert.notNull(id, "Id must not be null!");
|
Assert.notNull(id, "Id must not be null!");
|
||||||
return elasticsearchOperations.deleteById(convertId(id), entityInformation.getJavaType(), index) //
|
return elasticsearchOperations.deleteById(convertId(id), entityInformation.getJavaType(), entityInformation.getIndexCoordinates()) //
|
||||||
.then();
|
.then();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +146,7 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
|
|||||||
public Mono<Void> delete(T entity) {
|
public Mono<Void> delete(T entity) {
|
||||||
|
|
||||||
Assert.notNull(entity, "Entity must not be null!");
|
Assert.notNull(entity, "Entity must not be null!");
|
||||||
return elasticsearchOperations.delete(entity, index) //
|
return elasticsearchOperations.delete(entity, entityInformation.getIndexCoordinates()) //
|
||||||
.then();
|
.then();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +167,7 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
|
|||||||
@Override
|
@Override
|
||||||
public Mono<Void> deleteAll() {
|
public Mono<Void> deleteAll() {
|
||||||
|
|
||||||
return elasticsearchOperations.deleteBy(Query.findAll(), entityInformation.getJavaType(), index) //
|
return elasticsearchOperations.deleteBy(Query.findAll(), entityInformation.getJavaType(), entityInformation.getIndexCoordinates()) //
|
||||||
.then();
|
.then();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ import org.springframework.data.elasticsearch.annotations.FieldType;
|
|||||||
import org.springframework.data.elasticsearch.annotations.InnerField;
|
import org.springframework.data.elasticsearch.annotations.InnerField;
|
||||||
import org.springframework.data.elasticsearch.annotations.MultiField;
|
import org.springframework.data.elasticsearch.annotations.MultiField;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
||||||
|
@ -61,7 +61,7 @@ public class ElasticsearchRestTemplateTests extends ElasticsearchTemplateTests {
|
|||||||
indexRequest.source("{}", XContentType.JSON);
|
indexRequest.source("{}", XContentType.JSON);
|
||||||
UpdateQuery updateQuery = new UpdateQueryBuilder().withId(randomNumeric(5)).withIndexRequest(indexRequest).build();
|
UpdateQuery updateQuery = new UpdateQueryBuilder().withId(randomNumeric(5)).withIndexRequest(indexRequest).build();
|
||||||
assertThatThrownBy(() -> {
|
assertThatThrownBy(() -> {
|
||||||
elasticsearchTemplate.update(updateQuery, index);
|
operations.update(updateQuery, index);
|
||||||
}).isInstanceOf(ElasticsearchStatusException.class);
|
}).isInstanceOf(ElasticsearchStatusException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -34,6 +34,7 @@ import org.springframework.data.domain.Pageable;
|
|||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.annotations.Field;
|
import org.springframework.data.elasticsearch.annotations.Field;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||||
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
||||||
@ -59,7 +60,7 @@ public class ElasticsearchTransportTemplateTests extends ElasticsearchTemplateTe
|
|||||||
indexRequest.source("{}", XContentType.JSON);
|
indexRequest.source("{}", XContentType.JSON);
|
||||||
UpdateQuery updateQuery = new UpdateQueryBuilder().withId(randomNumeric(5)).withIndexRequest(indexRequest).build();
|
UpdateQuery updateQuery = new UpdateQueryBuilder().withId(randomNumeric(5)).withIndexRequest(indexRequest).build();
|
||||||
assertThatThrownBy(() -> {
|
assertThatThrownBy(() -> {
|
||||||
elasticsearchTemplate.update(updateQuery, index);
|
operations.update(updateQuery, index);
|
||||||
}).isInstanceOf(DocumentMissingException.class);
|
}).isInstanceOf(DocumentMissingException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core;
|
|||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Peter-Josef Meisch
|
* @author Peter-Josef Meisch
|
||||||
|
@ -36,6 +36,7 @@ import org.springframework.context.annotation.Import;
|
|||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.annotations.Field;
|
import org.springframework.data.elasticsearch.annotations.Field;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||||
|
@ -24,6 +24,7 @@ import lombok.Builder;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
@ -42,7 +42,7 @@ import org.springframework.data.elasticsearch.annotations.Field;
|
|||||||
import org.springframework.data.elasticsearch.annotations.InnerField;
|
import org.springframework.data.elasticsearch.annotations.InnerField;
|
||||||
import org.springframework.data.elasticsearch.annotations.MultiField;
|
import org.springframework.data.elasticsearch.annotations.MultiField;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.ResultsExtractor;
|
import org.springframework.data.elasticsearch.core.ResultsExtractor;
|
||||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
||||||
|
@ -26,6 +26,7 @@ import org.elasticsearch.search.suggest.SuggestBuilder;
|
|||||||
import org.elasticsearch.search.suggest.SuggestBuilders;
|
import org.elasticsearch.search.suggest.SuggestBuilders;
|
||||||
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||||
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
|
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -35,7 +36,8 @@ import org.springframework.data.elasticsearch.annotations.CompletionField;
|
|||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate;
|
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.IndexOperations;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||||
@ -60,9 +62,17 @@ public class ElasticsearchTemplateCompletionTests {
|
|||||||
|
|
||||||
@Autowired private ElasticsearchOperations operations;
|
@Autowired private ElasticsearchOperations operations;
|
||||||
|
|
||||||
private void loadCompletionObjectEntities() {
|
IndexOperations indexOperations;
|
||||||
|
|
||||||
IndexInitializer.init(operations, CompletionEntity.class);
|
@BeforeEach
|
||||||
|
private void setup() {
|
||||||
|
indexOperations = operations.getIndexOperations();
|
||||||
|
|
||||||
|
IndexInitializer.init(indexOperations, CompletionEntity.class);
|
||||||
|
IndexInitializer.init(indexOperations, AnnotatedCompletionEntity.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadCompletionObjectEntities() {
|
||||||
|
|
||||||
List<IndexQuery> indexQueries = new ArrayList<>();
|
List<IndexQuery> indexQueries = new ArrayList<>();
|
||||||
indexQueries.add(
|
indexQueries.add(
|
||||||
@ -80,8 +90,6 @@ public class ElasticsearchTemplateCompletionTests {
|
|||||||
|
|
||||||
private void loadAnnotatedCompletionObjectEntities() {
|
private void loadAnnotatedCompletionObjectEntities() {
|
||||||
|
|
||||||
IndexInitializer.init(operations, AnnotatedCompletionEntity.class);
|
|
||||||
|
|
||||||
NonDocumentEntity nonDocumentEntity = new NonDocumentEntity();
|
NonDocumentEntity nonDocumentEntity = new NonDocumentEntity();
|
||||||
nonDocumentEntity.setSomeField1("foo");
|
nonDocumentEntity.setSomeField1("foo");
|
||||||
nonDocumentEntity.setSomeField2("bar");
|
nonDocumentEntity.setSomeField2("bar");
|
||||||
@ -103,8 +111,6 @@ public class ElasticsearchTemplateCompletionTests {
|
|||||||
|
|
||||||
private void loadAnnotatedCompletionObjectEntitiesWithWeights() {
|
private void loadAnnotatedCompletionObjectEntitiesWithWeights() {
|
||||||
|
|
||||||
IndexInitializer.init(operations, AnnotatedCompletionEntity.class);
|
|
||||||
|
|
||||||
List<IndexQuery> indexQueries = new ArrayList<>();
|
List<IndexQuery> indexQueries = new ArrayList<>();
|
||||||
indexQueries.add(new AnnotatedCompletionEntityBuilder("1").name("Mewes Kochheim1")
|
indexQueries.add(new AnnotatedCompletionEntityBuilder("1").name("Mewes Kochheim1")
|
||||||
.suggest(new String[] { "Mewes Kochheim1" }, 4).buildIndex());
|
.suggest(new String[] { "Mewes Kochheim1" }, 4).buildIndex());
|
||||||
@ -120,17 +126,6 @@ public class ElasticsearchTemplateCompletionTests {
|
|||||||
operations.refresh(AnnotatedCompletionEntity.class);
|
operations.refresh(AnnotatedCompletionEntity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldPutMappingForGivenEntity() throws Exception {
|
|
||||||
|
|
||||||
// given
|
|
||||||
Class entity = CompletionEntity.class;
|
|
||||||
operations.createIndex(entity);
|
|
||||||
|
|
||||||
// when
|
|
||||||
assertThat(operations.putMapping(entity)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindSuggestionsForGivenCriteriaQueryUsingCompletionEntity() {
|
public void shouldFindSuggestionsForGivenCriteriaQueryUsingCompletionEntity() {
|
||||||
|
|
||||||
@ -164,7 +159,7 @@ public class ElasticsearchTemplateCompletionTests {
|
|||||||
// when
|
// when
|
||||||
SearchResponse suggestResponse = ((AbstractElasticsearchTemplate) operations).suggest(
|
SearchResponse suggestResponse = ((AbstractElasticsearchTemplate) operations).suggest(
|
||||||
new SuggestBuilder().addSuggestion("test-suggest", completionSuggestionFuzzyBuilder),
|
new SuggestBuilder().addSuggestion("test-suggest", completionSuggestionFuzzyBuilder),
|
||||||
IndexCoordinates.of("test-index-core-completion").withTypes("completion-type"));
|
IndexCoordinates.of("test-index-annotated-completion").withTypes("annotated-completion-type"));
|
||||||
CompletionSuggestion completionSuggestion = suggestResponse.getSuggest().getSuggestion("test-suggest");
|
CompletionSuggestion completionSuggestion = suggestResponse.getSuggest().getSuggestion("test-suggest");
|
||||||
List<CompletionSuggestion.Entry.Option> options = completionSuggestion.getEntries().get(0).getOptions();
|
List<CompletionSuggestion.Entry.Option> options = completionSuggestion.getEntries().get(0).getOptions();
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
|
|||||||
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
|
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
|
||||||
import org.elasticsearch.search.suggest.completion.context.CategoryQueryContext;
|
import org.elasticsearch.search.suggest.completion.context.CategoryQueryContext;
|
||||||
import org.elasticsearch.search.suggest.completion.context.ContextMapping;
|
import org.elasticsearch.search.suggest.completion.context.ContextMapping;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -43,7 +44,8 @@ import org.springframework.data.elasticsearch.annotations.CompletionField;
|
|||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate;
|
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.IndexOperations;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||||
@ -64,9 +66,18 @@ public class ElasticsearchTemplateCompletionWithContextsTests {
|
|||||||
|
|
||||||
@Autowired private ElasticsearchOperations operations;
|
@Autowired private ElasticsearchOperations operations;
|
||||||
|
|
||||||
|
private IndexOperations indexOperations;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setup() {
|
||||||
|
indexOperations = operations.getIndexOperations();
|
||||||
|
|
||||||
|
indexOperations.deleteIndex(ContextCompletionEntity.class);
|
||||||
|
}
|
||||||
|
|
||||||
private void loadContextCompletionObjectEntities() {
|
private void loadContextCompletionObjectEntities() {
|
||||||
|
|
||||||
IndexInitializer.init(operations, ContextCompletionEntity.class);
|
IndexInitializer.init(indexOperations, ContextCompletionEntity.class);
|
||||||
|
|
||||||
NonDocumentEntity nonDocumentEntity = new NonDocumentEntity();
|
NonDocumentEntity nonDocumentEntity = new NonDocumentEntity();
|
||||||
nonDocumentEntity.setSomeField1("foo");
|
nonDocumentEntity.setSomeField1("foo");
|
||||||
@ -99,17 +110,6 @@ public class ElasticsearchTemplateCompletionWithContextsTests {
|
|||||||
operations.refresh(ContextCompletionEntity.class);
|
operations.refresh(ContextCompletionEntity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldPutMappingForGivenEntity() throws Exception {
|
|
||||||
|
|
||||||
// given
|
|
||||||
Class<?> entity = ContextCompletionEntity.class;
|
|
||||||
operations.createIndex(entity);
|
|
||||||
|
|
||||||
// when
|
|
||||||
assertThat(operations.putMapping(entity)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATAES-536
|
@Test // DATAES-536
|
||||||
public void shouldFindSuggestionsForGivenCriteriaQueryUsingContextCompletionEntityOfMongo() {
|
public void shouldFindSuggestionsForGivenCriteriaQueryUsingContextCompletionEntityOfMongo() {
|
||||||
|
|
||||||
|
@ -38,7 +38,8 @@ import org.springframework.data.annotation.Id;
|
|||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.annotations.GeoPointField;
|
import org.springframework.data.elasticsearch.annotations.GeoPointField;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.IndexOperations;
|
||||||
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
@ -75,11 +76,15 @@ public class ElasticsearchTemplateGeoTests {
|
|||||||
|
|
||||||
@Autowired private ElasticsearchOperations operations;
|
@Autowired private ElasticsearchOperations operations;
|
||||||
|
|
||||||
|
private IndexOperations indexOperations;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void before() {
|
public void before() {
|
||||||
|
|
||||||
IndexInitializer.init(operations, AuthorMarkerEntity.class);
|
indexOperations = operations.getIndexOperations();
|
||||||
IndexInitializer.init(operations, LocationMarkerEntity.class);
|
|
||||||
|
IndexInitializer.init(indexOperations, AuthorMarkerEntity.class);
|
||||||
|
IndexInitializer.init(indexOperations, LocationMarkerEntity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadClassBaseEntities() {
|
private void loadClassBaseEntities() {
|
||||||
@ -125,17 +130,6 @@ public class ElasticsearchTemplateGeoTests {
|
|||||||
operations.refresh(LocationMarkerEntity.class);
|
operations.refresh(LocationMarkerEntity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldPutMappingForGivenEntityWithGeoLocation() throws Exception {
|
|
||||||
|
|
||||||
// given
|
|
||||||
Class<?> entity = AuthorMarkerEntity.class;
|
|
||||||
operations.createIndex(entity);
|
|
||||||
|
|
||||||
// when
|
|
||||||
assertThat(operations.putMapping(entity)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindAuthorMarkersInRangeForGivenCriteriaQuery() {
|
public void shouldFindAuthorMarkersInRangeForGivenCriteriaQuery() {
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ import org.springframework.data.annotation.Id;
|
|||||||
import org.springframework.data.annotation.Transient;
|
import org.springframework.data.annotation.Transient;
|
||||||
import org.springframework.data.elasticsearch.annotations.*;
|
import org.springframework.data.elasticsearch.annotations.*;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.completion.Completion;
|
import org.springframework.data.elasticsearch.core.completion.Completion;
|
||||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
|
@ -42,7 +42,7 @@ import org.springframework.data.elasticsearch.annotations.Document;
|
|||||||
import org.springframework.data.elasticsearch.annotations.Field;
|
import org.springframework.data.elasticsearch.annotations.Field;
|
||||||
import org.springframework.data.elasticsearch.annotations.Score;
|
import org.springframework.data.elasticsearch.annotations.Score;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
@ -27,6 +27,7 @@ import org.springframework.context.annotation.Import;
|
|||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
|
import org.springframework.data.elasticsearch.core.IndexOperations;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||||
@ -57,15 +58,18 @@ public class DynamicIndexEntityTests {
|
|||||||
@Autowired private DynamicIndexRepository repository;
|
@Autowired private DynamicIndexRepository repository;
|
||||||
|
|
||||||
@Autowired private ElasticsearchOperations operations;
|
@Autowired private ElasticsearchOperations operations;
|
||||||
|
private IndexOperations indexOperations;
|
||||||
|
|
||||||
@Autowired private IndexNameProvider indexNameProvider;
|
@Autowired private IndexNameProvider indexNameProvider;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
||||||
|
indexOperations = operations.getIndexOperations();
|
||||||
|
|
||||||
deleteIndexes();
|
deleteIndexes();
|
||||||
operations.createIndex("index1");
|
indexOperations.createIndex("index1");
|
||||||
operations.createIndex("index2");
|
indexOperations.createIndex("index2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
@ -75,8 +79,8 @@ public class DynamicIndexEntityTests {
|
|||||||
|
|
||||||
private void deleteIndexes() {
|
private void deleteIndexes() {
|
||||||
|
|
||||||
operations.deleteIndex("index1");
|
indexOperations.deleteIndex("index1");
|
||||||
operations.deleteIndex("index2");
|
indexOperations.deleteIndex("index2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAES-456
|
@Test // DATAES-456
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013-2019 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.repositories.nondocument;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|
||||||
import org.springframework.data.annotation.Id;
|
|
||||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Rizwan Idrees
|
|
||||||
* @author Mohsin Husen
|
|
||||||
* @author Peter-Josef Meisch
|
|
||||||
*/
|
|
||||||
public class NonDocumentEntityTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldNotInitialiseRepositoryWithNonDocument() {
|
|
||||||
// when
|
|
||||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/repository-non-document-entity.xml");
|
|
||||||
assertThatThrownBy(() -> {
|
|
||||||
ctx.getBean(NonDocumentEntityRepository.class);
|
|
||||||
}).isInstanceOf(BeanCreationException.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Rizwan Idrees
|
|
||||||
* @author Mohsin Husen
|
|
||||||
*/
|
|
||||||
static class NonDocumentEntity {
|
|
||||||
|
|
||||||
@Id private String someId;
|
|
||||||
private String someField1;
|
|
||||||
private String someField2;
|
|
||||||
|
|
||||||
public String getSomeField1() {
|
|
||||||
return someField1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSomeField1(String someField1) {
|
|
||||||
this.someField1 = someField1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSomeField2() {
|
|
||||||
return someField2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSomeField2(String someField2) {
|
|
||||||
this.someField2 = someField2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Rizwan Idrees
|
|
||||||
* @author Mohsin Husen
|
|
||||||
* @author Oliver Gierke
|
|
||||||
*/
|
|
||||||
@Lazy
|
|
||||||
interface NonDocumentEntityRepository extends ElasticsearchRepository<NonDocumentEntity, String> {}
|
|
||||||
|
|
||||||
}
|
|
@ -32,7 +32,7 @@ import org.springframework.data.elasticsearch.annotations.Document;
|
|||||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
import org.springframework.data.elasticsearch.annotations.Mapping;
|
||||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||||
|
@ -26,7 +26,7 @@ import org.springframework.context.annotation.Import;
|
|||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||||
|
@ -32,7 +32,7 @@ import org.springframework.data.elasticsearch.annotations.Document;
|
|||||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
import org.springframework.data.elasticsearch.annotations.Mapping;
|
||||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package org.springframework.data.elasticsearch.utils;
|
package org.springframework.data.elasticsearch.utils;
|
||||||
|
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
|
import org.springframework.data.elasticsearch.core.IndexOperations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility to initialize indexes.
|
* Utility to initialize indexes.
|
||||||
@ -31,9 +32,24 @@ public class IndexInitializer {
|
|||||||
*
|
*
|
||||||
* @param operations
|
* @param operations
|
||||||
* @param clazz
|
* @param clazz
|
||||||
|
* @deprecated since 4.0, use {@link IndexInitializer#init(IndexOperations, Class)}
|
||||||
*/
|
*/
|
||||||
public static void init(ElasticsearchOperations operations, Class<?> clazz) {
|
public static void init(ElasticsearchOperations operations, Class<?> clazz) {
|
||||||
|
|
||||||
|
operations.getIndexOperations().deleteIndex(clazz);
|
||||||
|
operations.getIndexOperations().createIndex(clazz);
|
||||||
|
operations.getIndexOperations().putMapping(clazz);
|
||||||
|
operations.getIndexOperations().refresh(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a fresh index with mappings for {@link Class}. Drops the index if it exists before creation.
|
||||||
|
*
|
||||||
|
* @param operations
|
||||||
|
* @param clazz
|
||||||
|
*/
|
||||||
|
public static void init(IndexOperations operations, Class<?> clazz) {
|
||||||
|
|
||||||
operations.deleteIndex(clazz);
|
operations.deleteIndex(clazz);
|
||||||
operations.createIndex(clazz);
|
operations.createIndex(clazz);
|
||||||
operations.putMapping(clazz);
|
operations.putMapping(clazz);
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
|
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/data/elasticsearch https://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch.xsd
|
|
||||||
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
|
|
||||||
|
|
||||||
<elasticsearch:node-client id="client" local="true" cluster-name="#{T(java.util.UUID).randomUUID().toString()}"
|
|
||||||
http-enabled="true" path-data="target/elasticsearchTestData" path-home="src/test/resources/test-home-dir"
|
|
||||||
path-configuration="node-client-configuration.yml"/>
|
|
||||||
|
|
||||||
<bean name="elasticsearchTemplate"
|
|
||||||
class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
|
|
||||||
<constructor-arg name="client" ref="client"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<elasticsearch:repositories
|
|
||||||
base-package="org.springframework.data.elasticsearch.repositories.nondocument"
|
|
||||||
consider-nested-repositories="true"/>
|
|
||||||
|
|
||||||
</beans>
|
|
Loading…
x
Reference in New Issue
Block a user