微服务篇-深入了解 Elasticsearch 基础概念、Elasticsearch 倒排索引、IK 分词器(拓展词典)

🔥博客主页: 【小扳_-CSDN博客】**
❤感谢大家点赞👍收藏⭐评论✍**

文章目录

[1.0 Elasticsearch 基本概述](#1.0 Elasticsearch 基本概述)

[1.1 Elasticsearch 安装](#1.1 Elasticsearch 安装)

[1.2 Kibana 安装](#1.2 Kibana 安装)

[2.0 Elasticsearch 倒排索引](#2.0 Elasticsearch 倒排索引)

[2.1 正向索引](#2.1 正向索引)

[2.2 倒排索引](#2.2 倒排索引)

[2.3 正向和倒排](#2.3 正向和倒排)

[3.0 Elasticsearch 基础概念](#3.0 Elasticsearch 基础概念)

[3.1 文档和字段](#3.1 文档和字段)

[3.2 索引和映射](#3.2 索引和映射)

[3.3 Mysql 和 Elasticsearch](#3.3 Mysql 和 Elasticsearch)

[4.0 IK 分词器](#4.0 IK 分词器)

[4.1 使用 IK 分词器](#4.1 使用 IK 分词器)

[4.2 拓展词典](#4.2 拓展词典)


1.0 Elasticsearch 基本概述

数据库模糊查询随着表数据量的增多,查询性能的下降会非常明显,而搜索引擎的性能则不

会随着数据增多而下降太多。目前仅 10 万不到的数据量差距就如此明显,如果数据量达到百万、

千万、甚至上亿级别,这个性能差距会非常夸张。

其次,功能单一数据库的模糊搜索功能单一,匹配条件非常苛刻,必须恰好包含用户搜索的

关键字。而在搜索引擎中,用户输入出现个别错字,或者用拼音搜索、同义词搜索都能正确匹配到

数据。

综上,在面临海量数据的搜索,或者有一些复杂搜索需求的时候,推荐使用专门的搜索引擎

来实现搜索功能。

目前全球的搜索引擎技术排名如下:

Elasticsearch 是一款非常强大的开源搜索引擎,支持的功能非常多。

Elasticsearch 的官方网站如下:

Elasticsearch:官方分布式搜索和分析引擎 | Elastic

Elasticsearch 是由 elastic 公司开发的一套搜索引擎技术,它是 elastic 技术栈中的一部分。

完整的技术栈包括:

1)Elasticsearch:用于数据存储、计算和搜索

2)Logstash/Beats:用于数据收集

3)Kibana:用于数据可视化

整套技术栈被称为 ELK,经常用来做日志收集、系统监控和状态分析等等,而整套技术栈的

核心就是用来存储、搜索、计算的 Elasticsearch 。

1.1 Elasticsearch 安装

通过下面的 Docker 命令即可安装单机版本的 Elasticsearch :

bash 复制代码
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

这里采用的是 elasticsearch 的 7.12.1 版本,由于 8 以上版本的 JavaAPI 变化很大,在企业

中应用并不广泛,企业中应用较多的还是 8 以下的版本。

安装完成后,访问 9200 端口,即可看到响应的 Elasticsearch 服务的基本信息:

1.2 Kibana 安装

Kibana 是 elastic 公司提供的用于操作 Elasticsearch 的可视化控制台。它的功能非常强

大,包括:

1)对 Elasticsearch 数据的搜索、展示。

2)对 Elasticsearch 数据的统计、聚合,并形成图形化报表、图形。

3)对 Elasticsearch 的集群状态监控。

4)它还提供了一个开发控制台(DevTools),在其中对 Elasticsearch 的 Restful 的 API

接口提供了语法提示。

通过下面的 Docker 命令,即可部署 Kibana:

bash 复制代码
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=net \
-p 5601:5601  \
kibana:7.12.1

安装完成后,直接访问 5601 端口,即可看到控制台页面:

点击 Explore on my own:

继续点击 Dev tools:

输入 "GET /" 之后点击开始按钮:

右边出现的内容与直接访问 Elasticsearch 的效果是一样的。

2.0 Elasticsearch 倒排索引

Elasticsearch 之所以有如此高性能的搜索表现,正是得益于底层的倒排索引技术。那么什么

是倒排索引呢?

倒排索引的概念是基于 MySQL 这样的正向索引而言的。

2.1 正向索引

例如有一张名为 tb_goods 的表:

其中的 id 字段已经创建了索引,由于索引底层采用了 B+ 树结构,因此根据 id 搜索的速度会

非常快。但是其他字段例如 title,只在叶子节点上存在。

因此要根据 title 搜索的时候只能遍历树中的每一个叶子节点,判断 title 数据是否符合要求。

比如用户的 SQL 语句为:

sql 复制代码
select * from tb_goods where title like '%手机%';

此时,即使给 title 加上了索引,按照这种模糊查询的方法,索引会失效,最终会进行全表查

询,效率相对来说是很差的。

搜索的大概流程如图:

综上,根据 id 精确匹配时,可以走索引,查询效率较高。而当搜索条件为模糊匹配时,由于

索引无法生效,导致从索引查询退化为全表扫描,效率很差。

因此,正向索引适合于根据索引字段的精确搜索,不适合基于部分词条的模糊匹配。

而倒排索引恰好解决的就是根据部分词条模糊匹配的问题。

2.2 倒排索引

倒排索引中有两个非常重要的概念:

1)文档(Document):用来搜索的数据,其中的每一条数据就是一个文档。例如一个网

页、一个商品信息。

2)词条(Term):对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词

语就是词条。例如:我是中国人,就可以分为:我、是、中国人、中国、国人这样的几个词条。

创建倒排索引是对正向索引的一种特殊处理和应用,流程如下:

1)将每一个文档的数据利用分词算法根据语义拆分,得到一个个词条。

2)创建表,每行数据包括词条、词条所在文档 id、位置等信息。

3)因为词条唯一性,可以给词条创建正向索引。

倒排索引的搜索流程如下(以搜索"华为手机"为例),如图:

具体流程:

首先,在新增数据的时候,已经将文档进行分词建立了分词表,不同的词条都是唯一的,每

一个词条都有对应的 ID 也就是文档的 ID 。

再接着用户来搜索 "华为手机" 的时候,也会进行分词处理,变成一个个词条,比如说:"华

为","手机" 。拆分开来之后,就会根据词条到词条表中进行搜索,因为根据词条搜索的过程中,

肯定不是全表扫描的查询方式,而是有索引的方式来搜索,也就是根据词条搜索的效率不低。

得到对应的 ID 之后,再继续根据 ID 索引来查询文档得到数据,这些数据肯定是有多条的,

因为拆分出来的词条都多条,再匹配过程中会有多余的数据。

虽然要先查询倒排索引,再查询倒排索引,但是无论是词条、还是文档 id 都建立了索引,查

询速度非常快!无需全表扫描。

2.3 正向和倒排

那么为什么一个叫做正向索引,一个叫做倒排索引呢?

1)正向索引是最传统的,根据 id 索引的方式。但根据词条查询时,必须先逐条获取每个文

档,然后判断文档中是否包含所需要的词条,是根据文档找词条的过程。

2)而倒排索引则相反,是先找到用户要搜索的词条,根据词条得到保护词条的文档的 id,然

