ElasticSearch 基本原理
1. 搜索原理
1. ElasticSearch
简介
ElasticSearch
就是独立的网络上的一个或一组进程节点- 它能对外提供搜索服务(使用
http
或transport
协议),自从ElasticSearch 7.0
开始,主要支持http
协议 ElaticSearch
对内其实就是一个数据库
2. 分词
搜索是以词为单位做最基本单位的搜索单元,依赖分词器构建分词,用分词器倒排索引。
3. 倒排索引
-
正向索引
对文档中的所有分词进行遍历,获取与 keyword 中分词相同的词,命中一次,这种索引方法需要对每一个文档都进行遍历,性能上不是很好。
-
倒排索引
对文档的分词结果进行遍历,如果 keyword 命中该分词,那么通过该分词便可以找到所有含有这个分词的文档,性能相对较高。 倒排索引包含两个部分: - 单词词典(Term Dictionary),记录所有文档的单词,记录单词倒排列表的关联关系。单词词典一般比较大,可以通过B+树或者哈希拉链法实现,以满足高性能的插入与查询 - 倒排列表(Posting List),记录了单词对应的文档结合,由倒排索引组成。倒排索引项包含:文档ID,词频TF(该单词在文档中出现的次数,用于相关性评分),位置(Position,单词在文档中分词的位置。用于语句搜索(phrase query)),偏移(Offset,记录单词的开始结束位置,实现高亮显示) Elasticsearch的倒排索引:Elasticsearch的JSON文档中的每个字段,都有自己的倒排索引。但是可以对某些字段不做索引,优点是可以节省存储空间,缺点是该字段将无法被搜索。
4. TF/IDF
打分
TF:词频,这个 document 文档包含了多少个这个词,包含越多表名越相关
DF:文档频率,包含该词的文档总数目
IDF:DF 取反
单词 ID | 单词 | 文档频率 | 倒排列表(DocID;TF;<POS>) |
---|---|---|---|
1 | 谷歌 | 5 | (1;1;<1>),(2;1;<1>),(3;2;<1;6>),(4;1;<1>),(5;1;<1>) |
2 | 地图 | 5 | (1;1;<2>),(2;1;<2>),(3;1;<2>),(4;1;<2>),(5;1;<2>) |
3 | 之父 | 4 | (1;1;<3>),(2;1;<3>),(4;1;<3>),(5;1;<3>) |
4 | 跳槽 | 2 | (1;1;<4>),(4;1;<4>) |
5 | 5 | (1;1;<5>),(2;1;<5>),(3;1;<8>),(4;1;<5>),(5;1;<8>) | |
6 | 加盟 | 3 | (2;1;<4>),(3;1;<7>),(5;1;<5>) |
7 | 创始人 | 1 | (3;1;<3>) |
8 | 拉斯 | 2 | (3;1;<4>),(5;1;<4>) |
9 | 离开 | 1 | (3;1;<5>) |
10 | 与 | 1 | (4;1;<6>) |
2. 名词定义
在ElasticSearch
中的索引=数据库,类型=表,文档=行数据
,在ElasticSearch 7.0
逐步的废弃了类型这样一个定义,也就是说索引和类型统称为索引,也就是说在ElasticSearch 7.0
中只有索引和文档的定义,其中索引相当于索引和类型。
与关系型数据库的名词之间的类比:
关系型数据库 | ElasticSearch |
---|---|
Database | Index |
Table | Type |
Row | Document |
Column | Field |
Schema | Mapping |
Index | Everything is indexed |
SQL | Query DSL |
SELECT * FROM table … | GET http://… |
UPDATE table SET … | PUT http://… |
3. 分布式原理
Elasticsearch的分布式架构的好处:
- 存储的水平扩容
- 提高系统的可用性,部分节点停止服务,整个集群的服务不受影响
Elasticsearch的分布式架构:
- 不同的集群通过不同的名字来区分,默认名字为“elasticsearch”
- 通过配置文件修改,或者在命令行中-E cluster.name=Yankee进行设定
- 一个集群可以有一个或者多个节点
节点:
- 节点是一个Elasticsearch实例,本质上就是一个JAVA进程,一台机器上可以运行多个Elasticsearch进程,但是生产环境一般建议一台机器上只运行一个Elasticsearch实例
- 每一个节点都有名字,通过配置文件配置,或者启动时候-E node.name=node1指定
- 每一个节点在启动之后,会分配一个UID,保存在data目录下
Master-eligible Nodes和Master Node:
- 每个节点启动后,默认就是一个Master eligible节点,可以设置node.master:false禁止
- Master-eligible节点可以参加选主流程,称为Master节点
- 当第一个节点启动时,它会将自己选举成Master节点
- 每个节点上都保存了集群的状态,只有Master节点才能修改集群的状态信息
- 集群状态(Cluster State),维护了一个集群中,必要的信息(所有的节点信息,所有的索引和其相关的Mapping和Settings信息,分片的路由信息)
- 任意节点都能修改信息会导致数据的不一致性
Data Node和Coordinating Node:
- Data Node:可以保存数据的节点,叫做Data Node。负责保存分片数据。在数据扩展上起到了至关重要的作用
- Coordinating Node:负责接受Client的请求,将请求分发到合适的节点,最终把结果汇总在一起;每个节点默认都起到了Coordinating Node的职责
其他的节点类型:
- Hot & Warm Node:不同硬件配置的Data Node,用来实现Hot & Warm架构,减低集群部署的成本。其中Hot存放新数据,硬件配置比较高;Warm存放旧数据,硬件配置比较低
- Machine Learning Node:负责跑机器学习的Job,用来做异常检测
- Tribe Node:(5.3开始使用Cross Cluster Search)Tribe Node连接到不同的Elasticsearch集群,并且支持将这些集群当成一个单独的集群处理
1. 分片
ElasticSearch 中默认的主分片(num_of_shards)数量为 5,默认的副本(num_of_replicas)个数为 1
主分片数量一旦设置就不会再改变,但是副本个数可以进行改变
在单集群节点中,如果主分片数量为 1,副本也为 1,那么此时单节点集群的 health 为 yellow,因为单节点必然会存在副本和主分片在同一个节点,会导致该索引的 health 为 yellow。此时可以修改集群的副本个数为 0,则索引和集群的状态会变回到 green 状态。
主分片(Primary Shard),用以解决数据水平扩展的问题。通过主分片,可以将数据分布到集群内的所有节点之上:
- 一个分片是一个运行的Lucene的实例
- 主分片数在索引创建时指定,后续不允许修改,除非Reindex
副本(Replica Shard),用以解决数据高可用的问题。分片是主分片的拷贝:
- 副本分片数,可以动态调整
- 增加副本数,还可以在一定程序上提高服务的可用性(读取的吞吐)
分片的设定:
- 分片数设置过小:导致后续无法增加节点实现水平扩展;单个分片的数据量太大,导致数据重新分配耗时
- 分片数设置过大,7.0开始,默认主分片设置成1,解决了over-sharding的问题:影响搜索结果的相关性打分,影响统计结果的准确性;单个节点上过多的分片,会导致资源浪费,同时也会影响性能
2. 主从
# 单节点集群
单节点集群中,如果创建了一个索引,默认会拥有副本,此时由于副本和主分片在一个节点,则单节点集群的 health 为 yellow。创建索引时,根据未来的扩展性,将主分片个数设置为合适的个数,但也不能太多,因为数量太多,如果数据量没有达到对应的瓶颈,在进行数据聚合时,就需要遍历所有的主分片,才能得到结果。
# 双节点集群
当新增一个集群节点的,此时节点集群会将副本全部存放到新增的节点上,此时如果索引的副本个数为 1 时,那么此时集群的状态会变成 green。
# 三节点集群
当继续新增一个集群节点时,此时节点集群会使用负载均衡,将某个索引的主分片会迁移到新增的节点上,会将部分的副本也迁移到新增的节点上
# 三台节点构成 es 集群
# 副本个数为 2 时
此时 es 集群会将副本个数分别存放于另外两个节点之上,这两个节点中并没有改索引的主分片,此时主从分离,读写也分离。es 集群其实是一个对称的结构,es 集群的 master 用来管理所有负载的一个核心节点,也就是说如果要进行写操作,如果要写的索引的主分片就在 master 上,那么就可以直接进行写请求;如果写的索引在另一个节点上,那么 master 会将这个写请求进行转发,转发到要写的主分片所在的节点,由该节点进行写请求。
# 当关掉此时的 master 节点时
此时 es 集群会进行选举,选举一个新的 master 节点,会比较剩余的节点中的 metadata 是最新的,就会通过 paxos 方式从具备竞争主节点能力的机器中竞选主节点。此时被关掉的 master 上存在的主分片会均匀的分布到剩余的集群节点上,此时由于副本个数为 2,所以集群的状态又会变成 yellow,但是集群对外响应服务的能力还是有的。
# 三台节点构成 es 集群,并且状态为 green
# PUT 请求
当有操作请求集群进行新建索引操作时,无论请求的是 es 集群的那个节点,都会将该请求转发到 master 节点,因为只有 master 节点知道所有的 metadata 存储的位置,此时 master 会对进行写请求的操作进行识别,如果写请求的 documenId 识别是在 master 节点上,那么由 master 节点进行写操作,如果在 node3 上,就会将该写请求进行转发,转发到 node3,由 node3 完成写请求。写操作完成之后,node3 会异步的将数据改动同步回其对应的副本。
# GET 请求
进行读请求时,master 会进行一次路由计算,计算出该读请求属于 R0 副本的操作,假设 master 节点上也存在 R0 副本,假设上一次的操作是在 master 节点上进行,那么 es 集群会根据负载均衡,将该读请求转发到另一个存在 R0 副本的节点上。如果读请求第一次命中在别的节点上,但是由于是读请求,可以由每个节点进行路由操作。
# 总结
也就是说,master 节点只路由读请求,所有的写请求可以由其命中的节点进行处理,此时整个 es 集群就做到了负载均衡和读写分离。
3. 配置节点类型
开发环境中一个节点可以承担多种角色
生产环境中,应该设置单一的角色的节点(dedicated node)
节点类型 | 配置参数 | 默认值 |
---|---|---|
master eligible | node.master | true |
data | node.data | true |
ingest | node.ingest | true |
coordinating only | 无 | 每个节点默认都是coordinating节点。设置其他类型全部为false |
machine learning | node.ml | true(需要enable x-pack) |