博客项目目录: 请戳这里
准备
需求:用户登录后,点开搜索框,输入搜索内容,回车之后,就会跳转到对应的搜索页面 基本思路:
首先将所有的文章信息查询出来,同步到elasticsearch中,然后通过es进行搜索,得到对应的文档,之后转化成MyBatis的page信息,显示在前端页面
1.添加依赖包,修改yml配置
- es相关依赖用于整合elasticsearch,项目启动时,需要事先安装es,并开启es服务
- modelmapper用于将MyBatis查询到的记录转化为es的Docment
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>1.1.0</version>
</dependency>
一般来说,es的9200端口用于查询,9300端口用于连接程序
2.修改index.js
原来搜索框输入内容,回车之后,跳到固定的某一个网址进行搜索,现在修改之后,跳到我们写的接口进行搜索
3.新增search.ftl
<#include "/inc/layout.ftl" />
<@layout "搜索 - ${q}">
<#include "/inc/header-panel.ftl" />
<div class="layui-container">
<div class="layui-row layui-col-space15">
<div class="layui-col-md8">
<div class="fly-panel">
<div class="fly-panel-title fly-filter">
<a>您正在搜索关键字 “ ${q} ” - 共有 <strong>${pageData.total}</strong> 条记录</a>
<a href="#signin" class="layui-hide-sm layui-show-xs-block fly-right" id="LAY_goSignin" style="color: #FF5722;">去签到</a>
</div>
<ul class="fly-list">
<#list pageData.records as post>
<@plisting post></@plisting>
</#list>
</ul>
<@paging pageData></@paging>
</div>
</div>
<#include "/inc/right.ftl" />
</div>
</div>
</@layout>
4.新增Controller层请求
@RequestMapping("/search")
public String search(String q) {
req.setAttribute("q", q);
req.setAttribute("pageData", null);
return "search";
}
由于redis和es都包含netty相关的包,版本不匹配会存在包冲突,可在启动类加入相关语句解决。 测试:
5.设计es索引,并添加PostRepository
有了索引之后,es就可以根据索引进行搜索,title是模糊匹配,其他的authorName、categoryName是完全匹配
@Data
@Document(indexName = "post", type = "post", createIndex = true)
public class PostDocment implements Serializable {
@Id
private Long id;
@Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
private String title;
@Field(type = FieldType.Long)
private Long authorId;
@Field(type = FieldType.Keyword)
private String authorName;
private String authorAvatar;
private Long categoryId;
@Field(type = FieldType.Keyword)
private String categoryName;
private Integer level;
private Boolean recomment;
private Integer commentCount;
private Integer viewCount;
@Field(type = FieldType.Date)
private Date created;
}
PostRepository继承ElasticsearchRepository之后就可以进行jpa规范相关的操作,进行增删改查、控制page与Docment
@Repository
public interface PostRepository extends ElasticsearchRepository<PostDocment, Long> {
}
6.kibana可视化es
事先安装好kibana,绑定es,并启动kibana。 然后启动项目,发现es多出了我们刚才创建的post索引,以及相关的属性
7.设计搜索功能
1.请求层 2.定义接口
public interface SearchService {
IPage search(Page page, String keyword);
}
3.实现类
- 首先将mybatis的page转成jpa规范的page
- 然后通过es搜索得到文档记录
- 最后将记录转化为mybatis的页记录
@Override
public IPage search(Page page, String keyword) {
Long current = page.getCurrent() - 1;
Long size = page.getSize();
Pageable pageable = PageRequest.of(current.intValue(), size.intValue());
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword,
"title", "authorName", "categoryName");
org.springframework.data.domain.Page<PostDocment> docments = postRepository.search(multiMatchQueryBuilder, pageable);
IPage pageData = new Page(page.getCurrent(), page.getSize(), docments.getTotalElements());
pageData.setRecords(docments.getContent());
return pageData;
}
8.同步文章数据到es
要在es搜索,首先es要有数据,所以我们在页面设计一个按钮,按下按钮,便会将mybatis查到的所有文章信息同步到es。 1.请求层 预计最多存储1千万条记录,用一个循环进行同步,没查完一页就同步一次,当一页没有1万条记录时,说明是最后一页,终止查询。
@ResponseBody
@PostMapping("/initEsData")
public Result initEsData() {
int size = 10000;
Page page = new Page();
page.setSize(size);
long total = 0;
for (int i = 1; i < 1000; i ++) {
page.setCurrent(i);
IPage<PostVo> paging = postService.paging(page, null, null, null, null, null);
int num = searchService.initEsData(paging.getRecords());
total += num;
if(paging.getRecords().size() < size) {
break;
}
}
return Result.success("ES索引初始化成功,共 " + total + " 条记录!", null);
}
2.接口 3.实现类 利用modelMapper将查到的vo记录,映射成Docment,存到es。
@Override
public int initEsData(List<PostVo> records) {
if(records == null || records.isEmpty()) {
return 0;
}
List<PostDocment> documents = new ArrayList<>();
for(PostVo vo : records) {
PostDocment postDocment = modelMapper.map(vo, PostDocment.class);
documents.add(postDocment);
}
postRepository.saveAll(documents);
return documents.size();
}
4.配置modelMapper 5.修改set.ftl 在管理员的set界面下新增“同步ES”栏,以及“同步ES数据”按钮 6.测试: 管理员设置页面多出“同步ES”栏目 点击“同步ES数据”按钮: 查看kibana,出现对应文档:
9.搜索测试
搜索“一起学”: 搜索“MarkerHub”:
参考资料:
https://github.com/MarkerHub/eblog
|