DATAES-594 - Polishing.

This commit is contained in:
P.J.Meisch 2019-06-20 12:11:19 +02:00
parent d22b12874d
commit 6a3042c437
3 changed files with 87 additions and 24 deletions

View File

@ -32,10 +32,15 @@ import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface ElasticsearchRepository<T, ID> extends ElasticsearchCrudRepository<T, ID> {
<S extends T> S indexWithoutRefresh(S entity);
<S extends T> S index(S entity);
/**
* This method is intended to be used when many single inserts must be made that cannot be aggregated to be inserted
* with {@link #saveAll(Iterable)}. This might lead to a temporary inconsistent state until {@link #refresh()} is
* called.
*/
<S extends T> S indexWithoutRefresh(S entity);
Iterable<T> search(QueryBuilder query);
Page<T> search(QueryBuilder query, Pageable pageable);

View File

@ -61,6 +61,7 @@ import org.springframework.util.Assert;
public abstract class AbstractElasticsearchRepository<T, ID> implements ElasticsearchRepository<T, ID> {
static final Logger LOGGER = LoggerFactory.getLogger(AbstractElasticsearchRepository.class);
protected ElasticsearchOperations elasticsearchOperations;
protected Class<T> entityClass;
protected ElasticsearchEntityInformation<T, ID> entityInformation;
@ -76,6 +77,7 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
public AbstractElasticsearchRepository(ElasticsearchEntityInformation<T, ID> metadata,
ElasticsearchOperations elasticsearchOperations) {
this(elasticsearchOperations);
Assert.notNull(metadata, "ElasticsearchEntityInformation must not be null!");
@ -93,19 +95,23 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
}
private void createIndex() {
elasticsearchOperations.createIndex(getEntityClass());
}
private void putMapping() {
elasticsearchOperations.putMapping(getEntityClass());
}
private boolean createIndexAndMapping() {
return elasticsearchOperations.getPersistentEntityFor(getEntityClass()).isCreateIndexAndMapping();
}
@Override
public Optional<T> findById(ID id) {
GetQuery query = new GetQuery();
query.setId(stringIdRepresentation(id));
return Optional.ofNullable(elasticsearchOperations.queryForObject(query, getEntityClass()));
@ -113,134 +119,167 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
@Override
public Iterable<T> findAll() {
int itemCount = (int) this.count();
if (itemCount == 0) {
return new PageImpl<>(Collections.<T> emptyList());
}
return this.findAll(PageRequest.of(0, Math.max(1, itemCount)));
}
@Override
public Page<T> findAll(Pageable pageable) {
SearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).withPageable(pageable).build();
return elasticsearchOperations.queryForPage(query, getEntityClass());
}
@Override
public Iterable<T> findAll(Sort sort) {
int itemCount = (int) this.count();
if (itemCount == 0) {
return new PageImpl<>(Collections.<T> emptyList());
}
SearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQuery())
.withPageable(PageRequest.of(0, itemCount, sort)).build();
return elasticsearchOperations.queryForPage(query, getEntityClass());
}
@Override
public Iterable<T> findAllById(Iterable<ID> ids) {
Assert.notNull(ids, "ids can't be null.");
SearchQuery query = new NativeSearchQueryBuilder().withIds(stringIdsRepresentation(ids)).build();
return elasticsearchOperations.multiGet(query, getEntityClass());
}
@Override
public long count() {
SearchQuery query = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build();
return elasticsearchOperations.count(query, getEntityClass());
}
@Override
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Cannot save 'null' entity.");
elasticsearchOperations.index(createIndexQuery(entity));
elasticsearchOperations.refresh(entityInformation.getIndexName());
return entity;
}
public <S extends T> List<S> save(List<S> entities) {
Assert.notNull(entities, "Cannot insert 'null' as a List.");
Assert.notEmpty(entities, "Cannot insert empty List.");
List<IndexQuery> queries = new ArrayList<>();
for (S s : entities) {
queries.add(createIndexQuery(s));
}
elasticsearchOperations.bulkIndex(queries);
elasticsearchOperations.refresh(entityInformation.getIndexName());
return entities;
}
@Override
public <S extends T> S index(S entity) {
return save(entity);
}
/**
* This method might lead to a temporary inconsistent state until
* {@link org.springframework.data.elasticsearch.repository.ElasticsearchRepository#refresh() refresh} is called.
*/
@Override
public <S extends T> S indexWithoutRefresh(S entity) {
Assert.notNull(entity, "Cannot save 'null' entity.");
elasticsearchOperations.index(createIndexQuery(entity));
return entity;
}
@Override
public <S extends T> Iterable<S> saveAll(Iterable<S> entities) {
Assert.notNull(entities, "Cannot insert 'null' as a List.");
List<IndexQuery> queries = new ArrayList<>();
for (S s : entities) {
queries.add(createIndexQuery(s));
}
elasticsearchOperations.bulkIndex(queries);
elasticsearchOperations.refresh(entityInformation.getIndexName());
return entities;
}
@Override
public boolean existsById(ID id) {
return findById(id).isPresent();
}
@Override
public Iterable<T> search(QueryBuilder query) {
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(query).build();
int count = (int) elasticsearchOperations.count(searchQuery, getEntityClass());
if (count == 0) {
return new PageImpl<>(Collections.<T> emptyList());
}
searchQuery.setPageable(PageRequest.of(0, count));
return elasticsearchOperations.queryForPage(searchQuery, getEntityClass());
}
@Override
public Page<T> search(QueryBuilder query, Pageable pageable) {
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(query).withPageable(pageable).build();
return elasticsearchOperations.queryForPage(searchQuery, getEntityClass());
}
@Override
public Page<T> search(SearchQuery query) {
return elasticsearchOperations.queryForPage(query, getEntityClass());
}
@Override
public Page<T> searchSimilar(T entity, String[] fields, Pageable pageable) {
Assert.notNull(entity, "Cannot search similar records for 'null'.");
Assert.notNull(pageable, "'pageable' cannot be 'null'");
MoreLikeThisQuery query = new MoreLikeThisQuery();
query.setId(stringIdRepresentation(extractIdFromBean(entity)));
query.setPageable(pageable);
if (fields != null) {
query.addFields(fields);
}
return elasticsearchOperations.moreLikeThis(query, getEntityClass());
}
@Override
public void deleteById(ID id) {
Assert.notNull(id, "Cannot delete entity with id 'null'.");
elasticsearchOperations.delete(entityInformation.getIndexName(), entityInformation.getType(),
stringIdRepresentation(id));
elasticsearchOperations.refresh(entityInformation.getIndexName());
@ -248,13 +287,16 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
@Override
public void delete(T entity) {
Assert.notNull(entity, "Cannot delete 'null' entity.");
deleteById(extractIdFromBean(entity));
elasticsearchOperations.refresh(entityInformation.getIndexName());
}
@Override
public void deleteAll(Iterable<? extends T> entities) {
Assert.notNull(entities, "Cannot delete 'null' list.");
for (T entity : entities) {
delete(entity);
@ -263,6 +305,7 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
@Override
public void deleteAll() {
DeleteQuery deleteQuery = new DeleteQuery();
deleteQuery.setQuery(matchAllQuery());
elasticsearchOperations.delete(deleteQuery, getEntityClass());
@ -271,10 +314,12 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
@Override
public void refresh() {
elasticsearchOperations.refresh(getEntityClass());
}
private IndexQuery createIndexQuery(T entity) {
IndexQuery query = new IndexQuery();
query.setObject(entity);
query.setId(stringIdRepresentation(extractIdFromBean(entity)));
@ -285,11 +330,13 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
@SuppressWarnings("unchecked")
private Class<T> resolveReturnedClassFromGenericType() {
ParameterizedType parameterizedType = resolveReturnedClassFromGenericType(getClass());
return (Class<T>) parameterizedType.getActualTypeArguments()[0];
}
private ParameterizedType resolveReturnedClassFromGenericType(Class<?> clazz) {
Object genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
@ -298,11 +345,13 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
return parameterizedType;
}
}
return resolveReturnedClassFromGenericType(clazz.getSuperclass());
}
@Override
public Class<T> getEntityClass() {
if (!isEntityClassSet()) {
try {
this.entityClass = resolveReturnedClassFromGenericType();
@ -310,20 +359,25 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
throw new InvalidDataAccessApiUsageException("Unable to resolve EntityClass. Please use according setter!", e);
}
}
return entityClass;
}
private boolean isEntityClassSet() {
return entityClass != null;
}
public final void setEntityClass(Class<T> entityClass) {
Assert.notNull(entityClass, "EntityClass must not be null.");
this.entityClass = entityClass;
}
public final void setElasticsearchOperations(ElasticsearchOperations elasticsearchOperations) {
Assert.notNull(elasticsearchOperations, "ElasticsearchOperations must not be null.");
this.elasticsearchOperations = elasticsearchOperations;
}
@ -332,11 +386,14 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
}
private List<String> stringIdsRepresentation(Iterable<ID> ids) {
Assert.notNull(ids, "ids can't be null.");
List<String> stringIds = new ArrayList<>();
for (ID id : ids) {
stringIds.add(stringIdRepresentation(id));
}
return stringIds;
}

View File

@ -35,7 +35,6 @@ import org.elasticsearch.action.ActionRequestValidationException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
@ -586,7 +585,9 @@ public class SimpleElasticsearchRepositoryTests {
// then
Page<SampleEntity> entities = repository.search(termQuery("id", documentId), PageRequest.of(0, 50));
assertThat(entities.getTotalElements()).isEqualTo(0L);
repository.refresh();
entities = repository.search(termQuery("id", documentId), PageRequest.of(0, 50));
assertThat(entities.getTotalElements()).isEqualTo(1L);
}