自学内容网 自学内容网

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)!