一、初识ES及其下载安装
1.1 什么是ES
Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎,同时是可扩展的数据存储和矢量数据库,能够应对日益增多的各种用例。作为 Elastic Stack 的核心,Elasticsearch 能够集中存储您的数据,实现闪电般的搜索速度、精细的相关性调整以及强大的分析能力,并且能够轻松地进行规模扩展。
简单的讲,ES就是为了实现如京东、淘宝、百度等网站的多关键词全文检索功能,用户输入多个关键词,ES可以根据关键词进行全文检索,展示给用户包含该关键词的所有搜索结果,提高用户体验。
1.2 下载与安装
Elasticsearch是由elastic公司开发的一套搜索引擎技术,它是elastic技术栈中的一部分。完整的技术栈包括:
- Elastic Search:用于数据存储、计算和搜索
- Logstash/Beats:用于数据收集
- Kibana:用于数据可视化
其中Elastic Search与Kibana是我们主要使用的技术,接下来的下载与安装也主要介绍这两项技术,微服务中间件的使用大多布设于服务器,因此以下技术也基于Linux服务器介绍
前置环境要求
// 不同环境以及依赖版本可能会存在冲突,尽量保持版本一致
- JDK11
- Docker
- net网络环境(docker network create net)
1.2.1 Elastic Search下载与安装
- 首先需要拉取docker提供的ES与Kibana镜像或加载本地镜像
# 拉取远端ES
docker pull elasticsearch:7.12.1
# 加载本地ES
docker load -i elasticsearch.tar
1.2.2 Kibana下载与安装
Kibana是elastic公司提供的用于操作Elasticsearch的可视化控制台。它的功能非常强大,包括:
- 对Elasticsearch数据的搜索、展示
- 对Elasticsearch数据的统计、聚合,并形成图形化报表、图形
- 对Elasticsearch的集群状态监控
- 它还提供了一个开发控制台(DevTools),在其中对Elasticsearch的Restful的API接口提供了语法提示
为避免Kibana与ES产生冲突,要保证其与ES版本一致
# 拉取远端kibana
docker pull kibana:7.12.1
# 加载本地kibana
docker load -i kibana.tar
- 基于镜像创建容器并运行Elastic Search与Kibana
Kibana运行需要Elastic Search启动执行完毕,可以通过查看日志观察ES是否启动成功
运行ES:
docker run -d \
--name es \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \
--network net \
-p 9200:9200 \
-p 9300:9300 \
elasticsearch:7.12.1
查看日志:
docker logs -f es
运行Kibana:
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=net \
-p 5601:5601 \
kibana:7.12.1
查看日志:
docker logs -f kibana
- 安装完成后,直接访问5601端口,即可看到控制台页面:
- 选择
Explore on my own之后,进入主页面:
- 然后选中
Dev tools,进入开发工具页面:
1.3 倒排索引
Elastic Search之所以有如此高性能的搜索表现,正是得益于底层的倒排索引技术。
倒排索引的概念是基于MySQL这样的正向索引而言的。
假设有表:
| ID | title | price |
|---|---|---|
| 1 | 小米手机 | 3499 |
| 2 | 华为手机 | 4999 |
| 3 | 华为小米充电器 | 49 |
| 4 | 小米手环 | 49 |
| ... | ... | ... |
基于MySQL(正排索引)而言,ID依然创建了索引,基于ID查询速度会很快,但是商品搜索用户输入的必然是title,此时就需要进行模糊匹配,当用户输入多个关键字,如非有商品包含所有关键字,且格式也与用户输入相同,查询SQL就会查询不到结果,显然不符合我们的预期。
倒排索引中有两个非常重要的概念:
- 文档(
Document):用来搜索的数据,其中的每一条数据就是一个文档。例如一个网页、一个商品信息 - 词条(
Term):对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条。例如:我是中国人,就可以分为:我、是、中国人、中国、国人这样的几个词条
| 词条(索引) | 文档id |
|---|---|
| 小米 | 1,3,4 |
| 手机 | 1,2 |
| 华为 | 2,3 |
| 充电器 | 3 |
| 手环 | 4 |
倒排索引就可以基于词条将文档分类,然后将词条与上述表格进行匹配,得到查询结果的ID列表,然后再基于ID区查询数据库得到最终数据。
正向索引与倒排索引有各自的优缺点:
正向索引:
-
优点:
- 可以给多个字段创建索引
- 根据索引字段搜索、排序速度非常快
-
缺点:
- 根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。
倒排索引:
-
优点:
- 根据词条搜索、模糊搜索时,速度非常快
-
缺点:
- 只能给词条创建索引,而不是字段
- 无法根据字段做排序
ES官方提供的分词器会将中文的每一个字分为一个单独的词条,但是大多数情况下单独的字对用户来讲是没有意义的,所以我们需要引入中文分词器。
1.4 IK分词器
Elasticsearch的关键就是倒排索引,而倒排索引依赖于对文档内容的分词,而分词则需要高效、精准的分词算法,IK分词器就是这样一个中文分词算法。
- 在线安装
docker exec -it es ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip
安装完成后需要重启ES: docker restart es
- 离线安装
# 查看之前安装的ES的plugins数据卷目录
docker volume inspect es-plugins
# 得到Mountpoint这个属性对应的值就是挂载目录,将本地ik文件上传至本目录下
# 重启ES
docker restart es
IK分词器包含两种模式:
ik_smart:智能语义切分ik_max_word:最细粒度切分
二、索引库操作
Index就类似数据库表,Mapping映射就类似表的结构。我们要向es中存储数据,必须先创建Index和Mapping
2.1 Mapping映射属性
Mapping是对索引库中文档的约束,常见的Mapping属性包括:
-
type:字段数据类型,常见的简单类型有:- 字符串:
text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址) - 数值:
long、integer、short、byte、double、float、 - 布尔:
boolean - 日期:
date - 对象:
object
- 字符串:
-
index:是否创建索引,默认为true -
analyzer:使用哪种分词器 -
properties:该字段的子字段
2.2 索引库的CRUD
由于Elasticsearch采用的是Restful风格的API,因此其请求方式和路径相对都比较规范,而且请求参数也都采用JSON风格。
我们直接基于Kibana的DevTools来编写请求做测试,由于有语法提示,会非常方便。
2.2.1 创建索引库和映射
基本语法:
- 请求方式:
PUT - 请求路径:
/索引库名,可以自定义 - 请求参数:
mapping映射
PUT /索引库名称
{
"mappings": {
"properties": {
"字段名":{
"type": "text",
"analyzer": "ik_smart"
},
"字段名2":{
"type": "keyword",
"index": "false"
},
"字段名3":{
"properties": {
"子字段": {
"type": "keyword"
}
}
},
// ...略
}
}
}
2.2.2 查询索引库
基本语法:
- 请求方式:GET
- 请求路径:/索引库名
- 请求参数:无
GET /索引库名
2.2.3.修改索引库
倒排索引结构虽然不复杂,但是一旦数据结构改变(比如改变了分词器),就需要重新创建倒排索引,这简直是灾难。因此索引库一旦创建,无法修改mapping。
虽然无法修改mapping中已有的字段,但是却允许添加新的字段到mapping中,因为不会对倒排索引产生影响。因此修改索引库能做的就是向索引库中添加新字段,或者更新索引库的基础属性。
PUT /索引库名/_mapping
{
"properties": {
"新字段名":{
"type": "integer"
}
}
}
2.2.4 删除索引库
语法:
- 请求方式:DELETE
- 请求路径:/索引库名
- 请求参数:无
DELETE /索引库名
三、项目整合ES
3.1 导入依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
3.2 覆盖Spring Boot的默认ES版本
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<elasticsearch.version>7.12.1</elasticsearch.version>
</properties>
3.3 创建配置类将Client注册为Bean
@Configuration
public class ElasticSearchConfig {
/**
* es集群地址
*/
private static final String HOST = "http://服务器IP:9200";
/**
* 创建客户端
* @return RestHighLevelClient
*/
@Bean
public RestHighLevelClient restHighLevelClient() {
return new RestHighLevelClient(RestClient.builder(
HttpHost.create(HOST)
));
}
}
至此集成已经完成,已经可以开始测试使用了
四、MySQL与ES概念的对比
我们统一的把mysql与elasticsearch的概念做一下对比:
| MySQL | Elasticsearch | 说明 |
|---|---|---|
| Table | Index | 索引(index),就是文档的集合,类似数据库的表(table) |
| Row | Document | 文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式 |
| Column | Field | 字段(Field),就是JSON文档中的字段,类似数据库中的列(Column) |
| Schema | Mapping | Mapping(映射)是索引中文档的约束,例如字段类型约束。类似数据库的表结构(Schema) |
| SQL | DSL | DSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD |
是不是说,我们学习了elasticsearch就不再需要mysql了呢?
并不是如此,两者各自有自己的擅长之处:
-
Mysql:擅长事务类型操作,可以确保数据的安全和一致性
-
Elastic Search:擅长海量数据的搜索、分析、计算
因此在企业中,往往是两者结合使用:
-
对安全性要求较高的写操作,使用MySQL实现
-
对查询性能要求较高的搜索需求,使用Elastic Search实现
-
两者再基于某种方式,实现数据的同步,保证一致性