谈谈分词与倒排索引的原理
首先说分词是给检索用的。
英文:一个单词一个词,很简单。
I am a student
,词与词之间空格分隔。
中文:我是学生,就不能一个字一个字地分,我
-
是
-
学生。这是好分的。还有歧义的,使用户
放心,使用
-
户,使
-
用户。人很容易看出,机器就难多了。所以市面上有各种各样的分词器,
一个强调的效率一个强调的准确率。
倒排索引:倒排针对的是正排。
1.
正排就是我记得我电脑有个文档,讲了
ES
的常见问题总结。那么我就找到文档,从上往下翻
页,找到
ES
的部分。通过文档找文档内容。
2.
倒排:一个
txt
文件
ES
的常见问题
-> D:/
分布式问题总结
.doc
。
所以倒排就是文档内容找文档。当然内容不是全部的,否则也不需要找文档了,内容就是几个分词
而已。这里的
txt
就是搜索引擎。
说说分段存储的思想
Lucene
是著名的搜索开源软件,
ElasticSearch
和
Solr
底层用的都是它。
分段存储是
Lucene
的思想。
早期,都是一个整个文档建立一个大的倒排索引。简单,快速,但是问题随之而来。
文档有个很小的改动,整个索引需要重新建立,速度慢,成本高,为了提高速度,定期更新那么时
效性就差。
现在一个索引文件,拆分为多个子文件,每个子文件是段。修改的数据不影响的段不必做处理。
3
、谈谈你对段合并的策略思想的认识
分段的思想大大的提高了维护索引的效率。但是随之就有了新的问题。
每次新增数据就会新增加一个段,时间久了,一个文档对应的段非常多。段多了,也就影响检索性
能了。
检索过程:
1.
查询所有短中满足条件的数据
2.
对每个段的结果集合并
所以,定期的对段进行合理是很必要的。真是天下大势,分久必合合久必分。
策略:将段按大小排列分组,大到一定程度的不参与合并。小的组内合并。整体维持在一个合理的
大小范围。当然这个大到底应该是多少,是用户可配置的。这也符合设计的思想。
能说说
ElasticSearch
写索引的逻辑吗?
ElasticSearch
是集群的
=
主分片
+
副本分片。
写索引只能写主分片,然后主分片同步到副本分片上。但主分片不是固定的,可能网络原因,之前
还是
Node1
是主分片,后来就变成了
Node2
经过选举成了主分片了。
客户端如何知道哪个是主分片呢? 看下面过程。
1.
客户端向某个节点
NodeX
发送写请求
2. NodeX
通过文档信息,请求会转发到主分片的节点上
3.
主分片处理完,通知到副本分片同步数据,向
Nodex
发送成功信息。
4. Nodex
将处理结果返回给客户端。
熟悉
ElasticSearch
集群中搜索数据的过程吗?
1.
客户端向集群发送请求,集群随机选择一个
NodeX
处理这次请求。
2. Nodex
先计算文档在哪个主分片上,比如是主分片
A
,它有三个副本
A1
,
A2
,
A3
。那么请求
会轮询三个副本中的一个完成请求。
3.
如果无法确认分片,比如检索的不是一个文档,就遍历所有分片。
补充一点,一个节点的存储量是有限的,于是有了分片的概念。但是分片可能有丢失,于是有了副
本的概念。
比如:
ES
集群有
3
个分片,分片
A
、分片
B
、分片
C
,那么分片
A +
分片
B +
分片
C =
所有数据,每个分
片只有大概
1/3
。分片
A
又有副本
A1 A2 A3
,数据都是一样的。
了解
ElasticSearch
深翻页的问题及解决吗?
深翻页:比如我们检索一次,轮询所有分片,汇集结果,根据
TF-IDF
等算法打分,排序后将前
10
条数据返回。用户感觉不错,说我看看下一页。
ES
依然是轮询所有分片,汇集结果,根据
TF-IDF
等算法打分,排序后将前
11-20
条数据返回。
对用户来说,翻页应该很快啊,但是实际上,第一次检索多复杂,下一次检索就多复杂。
解决的话,可以把用户的检索结果,存入
Redis
中
10
分钟。这样分页就很快,超过
10
分钟,用户
不翻页,也就不会翻页了,数据就可以清除了。
熟悉
ElasticSearch
性能优化
1.
批量提交
背景是大量的写操作,每次提交都是一次网络开销。网络永久是优化要考虑的重点。
2.
优化硬盘
索引文件需要落地硬盘,段的思想又带来了更多的小文件,磁盘
IO
是
ES
的性能瓶颈。一个固态硬 盘比普通硬盘好太多。
3.
减少副本数量
副本可以保证集群的可用性,但是严重影响了 写索引的效率。写索引时不只完成写入索引,还要完成索引到副本的同步。ES
不是存储引擎,不要考虑数据丢失,性能更重要。 如果是批量导入,建议就关闭副本。
ElasticSearch
查询优化手段有哪些?
设计阶段调优
(
1
)根据业务增量需求,采取基于日期模板创建索引,通过
roll over API
滚动索引;
(
2
)使用别名进行索引管理;
(
3
)每天凌晨定时对索引做
force_merge
操作,以释放空间;
(
4
)采取冷热分离机制,热数据存储到
SSD
,提高检索效率;冷数据定期进行
shrink
操作,以缩
减存储;
(
5
)采取
curator
进行索引的生命周期管理;
(
6
)仅针对需要分词的字段,合理的设置分词器;
(
7
)
Mapping
阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。
……..
写入调优
(
1
)写入前副本数设置为
0
;
(
2
)写入前关闭
refresh_interval
设置为
-1
,禁用刷新机制;
(
3
)写入过程中:采取
bulk
批量写入;
(
4
)写入后恢复副本数和刷新间隔;
(
5
)尽量使用自动生成的
id
。
1.
批量提交
背景是大量的写操作,每次提交都是一次网络开销。网络永久是优化要考虑的重点。
2.
优化硬盘
索引文件需要落地硬盘,段的思想又带来了更多的小文件,磁盘
IO
是
ES
的性能瓶颈。一个固态硬
盘比普通硬盘好太多。
3.
减少副本数量
副本可以保证集群的可用性,但是严重影响了 写索引的效率。写索引时不只完成写入索引,还要完
成索引到副本的同步。
ES
不是存储引擎,不要考虑数据丢失,性能更重要。 如果是批量导入,建
议就关闭副本。
9
、
ElasticSearch
查询优化手段有哪些?
设计阶段调优
(
1
)根据业务增量需求,采取基于日期模板创建索引,通过
roll over API
滚动索引;
(
2
)使用别名进行索引管理;
(
3
)每天凌晨定时对索引做
force_merge
操作,以释放空间;
(
4
)采取冷热分离机制,热数据存储到
SSD
,提高检索效率;冷数据定期进行
shrink
操作,以缩
减存储;
(
5
)采取
curator
进行索引的生命周期管理;
(
6
)仅针对需要分词的字段,合理的设置分词器;
(
7
)
Mapping
阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。
……..
写入调优
(
1
)写入前副本数设置为
0
;
(
2
)写入前关闭
refresh_interval
设置为
-1
,禁用刷新机制;
(
3
)写入过程中:采取
bulk
批量写入;
(
4
)写入后恢复副本数和刷新间隔;
(
5
)尽量使用自动生成的
id
。
查询调优
(
1
)禁用
wildcard
;
(
2
)禁用批量
terms
(成百上千的场景);
(
3
)充分利用倒排索引机制,能
keyword
类型尽量
keyword
;
(
4
)数据量大时候,可以先基于时间敲定索引再检索;
(
5
)设置合理的路由机制。
10
、
elasticsearch
是如何实现
master
选举的?
面试官:想了解
ES
集群的底层原理,不再只关注业务层面了。
前置前提:
(
1
)只有候选主节点(
master
:
true
)的节点才能成为主节点。
(
2
)最小主节点数(
min_master_nodes
)的目的是防止脑裂。
核对了一下代码,核心入口为
fifindMaster
,选择主节点成功返回对应
Master
,否则返回
null
。选
举流程大致描述如下:
第一步:确认候选主节点数达标,
elasticsearch.yml
设置的值
discovery.zen.minimum_master_nodes
;
第二步:比较:先判定是否具备
master
资格,具备候选主节点资格的优先返回;
若两节点都为候选主节点,则
id
小的值会主节点。注意这里的
id
为
string
类型。
题外话:获取节点
id
的方法。
GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax,id,name
ip port heapPercent heapMax id name
11
、
elasticsearch
索引数据多了怎么办,如何调优,部署?
面试官:想了解大数据量的运维能力。
解答:索引数据的规划,应在前期做好规划,正所谓
“
设计先行,编码在后
”
,这样才能有效的避免
突如其来的数据激增导致集群处理能力不足引发的线上客户检索或者其他业务受到影响。
如何调优:
动态索引层面
基于模板
+
时间
+rollover api
滚动创建索引,举例:设计阶段定义:
blog
索引的模板格式为:
blog_index_
时间戳的形式,每天递增数据。这样做的好处:不至于数据量激增导致单个索引数据量
非常大,接近于上线
2
的
32
次幂
-1
,索引存储达到了
TB+
甚至更大。
一旦单个索引很大,存储等各种风险也随之而来,所以要提前考虑
+
及早避免。
存储层面
冷热数据分离存储,热数据(比如最近
3
天或者一周的数据),其余为冷数据。
对于冷数据不会再写入新数据,可以考虑定期
force_merge
加
shrink
压缩操作,节省存储空间和
检索效率。
部署层面
一旦之前没有规划,这里就属于应急策略。
结合
ES
自身的支持动态扩展的特点,动态新增机器的方式可以缓解集群压力,注意:如果之前主
节点等规划合理,不需要重启集群也能完成动态新增的