后根据 id 获取文档。是根据词条找文档的过程。

那么两者方式的优缺点是什么呢?

1)正向索引:

优点:

可以给多个字段创建索引。

根据索引字段搜索、排序速度非常快。

缺点:

根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。

2)倒排索引:

优点:

根据词条搜索、模糊搜索时,速度非常快。
缺点:

只能给词条创建索引,而不是字段。

无法根据字段做排序。

3.0 Elasticsearch 基础概念

Elasticsearch 中有很多独有的概念,与 mysql 中略有差别,但也有相似之处。

3.1 文档和字段

Elasticsearch 是面向文档(Document)存储的,可以是数据库中的一条商品数据,一个订

单信息。文档数据会被序列化为 json 格式后存储在 Elasticsearch 中:

3.2 索引和映射

将类型相同的文档集中在一起管理,称为索引(Index)。

可以把索引当做是数据库中的表。

数据库的表会有约束信息,用来定义表的结构、字段的名称、类型等信息。因此,索引库中

就有映射(mapping),是索引中文档的字段约束信息,类似表的结构约束。

3.3 Mysql 和 Elasticsearch

mysql 与 Elasticsearch 的概念做一下对比:

两者各自有自己的擅长之处:

1)Mysql:擅长事务类型操作,可以确保数据的安全和一致性。

