背景
目前公司的一个老项目,查询贼慢,需要想办法提升一下速度,于是就想到了ES,现在尝试一下将ES整合到项目中来提升检索效率。
ES是基于倒排索引实现的,倒排索引中一个表相当于一个索引,表中的每条记录都是一个文档(JSON数据),系统会先对字段数据进行分词,然后给词条建立索引,并映射到文档id。在查询的时候根据输入进行分词,然后根据词条走索引查询文档id,再根据文档id查询文档并放入结果集,最后将结果集返回。
一般来说,ES算是难度较高的一个技术栈,需要中高级才能熟练驾驭,新手入门比较难,因而我选中了对新手更加友好的easy-es,其在ES的基础上做了封装,使得使用起来和MybatisPlus很像,简单上手。
开始使用easy-es之前,建议先看一下避坑指南
Elastic Search下载
ES官网
按照官方推荐下载7.x的ES,我下载了和官方demo一样的7.14.0版本。
输入7.14.0搜索该版本并下载
下载完成之后解压,并去到bin目录,双击elasticsearch.bat文件启动elasticsearch。
Springboot整合ES
- 打开Springboot项目(或创建一个Springboot项目),先全局搜索elastic,看看项目是否已经引入过ES,如果有,需要去掉或者更改版本为7.14.0。印象中不同版本的Springboot默认引入的一定版本的ES。
- 在POM文件引入依赖
<!-- 引入easy-es最新版本的依赖--><dependency><groupId>org.dromara.easy-es</groupId><artifactId>easy-es-boot-starter</artifactId><!--这里Latest Version是指最新版本的依赖,比如2.0.0,可以通过下面的图片获取--><version>Latest Version</version></dependency><!-- 排除springboot中内置的es依赖,以防和easy-es中的依赖冲突--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId></exclusion><exclusion><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.14.0</version></dependency><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.14.0</version></dependency>
- YAML文件增加ES配置(更多配置可以在官网看)
easy-es:enable: true #默认为true,若为false则认为不启用本框架address: 127.0.0.1:9200 # es的连接地址,必须含端口 若为集群,则可以用逗号隔开 例如:127.0.0.1:9200,127.0.0.2:9200
# username: elastic #若无 则可省略此行配置。因为刚下载的ES默认不用账号密码登录,所以注掉
# password: WG7WVmuNMtM4GwNYkyWH #若无 则可省略此行配置
- 在启动类设置ES的mapper包扫描路径(一般应该设置成带*的通配格式,方便多模块项目的扫描。)同时注意,该mapper的包和mybatisplus的包不能是同一个,不然框架区分不开。
@EsMapperScan("org.jeecg.modules.test.esmapper")
@SpringBootApplication
public class JeecgSystemApplication extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(JeecgSystemApplication.class);}public static void main(String[] args) throws UnknownHostException {ConfigurableApplicationContext application = SpringApplication.run(JeecgSystemApplication.class, args);}
}
- 创建实体类(加上@IndexName注解)
package org.jeecg.modules.message.entity;import org.dromara.easyes.annotation.IndexField;
import org.dromara.easyes.annotation.IndexName;
import org.dromara.easyes.annotation.rely.Analyzer;
import org.dromara.easyes.annotation.rely.FieldType;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecg.common.system.base.entity.JeecgEntity;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;@Data
@IndexName
public class SysMessage{/** ID */@TableId(type = IdType.ASSIGN_ID)private java.lang.String id;/**推送内容*/private java.lang.String esContent;/**推送所需参数Json格式*/private java.lang.String esParam;/**接收人*/private java.lang.String esReceiver;/**推送失败原因*/private java.lang.String esResult;/**发送次数*/private java.lang.Integer esSendNum;/**推送状态 0未推送 1推送成功 2推送失败*/private java.lang.String esSendStatus;/**推送时间*/@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")private java.util.Date esSendTime;/**消息标题*/private java.lang.String esTitle;/**推送方式:1短信 2邮件 3微信*/private java.lang.String esType;/**备注*/private java.lang.String remark;/** 创建人 */private java.lang.String createBy;/** 创建时间 */@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private java.util.Date createTime;/** 更新人 */private java.lang.String updateBy;/** 更新时间 */@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private java.util.Date updateTime;
}
- 创建mapper类
package org.jeecg.modules.test.esmapper;import org.dromara.easyes.core.core.BaseEsMapper;
import org.jeecg.modules.message.entity.SysMessage;
public interface DocumentMapper extends BaseEsMapper<SysMessage> {}
- 编写测试类
@Resourceprivate DocumentMapper documentMapper;@GetMapping("/createIndex")@ApiOperation("创建索引")public Object createIndex(String a){Boolean index = documentMapper.createIndex();System.out.println(index);return index;}@GetMapping("/createDoc")@ApiOperation("创建文档")public Object createDoc(String a,String b){SysMessage sysMessage=new SysMessage();sysMessage.setEsContent(a);sysMessage.setEsTitle(b);sysMessage.setEsReceiver("系统管理员");sysMessage.setEsSendNum(10);Integer insert = documentMapper.insert(sysMessage);return insert;}@GetMapping("/updateDoc")@ApiOperation("updateDoc")public Object updateDoc(String a){LambdaEsUpdateWrapper<SysMessage> wrapper=new LambdaEsUpdateWrapper<>();wrapper.eq(SysMessage::getEsContent,a).set(SysMessage::getEsContent,"更改后的标题");Integer update = documentMapper.update(null, wrapper);return update;}@GetMapping("/getDoc")@ApiOperation("查询文档")public Object getDoc(String a){List<SysMessage> list = EsWrappers.lambdaChainQuery(documentMapper).like(SysMessage::getEsContent, a).list();return list;}
- 浏览器安装一个ES可视化插件。我安装的是es-client
添加连接
选中创建的连接,目前还没有索引。
- 测试
启动Springboot项目,调用createIndex接口,创建索引 。然后回到浏览器插件,点击刷新,可以看到创建了一个索引。
调用createDoc接口,创建一个文档记录
点击左侧的数据展示选项,右上角选中创建的索引,点击刷新,可以看到多了一条记录。
调用getDoc接口,查询记录,成功查出。
更新的语法和MybatisPlus的wrapper差不多。先用查询条件eq,in等去筛选要更新的记录,然后用set去设置新的值,然后调用update方法即可。(如下,通过“测试内容”找到记录,并将其的标题改成新的内容)
在浏览器刷新,可以看到数据更新了。
删除的语法比更新还简单,也是创建一个esupdatewrapper,用eq、in等筛选,然后调用delete方法就可以了,就不演示了。
总结
Springboot整合ES最大可能遇到的问题就是ES版本的问题,也就是依赖冲突。如果依赖冲突,在项目启动的时候会有一个ERROR日志提醒,看到了就想办法去掉原来带着的ES依赖或者更改依赖版本为7.14.0
关于ES的数据更新,就要去了解ES同步数据库相关的知识了。
想要了解easy-es的更多特性,建议去看easy-es的官网文档。