飞道的博客

系列课程 ElasticSearch 之第 8 篇 —— SpringBoot 整合 ElasticSearch 做查询(分页查询)

348人阅读  评论(0)

 

本篇博客基于前面第4篇的基础上改造的:https://blog.csdn.net/BiandanLoveyou/article/details/115773729

可以下载前面的代码:https://pan.baidu.com/s/1GnLrGGrP7nhw2Xovq3MtxQ   提取码:mhbi

这里我们需要修改一下 pom.xml 文件,引入 Google 的工具包:

完整配置如下:


  
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0 </modelVersion>
  6. <groupId>com.study </groupId>
  7. <artifactId>ElasticSearchTest </artifactId>
  8. <version>1.0-SNAPSHOT </version>
  9. <parent>
  10. <groupId>org.springframework.boot </groupId>
  11. <artifactId>spring-boot-starter-parent </artifactId>
  12. <version>2.2.0.RELEASE </version>
  13. </parent>
  14. <dependencies>
  15. <!--Spring boot 集成包-->
  16. <dependency>
  17. <groupId>org.springframework.cloud </groupId>
  18. <artifactId>spring-cloud-starter-netflix-eureka-client </artifactId>
  19. </dependency>
  20. <!--web支持-->
  21. <dependency>
  22. <groupId>org.springframework.boot </groupId>
  23. <artifactId>spring-boot-starter-web </artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot </groupId>
  27. <artifactId>spring-boot-starter-test </artifactId>
  28. <scope>test </scope>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot </groupId>
  32. <artifactId>spring-boot-starter-data-elasticsearch </artifactId>
  33. </dependency>
  34. <!-- 引入 Google 的集合工具包 -->
  35. <dependency>
  36. <groupId>com.google.collections </groupId>
  37. <artifactId>google-collections </artifactId>
  38. <version>1.0 </version>
  39. </dependency>
  40. </dependencies>
  41. <dependencyManagement>
  42. <dependencies>
  43. <dependency>
  44. <groupId>org.springframework.cloud </groupId>
  45. <artifactId>spring-cloud-dependencies </artifactId>
  46. <version>Greenwich.SR2 </version>
  47. <type>pom </type>
  48. <scope>import </scope>
  49. </dependency>
  50. </dependencies>
  51. </dependencyManagement>
  52. </project>

为了测试方便,我们提前准备5条数据,使用 Kibana 管理页面进行创建。

首先创建文档并指定类型:创建文档名称为【blog】,类型为【info】。指定博客名称为【blogName】,并在索引创建的时候使用的分词器,搜索字段的值时也指定的分词器为中文分词器。博客描述【blogDesc】,博客点击数【clickCount】,博客地址【blogUrl】。注意ES的字符串类型可以指定为 text 和 Keyword。


  
  1. POST /blog/ info
  2. {
  3. "info":{
  4. "properties":{
  5. "blogName":{
  6. "type": "text",
  7. "analyzer": "ik_smart",
  8. "search_analyzer": "ik_smart"
  9. },
  10. "blogDesc":{
  11. "type": "text",
  12. "analyzer": "ik_smart",
  13. "search_analyzer": "ik_smart"
  14. },
  15. "clickCount":{
  16. "type": "integer"
  17. },
  18. "blogUrl":{
  19. "type": "keyword"
  20. }
  21. }
  22. }
  23. }

执行结果:

然后使用 Kibana 创建5条测试数据(我们先记录每条记录生成的ID):


  
  1. POST /blog/info
  2. {
  3. "blogName":"了解ElasticSearch",
  4. "blogDesc":"这个系列教程我们主要学习ElasticSearch。去到大型互联网公司,这可是必备技能!",
  5. "clickCount":11,
  6. "blogUrl":"https://blog.csdn.net/BiandanLoveyou/article/details/115710882"
  7. }
  8. POST /blog/info
  9. {
  10. "blogName":"Windows安装ElasticSearch、Kibana、Logstash(ELK)",
  11. "blogDesc":"ElasticSearch是基于Java 语言开发的,因此需要JDK 环境",
  12. "clickCount":22,
  13. "blogUrl":"https://blog.csdn.net/BiandanLoveyou/article/details/115742897"
  14. }
  15. POST /blog/info
  16. {
  17. "blogName":"简单认识 Kibana 操作ElasticSearch,ElasticSearch 的版本控制",
  18. "blogDesc":"一般来收,在读取数据较多的场景,使用乐观锁比较多,能提高吞吐量。在更新数据比较多的场景,使用悲观锁,能保证数据准确性。",
  19. "clickCount":33,
  20. "blogUrl":"https://blog.csdn.net/BiandanLoveyou/article/details/115772565"
  21. }
  22. POST /blog/info
  23. {
  24. "blogName":"SpringBoot(2.2.X) 整合 最新版 ElasticSearch(7.12.X版本)",
  25. "blogDesc":"其实,我们可以把ElasticSearch设想成数据库!操作数据库的思想来操作即可。",
  26. "clickCount":44,
  27. "blogUrl":"https://blog.csdn.net/BiandanLoveyou/article/details/115773729"
  28. }
  29. POST /blog/info
  30. {
  31. "blogName":"Kibana高级查询语句、DSL语言查询和过滤、中文分词器",
  32. "blogDesc":"Elasticsearch中默认的标准分词器对中文分词不是很友好,会将中文词语拆分成一个个中文的汉字。因此需要引入中文分词器 es-ik 插件",
  33. "clickCount":55,
  34. "blogUrl":"https://blog.csdn.net/BiandanLoveyou/article/details/115789099"
  35. }

