博客项目学习笔记二十五:搜索引擎开发

博客项目目录: 请戳这里

准备

需求:用户登录后,点开搜索框,输入搜索内容,回车之后,就会跳转到对应的搜索页面
博客项目学习笔记二十五:搜索引擎开发_第1张图片
博客项目学习笔记二十五:搜索引擎开发_第2张图片
基本思路:

首先将所有的文章信息查询出来,同步到elasticsearch中,然后通过es进行搜索,得到对应的文档,之后转化成MyBatis的page信息,显示在前端页面

1.添加依赖包,修改yml配置

  • es相关依赖用于整合elasticsearch,项目启动时,需要事先安装es,并开启es服务
  • modelmapper用于将MyBatis查询到的记录转化为es的Docment
	   
       <dependency>
           <groupId>org.springframework.bootgroupId>
           <artifactId>spring-boot-starter-data-elasticsearchartifactId>
           <version>2.1.1.RELEASEversion>
       dependency>

       <dependency>
           <groupId>org.modelmappergroupId>
           <artifactId>modelmapperartifactId>
           <version>1.1.0version>
       dependency>

一般来说,es的9200端口用于查询,9300端口用于连接程序
博客项目学习笔记二十五:搜索引擎开发_第3张图片

2.修改index.js

原来搜索框输入内容,回车之后,跳到固定的某一个网址进行搜索,现在修改之后,跳到我们写的接口进行搜索
博客项目学习笔记二十五:搜索引擎开发_第4张图片

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张图片
测试:

博客项目学习笔记二十五:搜索引擎开发_第6张图片

5.设计es索引,并添加PostRepository

有了索引之后,es就可以根据索引进行搜索,title是模糊匹配,其他的authorName、categoryName是完全匹配

@Data
@Document(indexName = "post", type = "post", createIndex = true)
public class PostDocment implements Serializable {

    @Id
    private Long id;

    // ik分词器
    @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> {

    // 符合jpa命名规范的接口

}

6.kibana可视化es

事先安装好kibana,绑定es,并启动kibana。
然后启动项目,发现es多出了我们刚才创建的post索引,以及相关的属性
博客项目学习笔记二十五:搜索引擎开发_第7张图片

7.设计搜索功能

1.请求层
博客项目学习笔记二十五:搜索引擎开发_第8张图片
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) {
        // 分页信息 mybatis plus的page 转成 jpa的page
        Long current = page.getCurrent() - 1;
        Long size = page.getSize();
        Pageable pageable = PageRequest.of(current.intValue(), size.intValue());

        // 搜索es得到pageData
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword,
                "title", "authorName", "categoryName");

        org.springframework.data.domain.Page<PostDocment> docments = postRepository.search(multiMatchQueryBuilder, pageable);

        // 结果信息 jpa的pageData转成mybatis plus的pageData
        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;

            // 当一页查不出10000条的时候,说明是最后一页了
            if(paging.getRecords().size() < size) {
                break;
            }
        }

        return Result.success("ES索引初始化成功,共 " + total + " 条记录!", null);
    }

2.接口
博客项目学习笔记二十五:搜索引擎开发_第9张图片
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
博客项目学习笔记二十五:搜索引擎开发_第10张图片
5.修改set.ftl
在管理员的set界面下新增“同步ES”栏,以及“同步ES数据”按钮
在这里插入图片描述
博客项目学习笔记二十五:搜索引擎开发_第11张图片
6.测试:
管理员设置页面多出“同步ES”栏目
博客项目学习笔记二十五:搜索引擎开发_第12张图片
点击“同步ES数据”按钮:
博客项目学习笔记二十五:搜索引擎开发_第13张图片
查看kibana,出现对应文档:
博客项目学习笔记二十五:搜索引擎开发_第14张图片

9.搜索测试

搜索“一起学”:
博客项目学习笔记二十五:搜索引擎开发_第15张图片
搜索“MarkerHub”:
博客项目学习笔记二十五:搜索引擎开发_第16张图片

参考资料:

https://github.com/MarkerHub/eblog

你可能感兴趣的:(项目实战,java,搜索引擎,mysql,elasticsearch,spring)