2)Elasticsearch:擅长海量数据的搜索、分析、计算。

因此在企业中,往往是两者结合使用:

1)对安全性要求较高的写操作,使用 mysql 实现。

2)对查询性能要求较高的搜索需求,使用 Elasticsearch 实现。

3)两者再基于某种方式,实现数据的同步,保证一致性。

关于数据同步:可以考虑采用 MQ 异步通知实现。

4.0 IK 分词器

Elasticsearch 的关键就是倒排索引,而倒排索引依赖于对文档内容的分词,而分词则需要高

效、精准的分词算法,IK 分词器就是这样一个中文分词算法。

方法一:

运行一个命令即可:

bash 复制代码
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 容器:

bash 复制代码
docker restart es

方法二:

需要把 IK 分词器上传至 elasticsearch 的插件挂载到了 /var/lib/docker/volumes/es-

plugins/_data 这个目录。

IK 分词器:

接着:

最后,重启 es 容器:

4.1 使用 IK 分词器

IK 分词器包含两种模式:

1)ik_smart:智能语义切分。

2)ik_max_word:最细粒度切分。

在 Kibana 的 DevTools 上来测试分词器,首先测试 Elasticsearch 官方提供的标准分词器:

javascript 复制代码
POST /_analyze
{
  "analyzer": "standard",
  "text": "我是小扳手"
}

输出结果:

可以看到,标准分词器智能 1 字 1 词条,无法正确对中文做分词。

再测试 IK 分词器:

javascript 复制代码
POST /_analyze
{
  "analyzer": "ik_smart",
  "text": "我是小扳手了"
}

输出结果:

可见使用了 IK 分词器之后,不再一词一分了,而是根据了具体的语义来拆分成一个个词条。

IK 分词器另一个分词器也是同样如此:

javascript 复制代码
POST /_analyze
{
  "analyzer": "ik_max_word",
  "text": "我是小扳手了"
}

输出结果:

4.2 拓展词典

随着互联网的发展,"造词运动"也越发的频繁。出现了很多新的词语,在原有的词汇列表中

并不存在。要想正确分词,IK 分词器的词库也需要不断的更新,IK 分词器提供了扩展词汇的功

能。

1)打开 IK 分词器 config 目录:

2)在 IKAnalyzer.cfg.xml 配置文件内容添加:

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 *** 添加扩展词典-->
        <entry key="ext_dict">ext.dic</entry>
</properties>

3)在 IK 分词器的 config 目录新建一个 ext.dic,可以参考 config 目录下复制一个配置文件进行

修改:

首先创建 ext.dic 文件:

接着在该文件中添加词条:

再接着重启 elasticsearch:

再继续分词,查看最终分词结果:

javascript 复制代码
POST /_analyze
{
  "analyzer": "ik_smart",
  "text": "我是小扳手了"
}

输出结果:

由于在分词库上加上了 "小扳手" 这个词条,那么在分词的时候,就会查询到词库有对应的词

条,那么就不会将 "小扳手" 这个词条进行拆分了。

相关推荐
风象南1 分钟前
SpringBoot 控制器的动态注册与卸载
java·spring boot·后端
我是一只代码狗27 分钟前
springboot中使用线程池
java·spring boot·后端
hello早上好40 分钟前
JDK 代理原理
java·spring boot·spring
PanZonghui1 小时前
Centos项目部署之运行SpringBoot打包后的jar文件
linux·spring boot
PanZonghui1 小时前
Centos项目部署之Java安装与配置
java·linux
沉着的码农1 小时前
【设计模式】基于责任链模式的参数校验
java·spring boot·分布式
zyxzyx6661 小时前
Flyway 介绍以及与 Spring Boot 集成指南
spring boot·笔记
Mr_Xuhhh1 小时前
信号与槽的总结
java·开发语言·数据库·c++·qt·系统架构
何苏三月2 小时前
SpringCloud系列 - Sentinel 服务保护(四)
spring·spring cloud·sentinel
纳兰青华2 小时前
bean注入的过程中,Property of ‘java.util.ArrayList‘ type cannot be injected by ‘List‘
java·开发语言·spring·list