执行结果:

我们把执行五次的ID记录下来:


  
  1. 1条:Bs9O6ngBioXCws8F2uB2
  2. 2条:B89Q6ngBioXCws8FTuDJ
  3. 3条: CM9Q6ngBioXCws8FcOCH
  4. 4条:Cc9Q6ngBioXCws8FiOBV
  5. 5条:Cs9Q6ngBioXCws8FoODN

 

接下来,我们使用 SpringBoot 代码整合查询 ElasticSearch。

entity 包下创建实体类:BlogEntity。(我们可以在IDEA 安装 lombok 插件,可以省略get、set 方法,在实体上标注 @Data 即可。为了演示方便,这里写 get、set 方法)


  
  1. package com.study.entity;
  2. import org.springframework.data.annotation.Id;
  3. import org.springframework.data.elasticsearch.annotations.Document;
  4. /**
  5. * @author biandan
  6. * @description
  7. * @signature 让天下没有难写的代码
  8. * @create 2021-04-19 下午 9:28
  9. */
  10. @Document(indexName = "blog",type = "info")
  11. public class BlogEntity {
  12. @Id
  13. private String id; //ES 的ID
  14. private String blogName; //博客名称
  15. private String blogDesc; //博客描述
  16. private Integer clickCount; //点击数量
  17. private String blogUrl; //博客地址
  18. public String getId() {
  19. return id;
  20. }
  21. public void setId(String id) {
  22. this.id = id;
  23. }
  24. public String getBlogName() {
  25. return blogName;
  26. }
  27. public void setBlogName(String blogName) {
  28. this.blogName = blogName;
  29. }
  30. public String getBlogDesc() {
  31. return blogDesc;
  32. }
  33. public void setBlogDesc(String blogDesc) {
  34. this.blogDesc = blogDesc;
  35. }
  36. public Integer getClickCount() {
  37. return clickCount;
  38. }
  39. public void setClickCount(Integer clickCount) {
  40. this.clickCount = clickCount;
  41. }
  42. public String getBlogUrl() {
  43. return blogUrl;
  44. }
  45. public void setBlogUrl(String blogUrl) {
  46. this.blogUrl = blogUrl;
  47. }
  48. }

dao 包下创建 BlogDao:注意,我们继承的是 org.springframework.data.elasticsearch.repository.ElasticsearchRepository


  
  1. package com.study.dao;
  2. import com.study.entity.BlogEntity;
  3. import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
  4. /**
  5. * @author biandan
  6. * @description
  7. * @signature 让天下没有难写的代码
  8. * @create 2021-04-16 下午 11:32
  9. */
  10. public interface BlogDao extends ElasticsearchRepository<BlogEntity,String> {
  11. }

 

