SpringBoot整合Elasticsearch-按月分索引后怎么查

Spring Boot 整合 Elasticsearch:按月分索引后怎么查?

摘要: 按月拆 Elasticsearch 索引,写入时拼接年月只是第一步。按 ID 更新、按条件删除、单月查询和跨月查询都需要独立的路由依据。MetaLite 让 ES DAO 实现 TableRouter,在每种操作生成请求前决定物理索引。本文结合操作日志示例拆解动态索引路由,并指出“按月写入、查询仍返回逻辑索引”只有配合别名或通配符策略才可能查到数据。

日志类数据很适合按月建立索引:

app-log-2026-07
app-log-2026-08
app-log-2026-09

这样可以控制单索引规模,也便于按月归档和删除。

但很多实现只完成了写入路由:

index = "app-log-" + yyyyMM;

随后才发现,更新和查询时未必还拿得到创建时间。

分索引的难点不是字符串拼接,而是每种操作都必须回答:物理索引依据从哪里来?

一、逻辑索引和物理索引要分开

MetaLite 的实体使用 @Table 声明逻辑名称:

@Table("app-log")
public class OperateLogEntity implements Entity {
    private String id;
    private LocalDateTime createTime;
}

逻辑索引表达业务集合,物理索引表达实际存储位置:

逻辑索引:app-log
物理索引:app-log-2026-08

如果不需要拆分,二者可以相同;需要动态拆分时,由 DAO 的路由方法转换。

二、TableRouter 为什么有多组方法

TableRouter 没有只定义一个 route(),而是按操作和可用参数提供不同入口:

insertRoute(logicTable, entity)
queryRoute(logicTable)
queryRoute(logicTable, criteria)
queryRoute(logicTable, query)
updateRoute(logicTable, id)
updateRoute(logicTable, criteria)
deleteRoute(logicTable, id)
deleteRoute(logicTable, criteria)

原因很直接:不同操作掌握的路由信息不同。

  • 插入时有完整实体,可以读取创建时间;
  • 按 ID 更新时通常只有 ID;
  • 条件查询可以从 Criteria 中寻找时间范围;
  • 分页查询还可能从 Query 中获取条件;
  • 无条件 count 不一定知道目标月份。

默认实现全部返回逻辑索引,只有需要分索引的 DAO 才覆盖对应方法。

三、写入按月路由最容易实现

演示 DAO 的插入规则是:

@Override
public String insertRoute(String logicTable, Entity entity) {
    if (entity instanceof OperateLogEntity log) {
        return logicTable + "-" + DateTimeUtil.format2Str(
                log.getCreateTime(), Format.YYYY_MM);
    }
    return logicTable;
}

ES DAO 在构造 CreateRequest 之前调用它:

String index = insertRoute(logicTable, entity);
CreateRequest request = builder
        .index(index)
        .id(pkValue)
        .document(entity)
        .build();

批量插入也会逐条执行 insertRoute,所以一个批次中的不同实体可以写入不同月份索引。

这比用第一条数据决定整个批次索引更安全。

四、按 ID 更新为什么可能找不到索引

更新接口可能只有:

documentId = 9842...

如果 ID 本身不包含月份,updateRoute(logicTable, id) 无法推断文档在哪个物理索引。

常见解决方案有三种:

  1. ID 编码时间或分片信息;
  2. 业务调用同时提供月份,再构造带路由信息的条件;
  3. 先通过独立映射找到索引,再定点更新。

直接返回逻辑索引 app-log,只有当该名称被配置成可写别名且能唯一定位文档时才有意义。普通字符串不会自动代表所有 app-log-* 索引。

更新别名还要注意 Elasticsearch 的 write index 配置,避免多个物理索引同时匹配写操作。

五、单月查询应从时间条件计算索引

如果查询条件包含完整月份范围:

createTime >= 2026-08-01
createTime <  2026-09-01

queryRoute(logicTable, criteria) 可以返回:

app-log-2026-08

这样只搜索一个索引,分片数、查询成本和结果归并都最可控。

