本文将作为es系列第三篇,结合常见的实例,来演示下如何通过RestHighLevelClient
来实现es的各种查询支持
I. 项目搭建
1. 项目依赖
本项目借助SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ IDEA
进行开发
开一个web服务用于测试
1 2 3 4 5 6
| <dependencies> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency> </dependencies>
|
2. 配置信息
配置文件application.yml,注意下面的配置信息,下面采用的是由我们自己来解析配置的方式
1 2 3 4 5 6 7 8
| elasticsearch: host: localhost port: 9200 user: elastic pwd: test123 connTimeout: 3000 socketTimeout: 5000 connectionRequestTimeout: 500
|
II. 实例演示
0. 准备
在开始之前,先准备插入几条数据,这里会借助上一篇CURD博文中的插入接口
在开始之前就准备两条数据
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 26 27
| @Component public class TermQueryDemo { private BasicCurdDemo basicCurdDemo; @Autowired private RestHighLevelClient client; @Autowired private RequestOptions requestOptions;
private String TEST_ID = "11123-33345-66543-55231"; private String TEST_ID_2 = "11123-33345-66543-55232";
private String index = "term-demo";
public TermQueryDemo(BasicCurdDemo basicCurdDemo) throws IOException { this.basicCurdDemo = basicCurdDemo; Map<String, Object> doc = newMap("name", "一灰灰", "age", 10, "skills", Arrays.asList("java", "python"), "site", "blog.hhui.top"); basicCurdDemo.addDoc(index, doc, TEST_ID); doc = newMap("name", "二灰灰", "age", 16, "skills", Arrays.asList("js", "html")); basicCurdDemo.addDoc(index, doc, TEST_ID_2); }
@PreDestroy public void remove() throws IOException { basicCurdDemo.delete(index, TEST_ID); basicCurdDemo.delete(index, TEST_ID_2); } }
|
1. 全量查询
即查询所有的文档,如借助kibanan的控制台,发起的请求形如
1 2 3 4 5 6
| GET index/_search { "query": { "match_all": {} } }
|
于此对应的java实现如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
private void queryAll() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, requestOptions); System.out.println("mathAll: " + searchResponse.toString()); }
|
注意上面的实现:
- 初始化
SearchRequest
实例,用于构建请求相关数据
SearchSourceBuilder
来填充查询条件
client.search(searchRequest, requestOptions)
执行查询请求,第二个参数为请求参数,这里主要是设置请求时的权限验证信息
通常来说,实际的业务场景中,不太可能出现上面这种没有任何限制的查全量数据,即便真的有查全量数据的case,更常见的是分页查询,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| private void queryAll() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); int page = 1; int size = 2; int from = (page - 1) * size; searchSourceBuilder.from(from); searchSourceBuilder.size(size); searchSourceBuilder.sort(new FieldSortBuilder("age").order(SortOrder.DESC)); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, requestOptions); System.out.println("mathAll: " + searchResponse.toString()); }
|
2. 根据Field值精确查询
即es中常说的term查询,具体实现如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
private void term() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.termQuery("site", "blog.hhui.top")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("term: " + response.toString()); }
|
从上面的实现也可以看出,查询的套路没啥区别,无非就是SearchSourceBuilder
中的参数构造不一样;上面主要通过
QueryBuilders.termQuery("site", "blog.hhui.top")
来构建 term的查询条件,表明查询 site=blog.hhui.top
的文档
中文查询不到问题
在我们实际使用过程中,如果value为中文,在查询时,可能会遇到命名有对应的数据,但是就查不到,主要原因就在于分词,如对于中文的查询,可以考虑下面这种方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private void term2() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.termQuery("name.keyword", "一灰灰"));
searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("term2: " + response.toString()); }
|
3. Field值in查询
另外一个常见的就是多值查询,也就是我们常说的 field in (val1, val2...)
,这个对应的就是es中的terms
查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
private void multTerm() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.termsQuery("name.keyword", "一灰灰", "二灰灰"));
searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("term: " + response.toString()); }
|
4. 范围查询
对于数值类型的Field,同样是支持比较、范围查询的,对应的是es中 range
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
private void range() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.rangeQuery("age").gt(8).lt(12)); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("range: " + response.toString()); }
|
注意上面的查询有条件
QueryBuilders.rangeQuery("age").gt(8).lt(12)
- 表示查询
age > 8 && age < 12
- gte: 表示 >=
- lte: 表示 <=
5. Field是否存在查询
es不同于mysql的在于它的field可以动态新增,当我们希望查询包含某个字段的文档时,可以考虑 exists
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
private void exists() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.existsQuery("site")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("exists: " + response.toString()); }
|
6. 模糊查询
es作为搜索引擎,更常见的是模糊匹配,比如match查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
private void match() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchQuery("name", "灰")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("matchQuery: " + response.toString()); }
|
多Field中进行查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
private void multiMatch() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.multiMatchQuery("灰", "name", "site")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("multiMatchQuery: " + response.toString()); }
|
在es的语法支持中,除了match,还有一个wildcard
,可以使用?
来代指单字符,*
来代指0..n字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
private void wild() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.wildcardQuery("site", "*top")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("wildcard: " + response.toString()); }
|
7. 正则匹配
1 2 3 4 5 6 7 8 9 10
| private void regexp() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.regexpQuery("site", ".*hhui.*")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("regexpQuery: " + response.toString()); }
|
8. 前缀查询
1 2 3 4 5 6 7 8 9 10
| private void prefix() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.prefixQuery("site", "blog")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("prefixQuery: " + response.toString()); }
|
9.小结
本文虽然介绍了一些常见的查询case,但注意并不仅仅只有这些,比如
- 查询指定Feild的内容
- 排序
- 分组聚合
- 多查询条件组合:and/or
- 高亮
- …
更多的使用实例,敬请期待…,欢迎感兴趣的小伙伴,点赞收藏评论一波😝
III. 不能错过的源码和相关知识点
0. 项目
系列博文
源码
1. 微信公众号: 一灰灰Blog
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
一灰灰blog
Be the first person to leave a comment!