编写 controller 层:


  
  1. package com.study.controller;
  2. import com.google.common.collect.Lists;
  3. import com.study.dao.BlogDao;
  4. import com.study.entity.BlogEntity;
  5. import org.apache.commons.lang.StringUtils;
  6. import org.elasticsearch.index.query.BoolQueryBuilder;
  7. import org.elasticsearch.index.query.MatchQueryBuilder;
  8. import org.elasticsearch.index.query.QueryBuilders;
  9. import org.elasticsearch.index.query.TermQueryBuilder;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.data.domain.Pageable;
  12. import org.springframework.data.web.PageableDefault;
  13. import org.springframework.web.bind.annotation.RequestMapping;
  14. import org.springframework.web.bind.annotation.RequestMethod;
  15. import org.springframework.web.bind.annotation.RestController;
  16. import java.util.*;
  17. /**
  18. * @author biandan
  19. * @description
  20. * @signature 让天下没有难写的代码
  21. * @create 2021-04-16 下午 11:33
  22. */
  23. @RestController
  24. @RequestMapping(value = "/blog")
  25. public class BlogController {
  26. @Autowired
  27. private BlogDao blogDao;
  28. /**
  29. * 根据ID查询博客信息
  30. *
  31. * @param id
  32. * @return
  33. */
  34. @RequestMapping(value = "/findById", method = RequestMethod.GET)
  35. public Optional<BlogEntity> findById(String id) {
  36. Optional<BlogEntity> blogEntity = blogDao.findById(id);
  37. return blogEntity;
  38. }
  39. /**
  40. * 根据条件查询所有博客列表
  41. * @param blogName 博客名称
  42. * @param blogDesc 博客描述
  43. * @param clickCount 点击数
  44. * @return
  45. */
  46. @RequestMapping(value = "/findAll", method = RequestMethod.POST)
  47. public List<BlogEntity> findAll(String blogName,String blogDesc,Integer clickCount){
  48. BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
  49. //模糊查询博客名称
  50. if(StringUtils.isNotBlank(blogName)){
  51. MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery( "blogName", blogName);
  52. boolQueryBuilder.must(queryBuilder);
  53. }
  54. //模糊查询博客描述
  55. if(StringUtils.isNotBlank(blogDesc)){
  56. MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery( "blogDesc", blogDesc);
  57. boolQueryBuilder.must(queryBuilder);
  58. }
  59. //根据点击数精确查询
  60. if( null != clickCount){
  61. TermQueryBuilder queryBuilder = QueryBuilders.termQuery( "clickCount", clickCount);
  62. boolQueryBuilder.must(queryBuilder);
  63. }
  64. Iterable<BlogEntity> entities = blogDao.search(boolQueryBuilder);
  65. //使用Google的工具包
  66. List<BlogEntity> resultList = Lists.newArrayList(entities);
  67. return resultList;
  68. }
  69. }

说明:我们使用的是单机版 ES,不使用集群版。学习的时候就学单机版好了。集群很耗电脑性能的。

OK,我们启动服务,使用 postman 做请求测试:先测试 findById 接口,这里的 id 值就是我们之前创建数据的 ID 值。

然后测试 findAll 接口:

1、测试只传递 blogName 的情况:

 

2、增加 clickCount 参数:字段之间,取的是 and 

3、增加 blogDesc 字段的查询:博客内容是:需要JDK,而我们的请求参数是:安装JDK,但是ES依然帮我们查询出来,说明ES使用了分词检索功能。

 

OK,我们看下 ElasticSearch 如何做分页查询。