不过当前 Criteria 是通用表达模型,路由实现需要自行解析其中与时间有关的条件。框架不会凭字段名自动猜测哪个字段是分索引键。

六、跨月查询要返回多个索引表达式

查询 7 月到 9 月的数据时,可以构造:

app-log-2026-07,app-log-2026-08,app-log-2026-09

或者使用受控通配符:

app-log-2026-*

也可以维护读别名,例如:

app-log-recent

选择哪种方式取决于:

  • 时间跨度是否明确;
  • 历史索引数量;
  • 是否允许查询全部历史数据;
  • 索引生命周期和别名维护方式;
  • ES 集群对通配符展开的限制。

范围已知时,枚举准确月份通常比无边界通配符更可控。

七、示例代码当前展示的是扩展点,不是完整跨月方案

OperateLogEsDao 当前只在 insertRoute 中拼接月份,而查询、更新和删除路由仍返回 logicTable

因此它准确证明了:

BaseEntityEsDao 支持在操作前调用 TableRouter
DAO 可以按实体时间把写入路由到月索引

但它不能单独证明:

app-log 查询一定会自动命中 app-log-*
按 ID 更新会自动找到历史月份
跨月查询已经自动拆分和归并

这些能力需要索引别名、通配符或更完整的路由实现配合。

把演示代码的边界说清楚,比把一个扩展接口宣传成全自动分索引更有工程价值。

八、缺失索引如何处理

跨月查询经常包含没有数据、因此从未创建的月份。

此时要明确:

  • 查询不存在的索引是报错还是忽略;
  • 是否提前创建每月索引和 Mapping;
  • 是否允许自动创建索引;
  • 通配符没有匹配结果时返回空集还是异常;
  • 批量请求中部分索引失败如何呈现。

当前 BaseEntityEsDao 捕获 Elasticsearch 异常后统一转换为 DaoException,没有在 DAO 层自动吞掉“索引不存在”。

如果业务希望缺失月份等价于空数据,应在索引治理或查询构建层显式实现,而不是依赖异常信息变化。

九、Mapping 和索引模板必须跟上路由

按月创建物理索引后,每个月都要保持一致的字段类型和分析器。

否则同一个逻辑字段可能出现:

2026-07:userId 是 keyword
2026-08:userId 被动态映射成 long

跨月查询和聚合就会失败。

生产环境通常需要索引模板或创建流程统一:

  • Mapping;
  • 分片与副本;
  • refresh 策略;
  • 生命周期策略;
  • 读写别名;
  • 版本升级兼容。

TableRouter 只负责返回索引名称,不负责创建模板或迁移历史索引。

十、动态索引路由必须满足读写对称

可以把核心契约总结为:

写入时能确定物理索引
按 ID 修改和删除时能重新定位同一索引
单分片查询尽量定点
跨分片查询明确列出范围
缺失索引行为可预期
Mapping 在所有物理索引间兼容

MetaLite 把路由决策放在 DAO 接口层,而不是内置一套固定的月份规则,是因为分片键可能是日期、租户、业务 ID 或其他字段。

扩展点的价值不在于替业务自动猜测,而在于让每种操作都必须显式回答“这次究竟访问哪个物理索引”。


框架简介
MetaLite 是面向企业生产环境的新一代 Java 微服务技术底座。系列文章重点分享代码背后的设计思路、技术取舍与工程实践。

源码基线
JDK 21、Spring Boot 3.2.9、Spring Cloud 2023.0.1、Spring Cloud Alibaba 2023.0.1.3,具体组件版本以项目 backend-bom 为准。

作者简介
15 年 Spring 体系企业级开发经验,专注于 Java 微服务架构、工程治理与生产实践。

持续更新
MetaLite 系列内容将持续更新,围绕核心设计、源码链路、技术取舍与生产实践展开。欢迎关注作者,及时获取后续内容。

在线演示
演示地址: https://admin.metalite.top/
演示账号: guess
演示密码: admin@2026

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值