前言
最近在开发一个分布式的博客项目,目前正在开发检索功能,因为做这个项目本意也是自己从0的开始学习微服务开发,想尽量多的应用一些技术栈,所以,系统的检索部分,就整合了ELasticSearch全文检索来做,本文分享一下,ELasticSearch从安装、到SpringBoot整合的全过程。
安装
我选择了在linux系统安装Es,系统版本是Centos7,使用Vagrant快速创建,感兴趣的朋友可参考 Vagrant + VirtualBox 快速搭建本地centos7环境。
手动安装
下载安装包
我们先要下载安装包,主要有下面这些:
- Jdk:Es的运行环境
- ElasticSearch安装包:全文检索服务
- Kibana:Es的可视化工具
- ik分词器:第三方分词器
经过简单调研,Es版本我选择了7.17.18,因为7.x已经挺久了,资料肯定更全面,再加上我是自学的目的,所以选择了这个版本。还有一个原因,ik分词器,在7.x最后支持的版本好像就是7.17.18(我在github没看到有7.17.22的版本)。
Kibana是Es的可视化工具,主要用于我们开发过程中,查看数据使用。
jdk我还是用的1.8,这个版本在运行es7.x时可能会提示过时,不过还能用。
下载地址:
- jdk:www.oracle.com/java/techno…
- es:www.elastic.co/cn/download…
- kibana:www.elastic.co/cn/download…
- ik分词器:github.com/infinilabs/…
安装Es
将elasticsearch-7.17.18-linux-x86_64.tar.gz拷贝到/opt目录下解压
tar -zxvf elasticsearch-7.17.18-linux-x86_64.tar.gz -C /opt
然后需要进行一些配置
配置1
执行下面命令
sudo vi /etc/security/limits.conf
添加如下配置:
{启动es的用户名} hard nproc 4096
{启动es的用户名} soft nproc 4096
{启动es的用户名} hard nofile 65535
{启动es的用户名} soft nofile 65535
再执行下面命令
sudo systemctl daemon-reload
配置2
执行下面命令:
sudo vi /etc/sysctl.conf
添加如下配置:
vm.max_map_count=655360
执行命令:
sudo sysctl -p
配置3
执行命令
chmod -R 777 /opt
配置4:es配置文件
修改es的配置文件:主要是设置了一些节点名称、开放任意ip访问、关闭geoip库等。
sudo vi /opt/elasticsearch-7.17.18/config/elasticsearch.yml
添加如下配置:
cluster.name: my-cluster
node.name: single-node
cluster.initial_master_nodes: ["single-node"]
ingest.geoip.downloader.enabled: false
network.host: 0.0.0.0
接下来就可以启动Es了(不要用root用户,会启动失败。用上面配置的启动es的用户名)
nohup /opt/elasticsearch-7.17.18/bin/elasticsearch &
启动后可以通过9200端口访问
安装Kibana
先解压
tar -zxvf kibana-7.17.18-linux-x86_64.tar.gz -C /opt
修改配置文件
sudo vi /opt/kibana-7.17.18/config/kibana.yml
将server.host这个配置项的值改为0.0.0.0
启动
nohup /opt/kibana-7.17.18/bin/kibana &
启动后可以通过5601端口访问
安装ik分词器
将下载好的elasticsearch-analysis-ik-7.17.18.zip
拷贝到/opt/elasticsearch-7.17.18/plugins
下解压即可,然后重启es
可以在/opt/elasticsearch-7.17.18/bin
目录下,执行下面命令 查看已安装的插件
elasricsearch-plugin list
docker安装
配置 yum 源
备份原文件
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
下载新文件
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
没有 wget 的 可以去网址下载之后 拷贝到服务器上 修改名称
运行命令
yum clean all
yum makecache
安装必须依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
设置 docker 源
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
安装 docker 和 docker compose
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
设置开启自启
sudo systemctl enable docker
配置镜像
在 /etc/docker/daemon.json 中配置镜像站
{
"registry-mirrors": [
"https://dockerpull.pw"
]
}
刷新
sudo systemctl daemon-reload && sudo systemctl restart docker
直接根据项目中的docker-compose文件安装
docker compose -f docker-compose.env.yml up -d
SpringBoot整合
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
导入这个starter,基本不用进行什么配置,只需要在yml配置es地址即可
spring:
elasticsearch:
uris: 192.168.56.20:9200
在需要操作Es的地方,注入RestHighLevelClient即可,通过这个对象来操作es。
@Autowired
private RestHighLevelClient client;
业务应用
简单介绍一下 我的项目中目前对es的应用:
项目中创建一个blog-search模块,来处理全文检索相关的请求。用户在发布文章时,在文章保存接口中,通过openFeign
远程调用blog-search,将组装好的文章信息,上传到es:
检索页面如下:
代码如下:
//调用检索服务,将博客检索信息上传到es
BlogDocument doc = baseMapper.getBlogDocumentByBlogId(blog.getUid());
searchFeignService.publish(doc);
blog-search中,上传部分:
@RestController
@RequestMapping("/publish")
public class PublishController {
@Autowired
private RestHighLevelClient client;
/**
* 根据传入的doc对象,上传文章数据到es
*
* @param doc
* @return
*/
@PostMapping
public Result publish(@RequestBody BlogDocument doc) {
IndexRequest indexRequest = new IndexRequest("blog_list");
indexRequest.id(doc.getUid());
indexRequest.source(JSONUtil.toJsonStr(doc), XContentType.JSON);
try {
IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
return Result.success("文章上传到es成功!");
} catch (Exception e) {
return Result.error("文章上传到es失败!" + e.getMessage());
}
}
}
用户在系统中检索时,就从es查询数据:
@Service("es")
public class EsSearchServiceImpl implements SearchService {
@Autowired
private RestHighLevelClient client;
/**
* 根据传入的关键字以及分页参数,检索数据 封装为SearchVo并返回
*
* @param keyword
* @param page
* @return
*/
@Override
public SearchVo search(String keyword, Long page) {
if (page == null) page = 1L;
page = (page - 1L) * 10L;
SearchRequest searchRequest = new SearchRequest("blog_list");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//设置检索参数
if (StrUtil.isNotBlank(keyword)) {
searchSourceBuilder.query(QueryBuilders.matchQuery("title", keyword));
//设置检索关键字高亮
HighlightBuilder builder = new HighlightBuilder();
builder.field("title");
builder.preTags("<span style='color:red'>");
builder.postTags("</span>");
searchSourceBuilder.highlighter(builder);
}
//设置分页参数
searchSourceBuilder.from(page.intValue());
searchSourceBuilder.size(10);
searchRequest.source(searchSourceBuilder);
try {
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchVo vo = new SearchVo();
if (hits.getHits() != null) {
vo.setTotal(hits.getTotalHits().value);
List<BlogDocument> list = Arrays.stream(hits.getHits())
.map(hit -> {
BlogDocument blogDocument = JSONUtil.toBean(hit.getSourceAsString(), BlogDocument.class);
//处理关键字高亮
HighlightField title = hit.getHighlightFields().get("title");
blogDocument.setTitle(title.getFragments()[0].toString());
return blogDocument;
}).collect(Collectors.toList());
vo.setList(list);
}
return vo;
} catch (Exception e) {
return null;
}
}
}
有一个注意事项:我们博客文章,可能用自定义的ik分词器更好,用es默认分词器可能一些常见的词识别不出来。所以要在创建es中的索引时,指定分词器类型,一般ik_smart就够用了。
在kibana的Dev Tools执行下面指令
PUT /blog_list
{
"settings": {
"analysis": {
"analyzer": {
"ik_smart": {
"type": "ik_smart"
}
}
}
}
}
总结
以上,就是我在自己的分布式项目中,对于Es的简单应用了。希望可以帮到你,谢谢