主要修改 controller 层,增加 findByPage 方法即可:引入 springframework.data 的相关接口


  
  1. package com.study.controller;
  2. import com.google.common.collect.Lists;
  3. import com.study.dao.BlogDao;
  4. import com.study.entity.BlogEntity;
  5. import org.apache.commons.lang.StringUtils;
  6. import org.elasticsearch.index.query.BoolQueryBuilder;
  7. import org.elasticsearch.index.query.MatchQueryBuilder;
  8. import org.elasticsearch.index.query.QueryBuilders;
  9. import org.elasticsearch.index.query.TermQueryBuilder;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.data.domain.Page;
  12. import org.springframework.data.domain.Pageable;
  13. import org.springframework.data.web.PageableDefault;
  14. import org.springframework.web.bind.annotation.RequestMapping;
  15. import org.springframework.web.bind.annotation.RequestMethod;
  16. import org.springframework.web.bind.annotation.RestController;
  17. import java.util.*;
  18. /**
  19. * @author biandan
  20. * @description
  21. * @signature 让天下没有难写的代码
  22. * @create 2021-04-16 下午 11:33
  23. */
  24. @RestController
  25. @RequestMapping(value = "/blog")
  26. public class BlogController {
  27. @Autowired
  28. private BlogDao blogDao;
  29. /**
  30. * 根据ID查询博客信息
  31. *
  32. * @param id
  33. * @return
  34. */
  35. @RequestMapping(value = "/findById", method = RequestMethod.GET)
  36. public Optional<BlogEntity> findById(String id) {
  37. Optional<BlogEntity> blogEntity = blogDao.findById(id);
  38. return blogEntity;
  39. }
  40. /**
  41. * 根据条件查询所有博客列表
  42. *
  43. * @param blogName 博客名称
  44. * @param blogDesc 博客描述
  45. * @param clickCount 点击数
  46. * @return
  47. */
  48. @RequestMapping(value = "/findAll", method = RequestMethod.POST)
  49. public List<BlogEntity> findAll(String blogName, String blogDesc, Integer clickCount) {
  50. BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
  51. //模糊查询博客名称
  52. if (StringUtils.isNotBlank(blogName)) {
  53. MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery( "blogName", blogName);
  54. boolQueryBuilder.must(queryBuilder);
  55. }
  56. //模糊查询博客描述
  57. if (StringUtils.isNotBlank(blogDesc)) {
  58. MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery( "blogDesc", blogDesc);
  59. boolQueryBuilder.must(queryBuilder);
  60. }
  61. //根据点击数精确查询
  62. if ( null != clickCount) {
  63. TermQueryBuilder queryBuilder = QueryBuilders.termQuery( "clickCount", clickCount);
  64. boolQueryBuilder.must(queryBuilder);
  65. }
  66. Iterable<BlogEntity> entities = blogDao.search(boolQueryBuilder);
  67. //使用Google的工具包
  68. List<BlogEntity> resultList = Lists.newArrayList(entities);
  69. return resultList;
  70. }
  71. /**
  72. * 分页查询
  73. *
  74. * @param blogName 博客名称
  75. * @param blogDesc 博客描述
  76. * @param clickCount 点击数量
  77. * @param pageable 分页信息,我们可以设置默认值: page、value(每页查询数量)的值
  78. * @return
  79. */
  80. @RequestMapping(value = "/findByPage", method = RequestMethod.POST)
  81. public Page<BlogEntity> findByPage(String blogName, String blogDesc, Integer clickCount, @PageableDefault(page = 0, value = 10) Pageable pageable) {
  82. BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
  83. //模糊查询博客名称
  84. if (StringUtils.isNotBlank(blogName)) {
  85. MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery( "blogName", blogName);
  86. boolQueryBuilder.must(queryBuilder);
  87. }
  88. //模糊查询博客描述
  89. if (StringUtils.isNotBlank(blogDesc)) {
  90. MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery( "blogDesc", blogDesc);
  91. boolQueryBuilder.must(queryBuilder);
  92. }
  93. //根据点击数精确查询
  94. if ( null != clickCount) {
  95. TermQueryBuilder queryBuilder = QueryBuilders.termQuery( "clickCount", clickCount);
  96. boolQueryBuilder.must(queryBuilder);
  97. }
  98. Page<BlogEntity> search = blogDao.search(boolQueryBuilder, pageable);
  99. return search;
  100. }
  101. }

重启服务,使用 postman 测试:

查询结果:


  
  1. {
  2. "content": [
  3. {
  4. "id": "Bs9O6ngBioXCws8F2uB2",
  5. "blogName": "了解ElasticSearch",
  6. "blogDesc": "这个系列教程我们主要学习ElasticSearch。去到大型互联网公司,这可是必备技能!",
  7. "clickCount": 11,
  8. "blogUrl": "https://blog.csdn.net/BiandanLoveyou/article/details/115710882"
  9. },
  10. {
  11. "id": "CM9Q6ngBioXCws8FcOCH",
  12. "blogName": "简单认识 Kibana 操作ElasticSearch,ElasticSearch 的版本控制",
  13. "blogDesc": "一般来收,在读取数据较多的场景,使用乐观锁比较多,能提高吞吐量。在更新数据比较多的场景,使用悲观锁,能保证数据准确性。",
  14. "clickCount": 33,
  15. "blogUrl": "https://blog.csdn.net/BiandanLoveyou/article/details/115772565"
  16. }
  17. ],
  18. "pageable": {
  19. "sort": {
  20. "sorted": false,
  21. "unsorted": true,
  22. "empty": true
  23. },
  24. "offset": 0,
  25. "pageSize": 2,
  26. "pageNumber": 0,
  27. "paged": true,
  28. "unpaged": false
  29. },
  30. "facets": [],
  31. "aggregations": null,
  32. "scrollId": null,
  33. "maxScore": 0.41181886,
  34. "totalElements": 4,
  35. "totalPages": 2,
  36. "number": 0,
  37. "size": 2,
  38. "sort": {
  39. "sorted": false,
  40. "unsorted": true,
  41. "empty": true
  42. },
  43. "numberOfElements": 2,
  44. "first": true,
  45. "last": false,
  46. "empty": false
  47. }

默认 page 的第一页是 0,size 是每页查询数量。

返回的分页参数:totalElements是总数量,totalPages是总页数,number是当前页(从0开始计算),size是每页查询数量。

代码地址:https://pan.baidu.com/s/13QyQvO3mixrBL3Ubxh2RLA  提取码:fwfw

 

 

 

 

 


转载:https://blog.csdn.net/BiandanLoveyou/article/details/115874372
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场