背景 版本
Elasticsearch : v 6.6
elasticsearch-rest-high-level-client.jar : v 6.6.2
目标 想提供一个web接口, 入参就是es的查询DSL json. 然后服务器用这个DSL透传转发到Elasticsearch服务期, 将数据返回给接口. 简单来说, 就是想在自己服务器上实现类似kibana上查询Elasticsearch数据的功能.
比如, 我们正常的查询DSL如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 { "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).
官方示例:
1 2 3 4 5 6 7 8 9 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.
1 2 3 4 5 { "wrapper" : { "query" : "eyJzaXplIjoxLCJxdWVyeSI6eyJib29sIjp7ImZpbHRlciI6W3sidGVybXMiOnsidXNlckNvZGUiOlsiMTEwMTExIl19fSx7InRlcm0iOnsiYWRkcmVzcyI6eyJ2YWx1ZSI6ImJlaWppbmcifX19XX19fQ==" } }
大家可以找个base64解码网站处理一下, 发现和我们的DSL一样. 然后用官方的方式处理下
1 2 3 4 5 6 7 { "query" : { "wrapper" : { "query" : "eyJzaXplIjoxLCJxdWVyeSI6eyJib29sIjp7ImZpbHRlciI6W3sidGVybXMiOnsidXNlckNvZGUiOlsiMTEwMTExIl19fSx7InRlcm0iOnsiYWRkcmVzcyI6eyJ2YWx1ZSI6ImJlaWppbmcifX19XX19fQ==" } } }
唉, 发现查询报错了, 为什么呢?
其实仔细分析一下,很容易发现问题. 我们将base64还原,看看最后的查询DSL的样子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 { "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重新单独拿出来处理下
1 2 3 4 5 6 7 { "query" : { "wrapper" : { "query" : "eyJib29sIjp7ImZpbHRlciI6W3sidGVybXMiOnsidXNlckNvZGUiOlsiMTEwMTExIl19fSx7InRlcm0iOnsiYWRkcmVzcyI6eyJ2YWx1ZSI6ImJlaWppbmcifX19XX19" } } }
搞定, 把上述DSL放到任何一个es的web客户端查询, 都有效.
聚合 关于聚合的功能, 官方没有提供现成的解析方法. 不过我觉得, 既然es的web端可以调用任意DSL, 通过java肯定能, 大不了就跳过RestHighLevelClient , 在RestLowLevelClient 上想办法.
// todo 等我找到合适的办法再补充.
java源码 1 2 3 4 5 6 7 8 9 10 11 class A { public void search (String boolJson) throws IOException { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder (); searchSourceBuilder.query(QueryBuilders.wrapperQuery(boolJson)); searchSourceBuilder.size(1 ); Optional<SearchResponse> response = restHighLevelClient.search(searchSourceBuilder); } }
参考