个人随笔
目录
SpringBoot2.0整合ELASTICSEARCH6实战之全文检索
2019-04-03 23:09:51

上一篇博文,我们整合了一下ES6,实现了添加和查找数据的操作,但是只是简单的根据ID操作而已,我研究ES的目标是可以用在博客平台上作为一个高效率的搜索框架,根据用户输入内容,高效的查询出博主名称、标签名称、博文标题、博文正文中包含有用户输入关键字的博主、标签、博文来。用普通的数据库like当然不行啦,难以想象效率有多低。所以这里就用ES,当然为了提高效率,肯定得多耗费储存,空间换时间嘛,守恒定律就算在代码领域也是符合的。

1、本实例目标

根据用户输入的内容,分页查询出标题,正文中包含这些内容的博文,返回给页面。这里的包含不是全包含,只需要含有用户输入的内容也得检索出来。
我这篇博文完全是基于SpringBoot2.0整合 Elasticsearch6实战这一篇搭建来的。

2、实体结构Topic

  1. //elasticsearch 6.0.0及之后移除了一个索引允许映射多个类型的操作(Removal of mapping types)
  2. @Document(indexName="topic",type="topic")
  3. public class Topic {
  4. @Id
  5. private Long id;
  6. private String title;
  7. private String content;
  8. public Long getId() {
  9. return id;
  10. }
  11. public void setId(Long id) {
  12. this.id = id;
  13. }
  14. public String getContent() {
  15. return content;
  16. }
  17. public void setContent(String content) {
  18. this.content = content;
  19. }
  20. public String getTitle() {
  21. return title;
  22. }
  23. public void setTitle(String title) {
  24. this.title = title;
  25. }
  26. }

因为elasticsearch 6.0.0及之后移除了一个索引允许映射多个类型的操作(Removal of mapping types),所以这里索引名称和类型都用topic。话说我的博客系统数据库设计是Topic表和Content表分开来的,这里只用一个实体不会冲突么?其实不会的,我在创建博文的时候就直接把标题和内容保存在ES中啦,读取的时候也是直接读取ES的,不会去取数据库,想当于多存储了一份数据(服务器内存硬盘小,好忧伤:expressionless:)。

3、操作ES的类

  1. public interface TopicDao extends ElasticsearchRepository<Topic, Long>{
  2. }

这里跟上一篇博文不同,这里继承的是ElasticsearchRepository,之间的差别后续再研究,毕竟我这个只是实战而已。

4、测试类MyController

  1. /**
  2. * ES控制类
  3. * @author suibibk.com
  4. */
  5. @RestController
  6. public class MyController {
  7. @Autowired
  8. private TopicDao topicDao;
  9. /**
  10. * 保存博文
  11. * @param request
  12. * @return
  13. */
  14. @RequestMapping("/add")
  15. public String add(HttpServletRequest request) {
  16. Long id = System.currentTimeMillis();
  17. String title = request.getParameter("title");
  18. String content = request.getParameter("content");
  19. Topic topic =new Topic();
  20. topic.setId(id);
  21. topic.setTitle(title);
  22. topic.setContent(content);
  23. topicDao.save(topic);
  24. System.out.println("topicid:"+id);
  25. return id+"";
  26. }
  27. /**
  28. * 根据ID查找
  29. * @param request
  30. * @return
  31. */
  32. @RequestMapping("/selectById")
  33. public Topic selectById(HttpServletRequest request) {
  34. String id = request.getParameter("id");
  35. //下面这里返回结果
  36. Optional<Topic> t = topicDao.findById(Long.parseLong(id));
  37. return t.get();
  38. }
  39. /**
  40. * 根据用户的输入查找,虽然传的是content,这里只是名称定义而已,会搜索title和content都含有的记录
  41. * @param request
  42. * @return
  43. */
  44. @RequestMapping("/selectBycontent")
  45. public List<Topic> selectBycontent(HttpServletRequest request) {
  46. String content = request.getParameter("content");
  47. QueryStringQueryBuilder builder = new QueryStringQueryBuilder(content);
  48. Iterable<Topic> searchResult = topicDao.search(builder);
  49. Iterator<Topic> topics = searchResult.iterator();
  50. List<Topic> list = new ArrayList<Topic>();
  51. while(topics.hasNext()) {
  52. list.add(topics.next());
  53. }
  54. return list;
  55. }
  56. /**
  57. * 分页搜索,pageNum是从0开始的
  58. * @param request
  59. * @return
  60. */
  61. @RequestMapping("/selectBycontentPage")
  62. public List<Topic> selectBycontentPage(HttpServletRequest request) {
  63. String pageNum = request.getParameter("pageNum");
  64. int pageSize=2;
  65. String content = request.getParameter("content");
  66. QueryStringQueryBuilder builder = new QueryStringQueryBuilder(content);
  67. Pageable pageable = PageRequest.of(Integer.parseInt(pageNum), pageSize);
  68. // 分页参数
  69. Iterable<Topic> searchResult = topicDao.search(builder,pageable);
  70. Iterator<Topic> topics = searchResult.iterator();
  71. List<Topic> list = new ArrayList<Topic>();
  72. while(topics.hasNext()) {
  73. list.add(topics.next());
  74. }
  75. System.out.println("数据大小:"+list.size());
  76. return list;
  77. }
  78. }

