背景
版本
- Elasticsearch : v 6.6
- elasticsearch-rest-high-level-client.jar : v 6.6.2
目标
想提供一个web接口, 入参就是es的查询DSL json. 然后服务器用这个DSL透传转发到Elasticsearch服务期, 将数据返回给接口.
简单来说, 就是想在自己服务器上实现类似kibana上查询Elasticsearch数据的功能.
比如, 我们正常的查询DSL如下:
{
"size":1,
"query":{
"bool":{
"filter":[
{
"terms":{
"userCode":[
"110111"
]
}
},
{
"term":{
"address":{
"value":"beijing"
}
}
}
]
}
}
}
实现
查询
如果是单纯的查询, 官方提供了一个透传查询DSL的实现类 QueryBuilders.wrapperQuery()
, 可以通过这个QueryBuilders来实现我们自定义DSL的透传.
让我们先看看官方怎么说
A query that accepts any other query as base64 encoded string.
This query is more useful in the context of the Java high-level REST client or transport client to also accept queries as json formatted string. In these cases queries can be specified as a json or yaml formatted string or as a query builder (which is a available in the Java high-level REST client).
官方示例:
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query" : {
"wrapper": {
"query" : "eyJ0ZXJtIiA6IHsgInVzZXIiIDogIktpbWNoeSIgfX0="
}
}
}
'
由此可见, 官方是将wrapper当做一个关键字类型来处理的, 将我们的查询DSL转成base64,交给es服务器解析处理.
好,下面就是我们将上述DSL 通过QueryBuilders.wrapperQuery()
处理后的sql.
{
"wrapper" : {
"query" : "eyJzaXplIjoxLCJxdWVyeSI6eyJib29sIjp7ImZpbHRlciI6W3sidGVybXMiOnsidXNlckNvZGUiOlsiMTEwMTExIl19fSx7InRlcm0iOnsiYWRkcmVzcyI6eyJ2YWx1ZSI6ImJlaWppbmcifX19XX19fQ=="
}
}
大家可以找个base64解码网站处理一下, 发现和我们的DSL一样. 然后用官方的方式处理下
{
"query" : {
"wrapper": {
"query" : "eyJzaXplIjoxLCJxdWVyeSI6eyJib29sIjp7ImZpbHRlciI6W3sidGVybXMiOnsidXNlckNvZGUiOlsiMTEwMTExIl19fSx7InRlcm0iOnsiYWRkcmVzcyI6eyJ2YWx1ZSI6ImJlaWppbmcifX19XX19fQ=="
}
}
}
唉, 发现查询报错了, 为什么呢?
其实仔细分析一下,很容易发现问题. 我们将base64还原,看看最后的查询DSL的样子
{
"query":{
"wrapper":{
"query":{
"size":1,
"query":{
"bool":{
"filter":[
{
"terms":{
"userCode":["110111"]
}
},
{
"term":{
"address":{"value":"beijing"}
}
}
]
}
}
}
}
}
}
发现没, query里套query, 明显查询有问题. 其实这里es解析的时候, 发现wrapper关键字, 就会将下面的query查询替换原始query.
所以我们要将wrapper的不是原始完整的DSL,而是query下面的DSL. 我们将bool关键字的JSON重新单独拿出来处理下
{
"query" : {
"wrapper": {
"query" : "eyJib29sIjp7ImZpbHRlciI6W3sidGVybXMiOnsidXNlckNvZGUiOlsiMTEwMTExIl19fSx7InRlcm0iOnsiYWRkcmVzcyI6eyJ2YWx1ZSI6ImJlaWppbmcifX19XX19"
}
}
}
搞定, 把上述DSL放到任何一个es的web客户端查询, 都有效.
聚合
关于聚合的功能, 官方没有提供现成的解析方法.
不过我觉得, 既然es的web端可以调用任意DSL, 通过java肯定能, 大不了就跳过RestHighLevelClient, 在RestLowLevelClient上想办法.
// todo 等我找到合适的办法再补充.
java源码
class A {
public void search(String boolJson) throws IOException {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// query dsl 包装
searchSourceBuilder.query(QueryBuilders.wrapperQuery(boolJson));
searchSourceBuilder.size(1);
Optional<SearchResponse> response = restHighLevelClient.search(searchSourceBuilder);
}
}
参考
文档信息
- 本文作者:寒澈
- 本文链接:https://www.hancher.top/2022/11/17/es_query_dsl_wrapper/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)