ElasticsearchRestTemplate DSL日志打印
ElasticsearchRestTemplate DSL日志打印
痛点
在使用 ElasticsearchRestTemplate 进行数据操作时,经常遇到的一个问题是线上问题排查困难。具体来说,在线上环境中,当出现问题时,我们往往无法直接获取到实际执行的 DSL(Domain Specific Language)语句。这导致我们在排查问题时面临以下几个主要挑战:
- 缺乏可追溯性:当线上系统出现性能问题或数据不一致的问题时,我们需要能够回溯到具体的查询或更新操作。然而,由于 ElasticsearchRestTemplate 默认并不会记录实际执行的 DSL 语句,我们很难确定问题的具体原因。
- 难以重现问题:在开发和测试环境中,我们通常会模拟各种场景来测试系统的健壮性和性能。但在生产环境中,由于数据量大且复杂,很多问题只有在实际运行时才会暴露出来。
- 调试难度增加:当系统出现异常或错误时,我们需要能够快速定位问题并修复。如果无法获取到实际执行的 DSL 语句,我们就无法准确判断问题的原因。
- 维护成本高:在长期维护过程中,系统可能会经历多次迭代和升级。如果没有记录实际执行的 DSL 语句,每次修改或优化查询逻辑时都需要重新验证其正确性和性能。
- 性能优化困难:在优化过程中,我们需要能够分析每个查询的实际执行情况,从而找出性能瓶颈并进行针对性的优化。如果没有记录实际执行的 DSL 语句,我们就无法准确评估每个查询的性能表现,从而导致优化效果不佳。
解决方案
为了应对上述痛点,我们需要在使用 ElasticsearchRestTemplate 时打印实际执行的 DSL 日志。
打印基础文档查询信息
经查询发现有人提出打印queryBuilder.build().getQuery()
的方法。然而,发现只会显示基础文档查询信息,而不包括过滤、聚合等内容。这并非我们所需的最终DML语句。
log.info("DML:{}", queryBuilder.build().getQuery());
打印最终DML语句
通过Debug我们发现 SearchRequest
中的source
属性,正是我们想要的最终DML语句。
而 SearchRequest 需要通过 RequestFactory 获取,虽然 ElasticsearchRestTemplate 提供了getRequestFactory()
方法获取RequestFactory,但RequestFactory是个私有类,无法编译运行。好在java留了后门,提供了强大的反射机制。于是,对于elasticsearchRestTemplate.search()
方法编写了如下切面:
/**
* Description: ElasticsearchRestTemplate 切面
*
* @author YanAn
* @date 2024/9/20 10:52
*/
@Slf4j
@Aspect
@Component
public class ElasticsearchRestTemplateAspect {
@Resource
private ElasticsearchRestTemplate elasticsearchRestTemplate;
/**
* AbstractElasticsearchTemplate#search(org.springframework.data.elasticsearch.core.query.Query, java.lang.Class) 前置通知
*
* @param joinPoint
*/
@Before("execution(* org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate.search(org.springframework.data.elasticsearch.core.query.Query, java.lang.Class))")
public void beforeSearch(JoinPoint joinPoint) {
try {
Object[] args = joinPoint.getArgs();
if (args != null && args.length == 2) {
Query query = (Query) args[0];
Class<?> clazz = (Class<?>) args[1];
IndexCoordinates index = elasticsearchRestTemplate.getIndexCoordinatesFor(clazz);
Method searchRequest = Class.forName("org.springframework.data.elasticsearch.core.RequestFactory").getMethod("searchRequest", Query.class, Class.class, IndexCoordinates.class);
searchRequest.setAccessible(true);
Object result = searchRequest.invoke(elasticsearchRestTemplate.getRequestFactory(), query, clazz, index);
if (result instanceof SearchRequest) {
SearchSourceBuilder source = ((SearchRequest) result).source();
log.info("DSL: {}", source.toString());
}
} else {
log.info("DSL打印失败");
}
} catch (Exception e) {
log.warn("DSL打印失败", e);
}
}
}
效果如下:
原文地址:https://blog.csdn.net/m0_49183244/article/details/142380467
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!