这里主要注意是用如下的类来分页查询的。当然也还有别的类,以后再研究。

  1. Pageable pageable = PageRequest.of(Integer.parseInt(pageNum), pageSize);
  2. QueryStringQueryBuilder builder = new QueryStringQueryBuilder(content);
  3. Iterable<Topic> searchResult = topicDao.search(builder,pageable);

5、启动程序测试

1.先启动该SpringBoot项目
这个当然不用说啦,右键运行即可。

2.添加几十条数据
访问链接:http://127.0.0.1:8080/add?title路漫漫其修远兮,吾将上下而求索&content=三生膳食 然后自救修改title和content添加几十条数据。每次添加完后都会返回一个id,就表示成功啦。

3、测试根据ID查询
根据上面添加数据的id,访问如下链接:
http://127.0.0.1:8080/selectById?id=1554284695241
将会返回如下内容:
{“id”:1554284695241,”title”:”路漫漫其修远兮,吾将上下而求索”,”content”:”三生三世”}

4、测试根据关键字搜索
访问如下链接:
http://127.0.0.1:8080/selectBycontent?content=的固
返回如下数据:

当然,上面的数据都是我在第二步插入的,我们可以知道,虽然传的是“的固”并不是一个组成短语,却仍然可以查询还有的或者固的内容来,真是强大。话说这里虽然只是实战,不讲原理,但是还是提一下原理是:倒排序。稍微了解的都可以知道,当然再保存的时候比较耗费时间和存储空间啦。没办法为了提高查询效率么,既然避免不了耗费更多的存储空间,只能尽量用算法优化降低存储空间的占用咯。

5、测试根据关键字分页查询
访问如下链接:
http://127.0.0.1:8080/selectBycontentPage?content=的固&pageNum=0
查询的是第一页,注意这里0才是第一页,返回如下数据:

可以看到只会返回第一页的数据,两条是因为我们代码里写死了一次查询两条,当我们把pageNum改为1的时候,返回的将会是第二页的数据,如下:

大家不要看中文内容,看到ID是有变化的。

6、GITHUB地址

https://github.com/suibibk/springboot-elasticsearch.git

总结

本博文基本上没有介绍任何原理性的东西,都只是为了实现全文检索目标的实战。后续会有博文慢慢研究讲解ES的原理。纯手打不易,转发请标注来源:
来源网站:随笔博客:https://www.suibibk.com/ ;IT小博客:https://www.suibibk.com/blog/538872310925361152

 647

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2