mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-05-31 17:22:11 +00:00
added version support and upgraded the version of elasticsearch to 0.20.4
This commit is contained in:
parent
0818015434
commit
ad24967b53
2
pom.xml
2
pom.xml
@ -20,7 +20,7 @@
|
||||
<spring.version>3.1.2.RELEASE</spring.version>
|
||||
<slf4j.version>1.7.1</slf4j.version>
|
||||
<commons-lang.version>2.6</commons-lang.version>
|
||||
<elasticsearch.version>0.20.2</elasticsearch.version>
|
||||
<elasticsearch.version>0.20.4</elasticsearch.version>
|
||||
<apache.httpcomponents.version>4.2.2</apache.httpcomponents.version>
|
||||
<spring.data-commons.version>1.4.0.RELEASE</spring.data-commons.version>
|
||||
<joda-time.version>2.1</joda-time.version>
|
||||
|
@ -0,0 +1,10 @@
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Documented
|
||||
public @interface Version {
|
||||
}
|
@ -216,8 +216,12 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
private IndexRequestBuilder prepareIndex(IndexQuery query){
|
||||
try {
|
||||
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(query.getObject().getClass());
|
||||
return client.prepareIndex(persistentEntity.getIndexName(), persistentEntity.getIndexType(), query.getId())
|
||||
IndexRequestBuilder indexRequestBuilder = client.prepareIndex(persistentEntity.getIndexName(), persistentEntity.getIndexType(), query.getId())
|
||||
.setSource(objectMapper.writeValueAsString(query.getObject()));
|
||||
if(query.getVersion() != null){
|
||||
indexRequestBuilder.setVersion(query.getVersion());
|
||||
}
|
||||
return indexRequestBuilder;
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("failed to index the document [id: " + query.getId() +"]",e);
|
||||
}
|
||||
|
@ -21,5 +21,5 @@ public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, El
|
||||
|
||||
String getIndexName();
|
||||
String getIndexType();
|
||||
|
||||
ElasticsearchPersistentProperty getVersionProperty();
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ public interface ElasticsearchPersistentProperty extends PersistentProperty<Elas
|
||||
|
||||
String getFieldName();
|
||||
|
||||
boolean isVersionProperty();
|
||||
|
||||
public enum PropertyToFieldNameConverter implements Converter<ElasticsearchPersistentProperty, String> {
|
||||
|
||||
INSTANCE;
|
||||
|
@ -22,6 +22,7 @@ import org.springframework.context.expression.BeanFactoryAccessor;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
@ -41,6 +42,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
private final StandardEvaluationContext context;
|
||||
private String indexName;
|
||||
private String indexType;
|
||||
private ElasticsearchPersistentProperty versionProperty;
|
||||
|
||||
public SimpleElasticsearchPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
super(typeInformation);
|
||||
@ -70,4 +72,23 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
public String getIndexType() {
|
||||
return indexType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElasticsearchPersistentProperty getVersionProperty() {
|
||||
return this.versionProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPersistentProperty(ElasticsearchPersistentProperty property) {
|
||||
super.addPersistentProperty(property);
|
||||
if(property.isVersionProperty()){
|
||||
if (this.versionProperty != null) {
|
||||
throw new MappingException(String.format(
|
||||
"Attempt to add version property %s but already have property %s registered "
|
||||
+ "as version. Check your mapping configuration!", property.getField(), versionProperty.getField()));
|
||||
}
|
||||
Assert.isTrue(property.getType() == Long.class, "Version property should be Long");
|
||||
this.versionProperty = property;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.mapping;
|
||||
|
||||
import org.springframework.data.elasticsearch.annotations.Version;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||
@ -55,7 +56,12 @@ public class SimpleElasticsearchPersistentProperty extends AnnotationBasedPersis
|
||||
return super.isIdProperty() || SUPPORTED_ID_PROPERTY_NAMES.contains(getFieldName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public boolean isVersionProperty(){
|
||||
return field.isAnnotationPresent(Version.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Association<ElasticsearchPersistentProperty> createAssociation() {
|
||||
return null;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ public class IndexQuery{
|
||||
|
||||
private String id;
|
||||
private Object object;
|
||||
private Long version;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@ -21,4 +22,12 @@ public class IndexQuery{
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public Long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
@ -28,5 +28,6 @@ public interface ElasticsearchEntityInformation<T, ID extends Serializable> exte
|
||||
String getIdAttribute();
|
||||
String getIndexName();
|
||||
String getType();
|
||||
|
||||
String getVersionAttribute();
|
||||
Long getVersion(T entity);
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.repository.support;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
@ -32,6 +34,7 @@ import java.io.Serializable;
|
||||
public class MappingElasticsearchEntityInformation<T, ID extends Serializable> extends AbstractEntityInformation<T, ID>
|
||||
implements ElasticsearchEntityInformation<T, ID> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MappingElasticsearchEntityInformation.class);
|
||||
private final ElasticsearchPersistentEntity<T> entityMetadata;
|
||||
private final String indexName;
|
||||
private final String type;
|
||||
@ -79,4 +82,24 @@ public class MappingElasticsearchEntityInformation<T, ID extends Serializable> e
|
||||
public String getType() {
|
||||
return type != null? type : entityMetadata.getIndexType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionAttribute() {
|
||||
return entityMetadata.getVersionProperty().getFieldName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getVersion(T entity) {
|
||||
ElasticsearchPersistentProperty versionProperty = entityMetadata.getIdProperty();
|
||||
try {
|
||||
if(versionProperty != null){
|
||||
return (Long) BeanWrapper.create(entity, null).getProperty(versionProperty);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.debug("failed to retrieve version", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -212,6 +212,7 @@ public class SimpleElasticsearchRepository<T> implements ElasticsearchRepository
|
||||
IndexQuery query = new IndexQuery();
|
||||
query.setObject(entity);
|
||||
query.setId(extractIdFromBean(entity));
|
||||
query.setVersion(extractVersionFromBean(entity));
|
||||
return query;
|
||||
}
|
||||
|
||||
@ -266,4 +267,11 @@ public class SimpleElasticsearchRepository<T> implements ElasticsearchRepository
|
||||
return null;
|
||||
}
|
||||
|
||||
private Long extractVersionFromBean(T entity){
|
||||
if (entityInformation != null) {
|
||||
return entityInformation.getVersion(entity);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,16 +1,9 @@
|
||||
package org.springframework.data.elasticsearch;
|
||||
|
||||
public class Author {
|
||||
private String name;
|
||||
private String id;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
private String id;
|
||||
private String name;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@ -19,4 +12,12 @@ public class Author {
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,10 @@ import org.springframework.data.elasticsearch.annotations.Document;
|
||||
|
||||
@Document(indexName = "book",type = "book")
|
||||
public class Book {
|
||||
private String id;
|
||||
private String name;
|
||||
private Author author;
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private Author author;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -4,6 +4,7 @@ import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Version;
|
||||
|
||||
@Document(indexName = "test-index", type = "test-type")
|
||||
public class SampleEntity {
|
||||
@ -14,6 +15,8 @@ public class SampleEntity {
|
||||
private String message;
|
||||
private int rate;
|
||||
private boolean available;
|
||||
@Version
|
||||
private Long version;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@ -55,6 +58,14 @@ public class SampleEntity {
|
||||
this.available = available;
|
||||
}
|
||||
|
||||
public Long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Long version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof SampleEntity)) {
|
||||
@ -67,6 +78,9 @@ public class SampleEntity {
|
||||
return new EqualsBuilder().append(this.id, rhs.id)
|
||||
.append(this.type, rhs.type)
|
||||
.append(this.message, rhs.message)
|
||||
.append(this.rate,rhs.rate)
|
||||
.append(this.available,rhs.available)
|
||||
.append(this.version,rhs.version)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@ -76,6 +90,9 @@ public class SampleEntity {
|
||||
.append(id)
|
||||
.append(type)
|
||||
.append(message)
|
||||
.append(rate)
|
||||
.append(available)
|
||||
.append(version)
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
package org.springframework.data.elasticsearch.core.mapping;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.elasticsearch.annotations.Version;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.PropertyDescriptor;
|
||||
|
||||
public class SimpleElasticsearchPersistentEntityTest {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionGivenVersionPropertyIsNotLong() throws NoSuchFieldException, IntrospectionException {
|
||||
//given
|
||||
TypeInformation typeInformation = ClassTypeInformation.from(EntityWithWrongVersionType.class);
|
||||
SimpleElasticsearchPersistentProperty persistentProperty =
|
||||
new SimpleElasticsearchPersistentProperty(EntityWithWrongVersionType.class.getDeclaredField("version"),
|
||||
new PropertyDescriptor("version", EntityWithWrongVersionType.class),
|
||||
new SimpleElasticsearchPersistentEntity<EntityWithWrongVersionType>(typeInformation),
|
||||
new SimpleTypeHolder());
|
||||
|
||||
//when
|
||||
new SimpleElasticsearchPersistentEntity(typeInformation).addPersistentProperty(persistentProperty);
|
||||
}
|
||||
|
||||
|
||||
@Test(expected = MappingException.class)
|
||||
public void shouldThrowExceptionGivenMultipleVersionPropertiesArePresent() throws NoSuchFieldException, IntrospectionException {
|
||||
//given
|
||||
TypeInformation typeInformation = ClassTypeInformation.from(EntityWithMultipleVersionField.class);
|
||||
SimpleElasticsearchPersistentProperty persistentProperty1 =
|
||||
new SimpleElasticsearchPersistentProperty(EntityWithMultipleVersionField.class.getDeclaredField("version1"),
|
||||
new PropertyDescriptor("version1", EntityWithMultipleVersionField.class),
|
||||
new SimpleElasticsearchPersistentEntity<EntityWithMultipleVersionField>(typeInformation),
|
||||
new SimpleTypeHolder());
|
||||
|
||||
SimpleElasticsearchPersistentProperty persistentProperty2 =
|
||||
new SimpleElasticsearchPersistentProperty(EntityWithMultipleVersionField.class.getDeclaredField("version2"),
|
||||
new PropertyDescriptor("version2", EntityWithMultipleVersionField.class),
|
||||
new SimpleElasticsearchPersistentEntity<EntityWithMultipleVersionField>(typeInformation),
|
||||
new SimpleTypeHolder());
|
||||
|
||||
SimpleElasticsearchPersistentEntity simpleElasticsearchPersistentEntity = new SimpleElasticsearchPersistentEntity(typeInformation);
|
||||
simpleElasticsearchPersistentEntity.addPersistentProperty(persistentProperty1);
|
||||
//when
|
||||
simpleElasticsearchPersistentEntity.addPersistentProperty(persistentProperty2);
|
||||
}
|
||||
|
||||
|
||||
private class EntityWithWrongVersionType {
|
||||
@Version
|
||||
private String version;
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
private class EntityWithMultipleVersionField{
|
||||
|
||||
@Version
|
||||
private Long version1;
|
||||
@Version
|
||||
private Long version2;
|
||||
|
||||
public Long getVersion1() {
|
||||
return version1;
|
||||
}
|
||||
|
||||
public void setVersion1(Long version1) {
|
||||
this.version1 = version1;
|
||||
}
|
||||
|
||||
public Long getVersion2() {
|
||||
return version2;
|
||||
}
|
||||
|
||||
public void setVersion2(Long version2) {
|
||||
this.version2 = version2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -27,7 +27,6 @@ public class RepositoryTest {
|
||||
@Resource
|
||||
private SampleElasticsearchRepository repository;
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldDoBulkIndexDocument(){
|
||||
//given
|
||||
@ -148,7 +147,7 @@ public class RepositoryTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testFindAllByIdQuery(){
|
||||
public void shouldFindAllByIdQuery(){
|
||||
//todo : find solution for findAll(Iterable<Ids> ids)
|
||||
//given
|
||||
String documentId = randomNumeric(5);
|
||||
@ -171,31 +170,27 @@ public class RepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveIterableEntities(){
|
||||
//given
|
||||
|
||||
public void shouldSaveIterableEntities(){
|
||||
//given
|
||||
String documentId = randomNumeric(5);
|
||||
SampleEntity sampleEntity = new SampleEntity();
|
||||
sampleEntity.setId(documentId);
|
||||
sampleEntity.setMessage("hello world.");
|
||||
SampleEntity sampleEntity1 = new SampleEntity();
|
||||
sampleEntity1.setId(documentId);
|
||||
sampleEntity1.setMessage("hello world.");
|
||||
|
||||
String documentId2 = randomNumeric(5);
|
||||
SampleEntity sampleEntity2 = new SampleEntity();
|
||||
sampleEntity2.setId(documentId2);
|
||||
sampleEntity2.setMessage("hello world.");
|
||||
|
||||
Iterable<SampleEntity> sampleEntities = Arrays.asList(sampleEntity,sampleEntity2);
|
||||
|
||||
Iterable<SampleEntity> sampleEntities = Arrays.asList(sampleEntity1,sampleEntity2);
|
||||
//when
|
||||
repository.save(sampleEntities);
|
||||
|
||||
//then
|
||||
Page<SampleEntity> entities = repository.search(fieldQuery("id", documentId), new PageRequest(0, 50));
|
||||
assertNotNull(entities);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDocumentExistById(){
|
||||
public void shouldReturnTrueGivenDocumentWithIdExists(){
|
||||
//given
|
||||
String documentId = randomNumeric(5);
|
||||
SampleEntity sampleEntity = new SampleEntity();
|
||||
@ -211,7 +206,7 @@ public class RepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForGivenSearchQuery(){
|
||||
public void shouldReturnResultsForGivenSearchQuery(){
|
||||
//given
|
||||
String documentId = randomNumeric(5);
|
||||
SampleEntity sampleEntity = new SampleEntity();
|
||||
@ -227,7 +222,7 @@ public class RepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAll(){
|
||||
public void shouldDeleteAll(){
|
||||
//when
|
||||
repository.deleteAll();
|
||||
//then
|
||||
@ -238,7 +233,7 @@ public class RepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteByEntity(){
|
||||
public void shouldDeleteEntity(){
|
||||
//given
|
||||
String documentId = randomNumeric(5);
|
||||
SampleEntity sampleEntity = new SampleEntity();
|
||||
@ -255,28 +250,30 @@ public class RepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForReturnIterableEntities(){
|
||||
public void shouldReturnIterableEntities(){
|
||||
//given
|
||||
String documentId = randomNumeric(5);
|
||||
SampleEntity sampleEntity = new SampleEntity();
|
||||
sampleEntity.setId(documentId);
|
||||
sampleEntity.setMessage("hello world.");
|
||||
repository.save(sampleEntity);
|
||||
SampleEntity sampleEntity1 = new SampleEntity();
|
||||
sampleEntity1.setId(documentId);
|
||||
sampleEntity1.setMessage("hello world.");
|
||||
sampleEntity1.setVersion(System.currentTimeMillis());
|
||||
repository.save(sampleEntity1);
|
||||
|
||||
String documentId2 = randomNumeric(5);
|
||||
SampleEntity sampleEntity2 = new SampleEntity();
|
||||
sampleEntity2.setId(documentId2);
|
||||
sampleEntity2.setMessage("hello world.");
|
||||
sampleEntity2.setVersion(System.currentTimeMillis());
|
||||
repository.save(sampleEntity2);
|
||||
|
||||
//when
|
||||
Iterable<SampleEntity> sampleEntities=repository.search(fieldQuery("id",documentId));
|
||||
//then
|
||||
//then
|
||||
assertNotNull("sample entities cant be null..", sampleEntities);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteIterableEntities(){
|
||||
public void shouldDeleteIterableEntities(){
|
||||
//given
|
||||
String documentId = randomNumeric(5);
|
||||
SampleEntity sampleEntity = new SampleEntity();
|
||||
@ -291,10 +288,8 @@ public class RepositoryTest {
|
||||
repository.save(sampleEntity);
|
||||
|
||||
Iterable<SampleEntity> sampleEntities = Arrays.asList(sampleEntity,sampleEntity2);
|
||||
|
||||
//when
|
||||
repository.delete(sampleEntities);
|
||||
|
||||
//then
|
||||
Page<SampleEntity> entities = repository.search(fieldQuery("id", documentId), new PageRequest(0,50));
|
||||
assertThat(entities.getTotalElements(),equalTo(0L));
|
||||
@ -303,11 +298,12 @@ public class RepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexEntity(){
|
||||
public void shouldIndexEntity(){
|
||||
//given
|
||||
String documentId = randomNumeric(5);
|
||||
SampleEntity sampleEntity = new SampleEntity();
|
||||
sampleEntity.setId(documentId);
|
||||
sampleEntity.setVersion(System.currentTimeMillis());
|
||||
sampleEntity.setMessage("some message");
|
||||
//when
|
||||
repository.index(sampleEntity);
|
||||
@ -318,7 +314,7 @@ public class RepositoryTest {
|
||||
|
||||
@Test
|
||||
@Ignore("By default, the search request will fail if there is no mapping associated with a field. The ignore_unmapped option allows to ignore fields that have no mapping and not sort by them")
|
||||
public void testFindBySort(){
|
||||
public void shouldSortByGivenField(){
|
||||
//todo
|
||||
//given
|
||||
String documentId = randomNumeric(5);
|
||||
@ -332,12 +328,9 @@ public class RepositoryTest {
|
||||
sampleEntity2.setId(documentId2);
|
||||
sampleEntity2.setMessage("B.hello world.");
|
||||
repository.save(sampleEntity2);
|
||||
|
||||
//when
|
||||
Iterable<SampleEntity> sampleEntities=repository.findAll(new Sort(new Sort.Order(Sort.Direction.ASC,"message")));
|
||||
|
||||
//then
|
||||
assertThat(sampleEntities,is(notNullValue()));
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user