初学es,用spring-data-elasticsearch的模板方法组装、执行dsl,有时候碰到执行报错或者执行结果不如预期,这时候就很想看一下执行的dsl到底是什么,也方便在其他工具中直接修改看效果。
目前网络上只能找到如下的这些打印方式:
// 打印query语句
log.info(nativeSearchQuery.getQuery().toString());
// 打印分页语句
log.info(nativeSearchQuery.getPageable());
// 打印排序语句
log.info(nativeSearchQuery.getElasticsearchSorts());
...
上面的语句都只能打印dsl的某一部分,并不是传给es服务器的完整dsl。
查看elasticsearchRestTemplate的源码
组装搜索请求:
public SearchRequest searchRequest(Query query, @Nullable Class<?> clazz, IndexCoordinates index) {
elasticsearchConverter.updateQuery(query, clazz);
SearchRequest searchRequest = prepareSearchRequest(query, clazz, index);
QueryBuilder elasticsearchQuery = getQuery(query);
QueryBuilder elasticsearchFilter = getFilter(query);
searchRequest.source().query(elasticsearchQuery);
if (elasticsearchFilter != null) {
searchRequest.source().postFilter(elasticsearchFilter);
}
return searchRequest;
}
这里的source就是请求里的参数构建类,里面包含了所有的参数,查看SearchSourceBuilder的toString方法可以看到完整dsl的打印,断点查看结果:
image.png
既然如此,那我们只要把source打印出来不就行了吗。
但是不行,第一、es没有提供打印方法,第二、SearchRequest的工厂类RequestFactory作用域不是public,无法自己创建调用。
那只能用赖皮大法了,java reflect,直接上代码:
Method searchRequest = ReflectionUtils.findMethod(Class.forName("org.springframework.data.elasticsearch.core.RequestFactory"), "searchRequest", Query.class, Class.class, IndexCoordinates.class);
searchRequest.setAccessible(true);
Object o = ReflectionUtils.invokeMethod(searchRequest, elasticsearchRestTemplate.getRequestFactory(), nativeSearchQuery,{ES_MODEL}.class, elasticsearchRestTemplate.getIndexCoordinatesFor({ES_MODEL}.class));
Field source = ReflectionUtils.findField(Class.forName("org.elasticsearch.action.search.SearchRequest"), "source");
source.setAccessible(true);
Object s = ReflectionUtils.getField(source, o);
log.info("dsl:{}", s);
至此,我们终于得到了完整的dsl,直接拷贝就可以执行。