1

i'm using spring-boot-starter-data-elasticsearch (1.4.0.M3). I'm unable to get the version (_version in elasticsearch query result) of a document using the annoation "version". Any idea why the annotation isn't working ?

f.e.:

@GwtCompatible
@Document(indexName = "myIndexName")
public class Catalog implements Serializable {

    private List<GroupProduct> groups;

    @Id
    private String uuid;

    @Version
    private Long version;

    @Field(type = FieldType.Nested)
    private List<Product> products;

    private String label;

    @NotEmpty
    private String organizationUuid;

    private List<String> organizationUnitUuids;

    private Date updateDate;

    private List<VAT> vats;

    public Catalog() {

    }

    public List<GroupProduct> getGroups() {
        return groups;
    }

    public List<Product> getProducts() {
        return products;
    }

    public Date getUpdateDate() {
        return updateDate;
    }

    public void setGroups(List<GroupProduct> groups) {
        this.groups = groups;
    }

    public void setProducts(List<Product> products) {
        this.products = products;
    }

    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }

    public List<VAT> getVats() {
        return vats;
    }

    public void setVats(List<VAT> vats) {
        this.vats = vats;
    }

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }

    public String getOrganizationUuid() {
        return organizationUuid;
    }

    public void setOrganizationUuid(String organizationUuid) {
        this.organizationUuid = organizationUuid;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public List<String> getOrganizationUnitUuids() {
        return organizationUnitUuids;
    }

    public void setOrganizationUnitUuids(List<String> organizationUnitUuids) {
        this.organizationUnitUuids = organizationUnitUuids;
    }

    public Long getVersion() {
        return version;
    }

    public void setVersion(Long version) {
        this.version = version;
    }
}
1
  • Support for the @Version annotation in Spring Data Elasticsearch does not appear to be implemented, unfortunately. Commented Jun 14, 2016 at 20:33

1 Answer 1

1

Spring Data Elasticsearch (as of version 2.0.2) seems to have only partial support for the @Version annotation. If you annotate a document with a version field, it will be used when indexing a document. It will tell Elasticsearch that the document being saved is that specified version. If the new version is less than or equal to the version of the current document, Elasticsearch will throw a VersionConflictEngineException.

Unfortunately, Spring does not appear to populate this version field when a document is retrieved. As far as I can tell, this makes the version annotation useless. Perhaps the project will add this support in the near future. In the meantime, I have found a workaround by extending the default ResultMapper that Spring uses:

public class ExtendedResultMapper extends DefaultResultMapper {

    protected MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext;

    public ExtendedResultMapper(MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {
        super(mappingContext);
        this.mappingContext = mappingContext;
    }

    @Override
    public <T> T mapResult(GetResponse response, Class<T> clazz) {
        T result = super.mapResult(response, clazz);
        if (result != null) {
            setPersistentEntityVersion(result, response.getVersion(), clazz);
        }
        return result;
    }

    @Override
    public <T> LinkedList<T> mapResults(MultiGetResponse responses, Class<T> clazz) {
        LinkedList<T> results = super.mapResults(responses, clazz);
        if (results != null) {
            for (int i = 0; i < results.size(); i++) {
                setPersistentEntityVersion(results.get(i), responses.getResponses()[i].getResponse().getVersion(), clazz);
            }
        }
        return results;
    }

    private <T> void setPersistentEntityVersion(T result, Long version, Class<T> clazz) {
        if (mappingContext != null && clazz.isAnnotationPresent(Document.class)) {
            PersistentProperty<ElasticsearchPersistentProperty> versionProperty = mappingContext.getPersistentEntity(clazz).getVersionProperty();
            if (versionProperty != null && versionProperty.getType().isAssignableFrom(Long.class)) {
                Method setter = versionProperty.getSetter();
                if (setter != null) {
                    try {
                        setter.invoke(result, version);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            }
        }
    }

}

You can tell Spring to use this version instead of the default mapper as follows:

@Autowired
private Client client;

@Bean
public ElasticsearchTemplate elasticsearchTemplate() {
    MappingElasticsearchConverter converter = new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext());
    ExtendedResultMapper mapper = new ExtendedResultMapper(converter.getMappingContext());
    return new ElasticsearchTemplate(client, converter, mapper);
}

Note that the version is only populated for Get or Multi-Get requests. Search results do not include version information.

You could also use this same approach to extract other information from the GetResponse objects.

Using this code, if you get a document and then try to save it back, it will fail unless you increment the version.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.