【问题标题】:Spring Data Elasticsearch : detect mapping differencesSpring Data Elasticsearch:检测映射差异
【发布时间】:2021-12-12 13:31:31
【问题描述】:

在 Spring Data Elasticsearch 中有没有一种方法可以检测到索引上的映射与从 Entity 对象创建的映射不匹配?

即 我允许 Spring Data Elasticsearch 从带有 @Document@Field 注释的实体模型创建映射

稍后我向模型添加一个新字段,但不更新索引映射,然后在我重新索引到新映射之前,这个新字段将无法正确配置

那么有没有办法检测这种差异,以便我知道哪些索引需要重新创建它们的映射,以及重新索引文档?

【问题讨论】:

    标签: spring-data-elasticsearch


    【解决方案1】:

    这是一个有趣的问题,但答案并不太复杂。

    假设我们有一个要存储在foo 索引中的Foo 实体类和一个使用该类的FooRepository。在 应用程序启动,当索引不存在时,将使用从实体派生的映射创建。

    为了检测从类派生的映射和存储在 Elasticsearch 中的映射的变化,您可以使用 像这样的方法:

    @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);
                }
            }
        }
    }
    

    这是一个注入了ElasticsearchOperations 的 Spring 组件,并且它有一个带有注解的方法 @Autowired。在将所有依赖项注入 bean 后,将执行自动装配的方法。这意味着 它在正常的应用程序逻辑启动之前运行。

    在这个方法中,我们首先为我们的实体类获取一个IndexOperations 实例。接下来我们检查索引是否存在, 如果没有,我们不需要检查。

    在下一步中,我们从实体获取当前映射并将其转换为 JsonNode 并对 我们从 Elasticsearch 检索到的映射。我们在这里使用JsonNodes 因为有一个equals() 方法 做我们需要的比较。

    如果我们检测到两个映射不同,我们会使用putMapping() 方法将新的映射写入索引。

    注意:

    这仅在向实体添加新属性时有效,因为无法在 Elasticsearch 中更改现有映射, 你需要重新索引。

    【讨论】:

    • 这似乎大部分工作,但我有一个标记为@Field(type = FieldType.Object)的字段的问题,mappingFromEntity将包含"type": "object",而mappingFromIndex没有,因此永远不会匹配。 Github 问题跟踪器上的示例会有帮助吗?
    • 我在开始集成新的 Elasticsearch 客户端 (github.com/elastic/elasticsearch-java/issues/45) 时注意到了这种行为。当一个字段被映射为对象时,Elasticsearch 在检索映射时不会返回它的类型。在比较之前,可能会遍历 mappingFromEntityTree 并删除 type 属性而不是值 object
    猜你喜欢
    • 2017-05-18
    • 2016-03-13
    • 2021-04-02
    • 2021-03-15
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    • 2017-01-19
    • 2019-04-09
    相关资源
    最近更新 更多