解决 Spring Boot 对 Elasticsearch 字段没有小驼峰映射的问题

场景重现

在使用 MyBatis/Mybatis-Plus 框架对 MySQL 操作时习惯了字段名小驼峰映射,然而在操作 Elasticsearch 时发现字段名没有小驼峰映射。

解决方法

1. 使用 `ObjectMapper` 手动转换:

这是最直接也最常用的方法。 在 Spring Boot 应用中使用 `ObjectMapper` 将从 Elasticsearch 获取的数据进行转换,将下划线命名转换为小驼峰命名。

java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class ElasticsearchService {

    @Autowired
    private ObjectMapper objectMapper; // 通过 @Bean 配置 ObjectMapper

    public Map<String, Object> getDocument(String index, String id) {
        // 假设你已经有了从 Elasticsearch 获取文档的方法,这里是模拟
        Map<String, Object> document = new HashMap<>();
        document.put("first_name", "John");
        document.put("last_name", "Doe");

        // 将下划线命名转换为小驼峰命名
        ObjectMapper snakeCaseMapper = new ObjectMapper();
        snakeCaseMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
        ObjectMapper camelCaseMapper = new ObjectMapper();
        camelCaseMapper.setPropertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE);

        try {
            String jsonString = snakeCaseMapper.writeValueAsString(document);
            return camelCaseMapper.readValue(jsonString, Map.class);

        } catch (Exception e) {
            // 处理异常
            e.printStackTrace();
            return null;
        }
    }
}

解释:

• `ObjectMapper` 配置: 在 Spring Boot 应用中,你需要配置一个 `ObjectMapper` Bean。

• `PropertyNamingStrategy`: 通过设置 `PropertyNamingStrategy`,`ObjectMapper` 可以自动将下划线命名转换为小驼峰命名。 这里先使用`snakeCaseMapper`读取,再使用`camelCaseMapper`写出。

• 转换过程: 从 Elasticsearch 获取的数据(`Map`)使用 `ObjectMapper`序列化成 JSON 字符串,然后再反序列化成 `Map`。 在这个过程中,`PropertyNamingStrategy` 会自动进行命名转换。

配置 `ObjectMapper` Bean:

java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ObjectMapperConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 可以根据需要配置 ObjectMapper 的其他属性
        return objectMapper;
    }
}

2. 使用 Elasticsearch 的 `field_alias` (推荐但ES版本要支持):

从 Elasticsearch 7.0 开始,引入了 `field_alias`。 你可以利用这个功能,在 Elasticsearch 索引的 Mapping 中定义字段别名,将下划线命名的字段映射到小驼峰命名的字段。

java 复制代码
PUT my_index
{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "alias",
        "path": "first_name"
      },
      "last_name": {
        "type": "alias",
        "path": "last_name"
      }
    }
  }
}

注意: `field_alias` 只是别名,它仍然需要你存储实际的下划线命名的字段。 这样做的好处是,你可以在查询时使用小驼峰命名,但底层存储仍然是下划线命名。

3. 自定义 Elasticsearch 客户端 (不推荐):

你可以自定义 Elasticsearch 客户端,拦截响应结果,并手动进行字段命名转换。 这通常比较复杂,需要你深入了解 Elasticsearch 客户端的内部机制。不建议使用这种方法,因为它维护成本高。

4. 定义 DTO 类并使用 `@JsonProperty` 注解:

创建一个 DTO 类,对应 Elasticsearch 中的文档结构,并在 DTO 类的字段上使用 `@JsonProperty` 注解,将 Elasticsearch 的字段名映射到 DTO 类的字段上。

java 复制代码
import com.fasterxml.jackson.annotation.JsonProperty;

public class UserDTO {

    @JsonProperty("first_name")
    private String firstName;

    @JsonProperty("last_name")
    private String lastName;

    // Getters and setters
}

然后,从 Elasticsearch 获取数据后,将数据映射到 `UserDTO` 对象。

5. 使用 Elasticsearch 插件 (不推荐):

有一些第三方 Elasticsearch 插件可以自动进行字段命名转换。 但使用插件会增加系统的复杂性,并且可能存在兼容性问题,因此不建议使用。

选择哪种方法?

  • 优先考虑 field_alias (如果你的 Elasticsearch 版本支持): 它是最优雅的解决方案,对现有代码的改动最小。
  • ObjectMapper 手动转换: 如果你无法修改 Elasticsearch 的 Mapping,那么使用 ObjectMapper 是一个不错的选择。 它简单易用,并且可以灵活地控制转换过程。
  • @JsonProperty 注解: 如果你的数据结构相对固定,并且需要将其映射到 DTO 对象,那么使用 @JsonProperty 注解是一个好主意。
  • 避免自定义客户端和插件: 除非你有非常特殊的需求,否则不建议使用自定义客户端和插件,因为它们维护成本很高。
相关推荐
爬山算法36 分钟前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
猫头虎1 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
Moment1 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
Cobyte2 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc
程序员侠客行3 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
Honmaple3 小时前
QMD (Quarto Markdown) 搭建与使用指南
后端
MZ_ZXD0013 小时前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·vue.js·spring boot·python·django·php
PP东3 小时前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
invicinble3 小时前
springboot的核心实现机制原理
java·spring boot·后端
全栈老石4 小时前
Python 异步生存手册:给被 JS async/await 宠坏的全栈工程师
后端·python