解决 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 注解是一个好主意。
  • 避免自定义客户端和插件: 除非你有非常特殊的需求,否则不建议使用自定义客户端和插件,因为它们维护成本很高。
相关推荐
Hello.Reader1 小时前
用 Go Typed Client 快速上手 Elasticsearch —— 从建索引到聚合的完整实战
elasticsearch·golang·jenkins
努力的小雨1 小时前
还在为调试提示词头疼?一个案例教你轻松上手!
后端
魔都吴所谓2 小时前
【go】语言的匿名变量如何定义与使用
开发语言·后端·golang
陈佬昔没带相机2 小时前
围观前后端对接的 TypeScript 最佳实践,我们缺什么?
前端·后端·api
旋风菠萝3 小时前
JVM易混淆名称
java·jvm·数据库·spring boot·redis·面试
Livingbody4 小时前
大模型微调数据集加载和分析
后端
Livingbody4 小时前
第一次免费使用A800显卡80GB显存微调Ernie大模型
后端
weisian1514 小时前
Java WEB技术-序列化和反序列化认识(SpringBoot的Jackson序列化行为?如何打破序列化过程的驼峰规则?如何解决学序列化循环引用问题?)
java·spring boot
橘子编程4 小时前
SpringMVC核心原理与实战指南
java·spring boot·spring·tomcat·mybatis
Goboy5 小时前
Java 使用 FileOutputStream 写 Excel 文件不落盘?
后端·面试·架构