1.基本术语:
集群:
集群中有多个节点,节点中有一个master节点,配置 cluster.name (同一个集群的标识)节点:
每一个运行的elasticserch实例称为节点主节点:
负责集群范围内所有的变更,如增、删节点或索引,配置node.master: true(允许的一个节点可以称为master节点)数据节点:
存储数据及其倒排索引,默认每一个节点都是数据节点,配置node.data: true协调节点:
node.master和node.data的属性均为false,不存储数据不参与竞选master,用来响应客户请求,均衡节点负载分片:
es就是利用分片来实现分布式的,分片是数据容器,文档被存储在分片内,分片又被分配在集群的各个节点上。当集群扩大或缩小时,es会自动在各个节点上迁移分片,以保证数据在各个节点上是均匀分配的。主分片和副本分片的数量决定了集群的健康程度,当集群中只有一个节点时,集群状态变为yelleow,存在着丢数据的可能主分片:
es中每一个文档都归属于一个主分片,主分片的个数决定集群文档的存储数量,索引在建立时需指定主分片的个数,且不能修改,默认有5个分片副本分片:
副本是主分片的拷贝,作为硬件故障时保护数据不丢失的备份,并为读操作提供搜索和数据返回功能,副本的数量可以任意修改
2.分片id计算原理:
shard = hash(routing) % number_of_primary_shards
routing是一个任意字符串,默认是es文档的_id字段,这个公式也就解释了为什么索引的主分片数只能在创建时定义且不能被修改
如果主分片数修改了,路由也就不生效了,数据就找不到了
3.elasticsearch写入数据原理:
-
思路:
当es的某个节点在收到客户端的文档写入请求时,该节点会根据文档的路由规则,计算出该文档对应的主分片,然后将写入请求转发到该文档对应的主分片中执行数据保存,当主分片保存成功,会并行将写入请求发送给所有副本分片,保证所有副本分片都有最新的数据
-
步骤:
- 1)将新的数据写入buff中,并将这一写入buffer的操作写入translog中,此时写入的数据还不能被搜索到
- 2)当buffer满了或间隔时间到,会将buffer中的数据刷到os cache,刷数据的同时会将数据写入translog中,然后清空buffer,当数据到达os cash表示数据可以被搜索到了
也可以调用api接口,手动将数据从buffer中刷到os cash中,注意translog会定时的写入磁盘中(默认5s),每隔一秒会将os cash 中的数据写入segment(默认每秒生成一个)
- 3)随着数据不断写入,translog不断变大,每30分钟或translog达到设定值,则执行一次fysnc操作,将segment中的数据写入磁盘中
- 4)segment每秒生成一个,即使没有数据写入,当查询请求到达分片时,分片会遍历segment获取数据,当segment数量较多时会影响查询效率,所以es会对segment进行合并,将大小相似的segment合并成一个新的segment,并删旧的segment
- 问题:
在执行2次fsync期间数据一直是在缓存中的,期间最长的间隔可能有30分钟,如果遇到硬件故障或断电,数据可能会丢失,所有es会每隔5s或一次写入请求完成,将缓存中的translog数据写入磁盘中,当遇到硬件故障时,重启系统时从translog中恢复数据
4.elasticsearch数据搜索原理:
-
数据查询阶段:
- 1)某个节点收到搜索请求,会广播请求到节点的每一个分片,每个分片(主分片或副本分片)会执行查询请求
2)当收到查询请求,每个分片会在本地创建一个优先级队列,如果客户端要求返回从from开始长度为size的结果集,那么每个分片会根据需求返回from+size的结果集,但分片仅会返回一个轻量级的结果集,包括文档id和排序相关信息
3)节点会将所有分片的结果集汇总,并进行全局排序,得到最终的查询结果集
-
数据取回阶段:
- 1)协调节点辨别出那个哪些document需要返回,并向相关分片发送GET请求
- 2)每个分片相应节点请求,根据需求返回完整的document
- 3)一旦所有的document都被返回,节点就将结果集返回给客户端
-
为什么搜索被分为2步?
- 避免数据传输带来的带宽和内存消耗问题
- 搜索类型:
-
query and fetch:
- 思路: 向个分片发起查询请求,各分片返回document元素文档及计算后的排名信息
- 优点: 搜索最快,只需要在各分片查询一次
- 缺点: 返回的数据量和排名都不准确,节点会收到N*分片数的结果集,各分片的打分标准都不一样
-
query then fetch:
- 思路:
分2步,先向各分片发起查询请求,各分片只返回包含文档id和打分信息
的数据,数据量是(from+size)*N
,由节点进行汇总全局排序(只重新排序,不打分
),标记出需要的文档,并根据标记向各分片发起get请求,由各分片返回完整的document信息- 优点: 查询数量准确
- 缺点: 性能一般,排名不一定准确,因为各个分片的打分标准不一样
-
DFS query and fetch
- 思路:
与query and fetch相比多了一步预查询,预先查询每个分片的词频和文档频率返回给节点,在各分片使用全局打分标准(重新打分)
- 优点: 排名准确,
- 缺点: 性能一般,返回数量不准确,返回的数量可能是(from+size)*N
-
DFS query then fetch
- 思路:
1)预先查询每个分片词频和文档频率
2)将查询发送到每个分片
3)查找所有匹配的文档,并使用从预查询计算的全局术语/文档频率计算分数
4)构建结果的优先级队列(排序,from/to的分页等)
5)将结果的元数据返回给请求节点。注意:实际文件尚未发送,只是分数
6)来自所有分片的分数在请求节点上合并和排序,根据查询条件选择文档
7)从它们所在的各个分片中检索实际的文档,将结果返回给客户端- 优点: 查询数量准确、排名准确
- 缺点: 性能最差
6.更新和删除文档:
- Elasticsearch的索引是不允许被修改,所以更新和删除操作,不允许直接在原索引上进行
- 删除:
磁盘上的每一个segment文件都会维持一个del文件,用来记录被删除的文件。当用户请求删除一个文件时,并不是真的删除这个文件,而是在del文件中标记该文件已经被删除
,因此该文档仍可以被检索到
,只是在返回检索结果时把它过滤掉
。只有在每次启动segment合并时,才会真正将del中标记的文档删除- 更新:
更新文档,会先查找原文档,获取版本号,并将修改后的文档写入内存,此过程与写入一个新的文档的过程相同。同时旧版文档会被标记为删
,同理,旧的文档也可以被搜索到,只是在返回结果时被过滤掉
7.solr与elasticsearch的区别:
- 文件格式
solr支持多文件格式(json、xml、html),elasticsearch只支持json格式- 查询效率
Solr 查询快,但更新索引时慢(即插入删除慢),用于电商等查询多的应用
ES建立索引快(即查询慢),即实时性查询快,用于facebook新浪等搜索- 架构
solr利用zookeeper进行分布式管理,而elasticsearch天生就是分布式的
7.倒排索引:
示例
正排索引:
通过key找value
倒排索引:
通过value找key
倒排索引内容:
文档列表、文档数量、词条在每个文档中出现的次数、出现的位置、每个文档的长度、所有文档的平均长
单词(term)
:一段文本经过分析器分析后,会解析为一串单词
单词索引(index)
:为单词建立索引
单词字典(tertremm dictionary)
:为Term的集合
倒排列表(posting list)
:记录了出现过某个单词的所有文档的文档列表及单词在该文档中出现的位置信息
类比现代汉语词典的话,那么Term就相当于词语,Term Dictionary相当于汉语词典本身,Term Index相当于词典的目录索引
上图例子是一个包含 “A”, “to”, “tea”, “ted”的trie(单词查找树)树。这棵树不会包含所有的term,它包含的是term的一些前缀。通过term index可以快速地定位到term dictionary的某个offset,然后从这个位置再往后顺序查找。再加上一些压缩技术( Lucene Finite State Transducers),Term index的尺寸可以只有所有term的尺寸的几十分之一,使得用内存缓存整个term index变成可能