RestHighLevelClient查询es
本篇分享的是es官网推荐的es客户端组件resthighlevelclient的使用,其封装了操作es的crud方法,底层原理就是模拟各种es需要的请求,如put,delete,get等方式;本篇主要分享常用查询,希望能给大家带来好的帮助;
- 分页查询
-
条件查询
- 文本模糊匹配
- 时间范围匹配
-
超时设置
- es超时时间
- resthighlevelclient发送请求的http响应超时时间
- 排序
- 指定返回列
- 模拟一个post获取es数据
准备工作
本人es服务端的版本是5.6.x,因此resthighlevelclient建议同样引入相同主版本的包,相关参考文档():
1 <dependency> 2 <groupid>org.elasticsearch.client</groupid> 3 <artifactid>elasticsearch-rest-high-level-client</artifactid> 4 <version>5.6.16</version> 5 </dependency> 6 7 <dependency> 8 <groupid>com.alibaba</groupid> 9 <artifactid>fastjson</artifactid> 10 <version>1.2.56</version> 11 <scope>compile</scope> 12 </dependency>
作为客户端来说,我们需要知道es服务的ip:端口,以此来连接到服务端,对于es来说连接服务端其实就是往这个ip:端口上发送各种格式请求参数,如下创建个restclient:
1 public resthighlevelclient client() { 2 assert.requirenonempty(this.hosts, "无效的es连接"); 3 return new resthighlevelclient( 4 restclient.builder(this.hosts).build() 5 ); 6 }
分页查询
作为客户端来说resthighlevelclient的查询操作及其简单,只需要如下简短代码即可操作查询:
1 searchsourcebuilder sourcebuilder = new searchsourcebuilder(); 2 searchrequest rq = new searchrequest(); 3 //索引 4 rq.indices(index); 5 //各种组合条件 6 rq.source(sourcebuilder); 7 8 //请求 9 system.out.println(rq.source().tostring()); 10 searchresponse rp = client().search(rq);
如上模板我们知道要完成一次查询,需要知道对应的索引和各种业务查询条件;索引是必须的,至于条件这里先来分页吧,可以通过如下方式设置页码:
1 from = from <= -1 ? 0 : from; 2 size = size >= 1000 ? 1000 : size; 3 size = size <= 0 ? 15 : size; 4 //其实位置 5 sourcebuilder.from(from); 6 //每页数量 7 sourcebuilder.size(size);
条件查询
对于查询来说通常都有各种and和or的条件,可以通过searchsourcebuilder的must和should来设置and和or关系,这里用到了must;
1.文本模糊匹配
对于es关键字或单词的查询我们可以借助querybuilders.wildcardquery方法来操作,只需要指定es中对应的列和要查询的内容即可:
1 //模糊匹配 2 boolquerybuilder.must(querybuilders.wildcardquery(k, v.tostring()));
2.时间范围匹配
相对时间条件来说,通常的需求都是按照范围来查询的,这里可以借助querybuilders.rangequery指定es中某列(k)的范围匹配:
1 boolquerybuilder.must( 2 querybuilders.rangequery(k). 3 gte(format.format(mapv.get("start"))). 4 lt(format.format(mapv.get("end"))));
超时设置
使用resthighlevelclient作为查询端,需要注意的超时时间有两种:es本身需要的时间和rest发送http的响应时间
1.es超时时间
对于es服务端来说往往需要设置一下查询超时时间,尽管es是分布式查询较快并建立在多个lucence基础上聚合的查询,也需要设置超时时间,避免由于数据量过大或集群过大导致查询缓慢问题;
1 sourcebuilder.timeout(new timevalue(timeout, timeunit.seconds));
2.resthighlevelclient发送请求的http响应超时时间
对应http来说往往会有一个响应的时长,超过时长后将不能再获取到数据,resthighlevelclient作为以http方式请求es客户端这点需要注意;比如es查询需要10s,但是http设置了5s,数据就无法正常返回;
1 return new resthighlevelclient( 2 restclient.builder(this.hosts). 3 setmaxretrytimeoutmillis(60 * 1000). //设置http客户请求时长 4 build() 5 );
排序
排序在业务中也是常用,es提供了默认排序和自定义排序,默认排序通常都是_score来排的,如下参数:
如果自定义列来排序,可以通过如下方式:
1 sourcebuilder.sort(new fieldsortbuilder(k).order(v ? sortorder.asc : sortorder.desc));
指定返回列
对应查询通常会指定一些返回列,就sql查询来说select *通常都比select cols要慢,一个原因是数据量少了有可能走了索引;es其实也同样,指定返回列可减少返回数据体量;
1 //返回和排除列 2 if (!collectionutils.isempty(includefields) || !collectionutils.isempty(excludefields)) { 3 sourcebuilder.fetchsource(includefields, excludefields); 4 }
模拟一个post获取es数据
如上就是查询es常用一些参数说明,配置及心得;下面给出完整的示例代码:
1 /** 2 * @param index 3 * @param from 4 * @param size 5 * @param where 6 * @param sortfieldstoasc 7 * @param includefields 8 * @param excludefields 9 * @param timeout 10 * @return 11 */ 12 public list<map<string, object>> searchindex(string index, int from, int size, map<string, object> where, 13 map<string, boolean> sortfieldstoasc, string[] includefields, string[] excludefields, 14 int timeout) { 15 simpledateformat format = new simpledateformat("yyyy-mm-dd't'hh:mm:ss.sssz"); 16 try { 17 searchsourcebuilder sourcebuilder = new searchsourcebuilder(); 18 //条件 19 if (where != null && !where.isempty()) { 20 boolquerybuilder boolquerybuilder = querybuilders.boolquery(); 21 where.foreach((k, v) -> { 22 if (v instanceof map) { 23 //范围选择map 暂定时间 24 map<string, date> mapv = (map<string, date>) v; 25 if (mapv != null) { 26 boolquerybuilder.must( 27 querybuilders.rangequery(k). 28 gte(format.format(mapv.get("start"))). 29 lt(format.format(mapv.get("end")))); 30 } 31 } else { 32 //普通模糊匹配 33 boolquerybuilder.must(querybuilders.wildcardquery(k, v.tostring())); 34 } 35 }); 36 sourcebuilder.query(boolquerybuilder); 37 } 38 39 //分页 40 from = from <= -1 ? 0 : from; 41 size = size >= 1000 ? 1000 : size; 42 size = size <= 0 ? 15 : size; 43 sourcebuilder.from(from); 44 sourcebuilder.size(size); 45 46 //超时 47 sourcebuilder.timeout(new timevalue(timeout, timeunit.seconds)); 48 49 //排序 50 if (sortfieldstoasc != null && !sortfieldstoasc.isempty()) { 51 sortfieldstoasc.foreach((k, v) -> { 52 sourcebuilder.sort(new fieldsortbuilder(k).order(v ? sortorder.asc : sortorder.desc)); 53 }); 54 } else { 55 sourcebuilder.sort(new scoresortbuilder().order(sortorder.desc)); 56 } 57 58 //返回和排除列 59 if (!collectionutils.isempty(includefields) || !collectionutils.isempty(excludefields)) { 60 sourcebuilder.fetchsource(includefields, excludefields); 61 } 62 63 searchrequest rq = new searchrequest(); 64 //索引 65 rq.indices(index); 66 //各种组合条件 67 rq.source(sourcebuilder); 68 69 //请求 70 system.out.println(rq.source().tostring()); 71 searchresponse rp = client().search(rq); 72 73 //解析返回 74 if (rp.status() != reststatus.ok || rp.gethits().gettotalhits() <= 0) { 75 return collections.emptylist(); 76 } 77 78 //获取source 79 return arrays.stream(rp.gethits().gethits()).map(b -> { 80 return b.getsourceasmap(); 81 }).collect(collectors.tolist()); 82 83 } catch (exception ex) { 84 ex.printstacktrace(); 85 } 86 return collections.emptylist(); 87 }
分享通过restclient方式往es发送的请求参数以及模拟post方式发送参数获取es数据:
1 { 2 "from" : 0, 3 "size" : 5, 4 "timeout" : "60s", 5 "query" : { 6 "bool" : { 7 "must" : [ 8 { 9 "range" : { 10 "timestamp" : { 11 "from" : "2019-05-23t19:17:59.000+0800", 12 "to" : "2019-05-23t19:18:00.000+0800", 13 "include_lower" : true, 14 "include_upper" : false, 15 "boost" : 1.0 16 } 17 } 18 }, 19 { 20 "wildcard" : { 21 "data" : { 22 "wildcard" : "虎", 23 "boost" : 1.0 24 } 25 } 26 } 27 ], 28 "disable_coord" : false, 29 "adjust_pure_negative" : true, 30 "boost" : 1.0 31 } 32 }, 33 "_source" : { 34 "includes" : [ ], 35 "excludes" : [ 36 "serverip" 37 ] 38 }, 39 "sort" : [ 40 { 41 "timestamp" : { 42 "order" : "desc" 43 } 44 } 45 ] 46 }
有了上面参数,我们完全可以通过postman直接发post给es服务端,让其返回响应的数据而;resthighlevelclient作为http客户端就是帮我们完成了这部分封装:
上一篇: 你真是我亲弟