Home > Software engineering >  How to sort on newly added field with spring-data elasticsearch?
How to sort on newly added field with spring-data elasticsearch?

Time:01-13

I'm quite new to elasticsearch and spring-data combo.

Let me give you some background. I started from this entity

@Document(indexName = "my-entity")
public class MyEntity {
    @Id
    private String id;
    private String someField;
}

A few of them got created and indexed. Later on, I added a new field to the entity. Now it looks like this:

@Document(indexName = "my-entity")
public class MyEntity {
    @Id
    private String id;
    private String someField;
    @Field(type = FieldType.Date, format = DateFormat.date_time)
    private Date date;
}

What I'm trying to achieve is to return all entities sorted by my new field (which not all existing entities have).

Initially I've adjust my Repository and define something similar to List<MyEntity> findAllByOrderByDate();, but when I try to call it, I get the following exception:

"No mapping found for [date] in order to sort on"

I am aware that a possible solution would be to make use of ignore_unmapped option from elasticsearch, but my question is: how do I achieve this with spring-data-elasticsearch?

On the other hand, I'm not fixed up on using the Repository approach - I'm open for solutions.

Thank you!

CodePudding user response:

When you add a new field to sort on, the mapping in Elasticsearch for the index needs to be updated, otherwise Elasticsearch what type this field has. Spring Data Elasticsearch repositories do not do an automatic update of the mapping.

The following is a way to check if the mapping of a class (in this example named Foo) needs an update:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.stereotype.Component;

/**
 * @author P.J. Meisch ([email protected])
 */
@Component
public class FooMappingValidator {

    private static final Logger LOGGER = LoggerFactory.getLogger(FooMappingValidator.class);

    private final ObjectMapper objectMapper = new ObjectMapper();
    private final ElasticsearchOperations operations;

    public FooMappingValidator(ElasticsearchOperations operations) {
        this.operations = operations;
    }

    @Autowired
    public void checkFooMapping() {

        var indexOperations = operations.indexOps(Foo.class);

        if (indexOperations.exists()) {
            LOGGER.info("checking if mapping for Foo changed");

            var mappingFromEntity = indexOperations.createMapping();
            var mappingFromEntityNode = objectMapper.valueToTree(mappingFromEntity);
            var mappingFromIndexNode = objectMapper.valueToTree(indexOperations.getMapping());

            if (!mappingFromEntityNode.equals(mappingFromIndexNode)) {
                LOGGER.info("mapping for class Foo changed!");
                indexOperations.putMapping(mappingFromEntity);
            }
        }
    }
}

  • Related