Elasticsearch架构原理
1、Elasticsearch的节点类型
1.1 Master节点
在Elasticsearch启动时,会选举出来一个Master节点。当某个节点启动后,然后
使用Zen Discovery机制找到集群中的其他节点,并建立连接。
discovery.seed_hosts: ["192.168.21.130", "192.168.21.131", "192.168.21.132"]
并从候选主节点中选举出一个主节点。
cluster.initial_master_nodes: ["node1", "node2","node3"]
Master节点主要负责:
管理索引(创建索引、删除索引)、分配分片
维护元数据
管理集群节点状态
不负责数据写入和查询,比较轻量级
一个Elasticsearch集群中,只有一个Master节点。在生产环境中,内存可以相对
小一点,但机器要稳定。
1.2 DataNode节点
在Elasticsearch集群中,会有N个DataNode节点。DataNode节点主要负责:
数据写入、数据检索,大部分Elasticsearch的压力都在DataNode节点上
在生产环境中,内存最好配置大一些
二 、分片和副本机制
2.1 分片(Shard)
Elasticsearch是一个分布式的搜索引擎,索引的数据也是分成若干部分,分布在不同的服务器节点中
分布在不同服务器节点中的索引数据,就是分片(Shard)。Elasticsearch会自动
管理分片,如果发现分片分布不均衡,就会自动迁移
一个索引(index)由多个shard(分片)组成,而分片是分布在不同的服务器上的
2.2 副本
为了对Elasticsearch的分片进行容错,假设某个节点不可用,会导致整个索引库
都将不可用。所以,需要对分片进行副本容错。每一个分片都会有对应的副本。
在Elasticsearch中,默认创建的索引为1个分片、每个分片有1个主分片和1个副本
分片。
每个分片都会有一个Primary Shard(主分片),也会有若干个Replica Shard(副
本分片)
Primary Shard和Replica Shard不在同一个节点上
2.3 指定分片、副本数量
// 创建指定分片数量、副本数量的索引
2 PUT /job_idx_shard_temp
3 {
4 "mappings":{
5 "properties":{
6 "id":{"type":"long","store":true},
7 "area":{"type":"keyword","store":true},
8 "exp":{"type":"keyword","store":true},
9 "edu":{"type":"keyword","store":true},
10 "salary":{"type":"keyword","store":true},
11 "job_type":{"type":"keyword","store":true},
12 "cmp":{"type":"keyword","store":true},
13 "pv":{"type":"keyword","store":true},
14 "title":{"type":"text","store":true},
15 "jd":{"type":"text"}
16
17 }
18 },
19 "settings":{
20 "number_of_shards":3,
21 "number_of_replicas":2
22 }
23 }
24
25 // 查看分片、主分片、副本分片
26 GET /_cat/indices?v
三、Elasticsearch重要工作流程
3.1 Elasticsearch文档写入原理
1.选择任意一个DataNode发送请求,例如:node2。此时,node2就成为一个
coordinating node(协调节点)
2.计算得到文档要写入的分片
`shard = hash(routing) % number_of_primary_shards`
routing 是一个可变值,默认是文档的 _id
3.coordinating node会进行路由,将请求转发给对应的primary shard所在的
DataNode(假设primary shard在node1、replica shard在node2)
4.node1节点上的Primary Shard处理请求,写入数据到索引库中,并将数据同步到
Replica shard
5.Primary Shard和Replica Shard都保存好了文档,返回clien
3.2 Elasticsearch检索原理
client发起查询请求,某个DataNode接收到请求,该DataNode就会成为协调节点
(Coordinating Node)
协调节点(Coordinating Node)将查询请求广播到每一个数据节点,这些数据节
点的分片会处理该查询请求
每个分片进行数据查询,将符合条件的数据放在一个优先队列中,并将这些数据
的文档ID、节点信息、分片信息返回给协调节点
协调节点将所有的结果进行汇总,并进行全局排序
协调节点向包含这些文档ID的分片发送get请求,对应的分片将文档数据返回给协
调节点,最后协调节点将数据返回给客户端
四、Elasticsearch准实时索引实现
4.1 溢写到文件系统缓存
当数据写入到ES分片时,会首先写入到内存中,然后通过内存的buffer生成一个
segment,并刷到文件系统缓存中,数据可以被检索(注意不是直接刷到磁盘)
ES中默认1秒,refresh一次
4.2 写translog保障容错
在写入到内存中的同时,也会记录translog日志,在refresh期间出现异常,会根
据translog来进行数据恢复
等到文件系统缓存中的segment数据都刷到磁盘中,清空translog文件
4.3 flush到磁盘
ES默认每隔30分钟会将文件系统缓存的数据刷入到磁盘
4.4 segment合并
Segment太多时,ES定期会将多个segment合并成为大的segment,减少索引查询时
IO开销,此阶段ES会真正的物理删除(之前执行过的delete的数据)
五.手工控制搜索结果精准度
5.1、下述搜索中,如果document中的remark字段包含java或developer词组,都符
合搜索条件。
1 GET /es_db/_search
2 {
3 "query": {
4 "match": {
5 "remark": "java developer"
6 }
7 }
8 }
如果需要搜索的document中的remark字段,包含java和developer词组,则需要使
用下述语法:
1 GET /es_db/_search
2 {
3 "query": {
4 "match": {
5 "remark": {
6 "query": "java developer",
7 "operator": "and"
8 }
9 }
10 }
11 }
上述语法中,如果将operator的值改为or。则与第一个案例搜索语法效果一致。默
认的ES执行搜索的时候,operator就是or。
如果在搜索的结果document中,需要remark字段中包含多个搜索词条中的一定比
例,可以使用下述语法实现搜索。其中minimum_should_match可以使用百分比或固
定数字。百分比代表query搜索条件中词条百分比,如果无法整除,向下匹配
(如,query条件有3个单词,如果使用百分比提供精准度计算,那么是无法除尽
的,如果需要至少匹配两个单词,则需要用67%来进行描述。如果使用66%描述,ES
则认为匹配一个单词即可。)。固定数字代表query搜索条件中的词条,至少需要
匹配多少个。
1 GET /es_db/_search
2 {
3 "query": {
4 "match": {
5 "remark": {
6 "query": "java architect assistant",
7 "minimum_should_match": "68%"
8 }
9 }
10 }
11 }
如果使用should+bool搜索的话,也可以控制搜索条件的匹配度。具体如下:下述
案例代表搜索的document中的remark字段中,必须匹配java、developer、
assistant三个词条中的至少2个。
1 GET /es_db/_search
2 {
3 "query": {
4 "bool": {
5 "should": [
6 {
7 "match": {
8 "remark": "java"
9 }
10 },
11 {
12 "match": {
13 "remark": "developer"
14 }
15 },
16 {
17 "match": {
18 "remark": "assistant"
19 }
20 }
21 ],
22 "minimum_should_match": 2
23 }
24 }
25 }
5.2、match 的底层转换
其实在ES中,执行match搜索的时候,ES底层通常都会对搜索条件进行底层转换,
来实现最终的搜索结果。如:
1 GET /es_db/_search
2 {
3 "query": {
4 "match": {
5 "remark": "java developer"
6 }
7 }
8 }
9
10 转换后是:
11 GET /es_db/_search
12 {
13 "query": {
14 "bool": {
15 "should": [
16 {
17 "term": {
18 "remark": "java"
19 }
20 },
21 {
22 "term": {
23 "remark": {
24 "value": "developer"
25 }
26 }
27 }
28 ]
29 }
30 }
31 }
1 GET /es_db/_search
2 {
3 "query": {
4 "match": {
5 "remark": {
6 "query": "java developer",
7 "operator": "and"
8 }
9 }
10 }
11 }
12
13 转换后是:
14 GET /es_db/_search
15 {
16 "query": {
17 "bool": {
18 "must": [
19 {
20 "term": {
21 "remark": "java"
22 }
23 },
24 {
25 "term": {
26 "remark": {
27 "value": "developer"
28 }
29 }
30 }
31 ]
32 }
33 }
34 }
1 GET /es_db/_search
2 {
3 "query": {
4 "match": {
5 "remark": {
6 "query": "java architect assistant",
7 "minimum_should_match": "68%"
8 }
9 }
10 }
11 }
12
13 转换后为:
14 GET /es_db/_search
15 {
16 "query": {
17 "bool": {
18 "should": [
19 {
20 "term": {
21 "remark": "java"
22 }
23 },
24 {
25 "term": {
26 "remark": "architect"
27 }
28 },
29 {
30 "term": {
31 "remark": "assistant"
32 }
33 }
34 ],
35 "minimum_should_match": 2
36 }
37 }
38 }
5.3、boost权重控制
搜索document中remark字段中包含java的数据,如果remark中包含developer
或architect,则包含architect的document优先显示。(就是将architect数据匹
配时的相关度分数增加)。
一般用于搜索时相关度排序使用。如:电商中的综合排序。将一个商品的销
量,广告投放,评价值,库存,单价比较综合排序。在上述的排序元素中,广告投
放权重最高,库存权重最低。
GET /es_db/_search
2 {
3 "query": {
4 "bool": {
5 "must": [
6 {
7 "match": {
8 "remark": "java"
9 }
10 }
11 ],
12 "should": [
13 {
14 "match": {
15 "remark": {
16 "query": "developer",
17 "boost" : 1
18 }
19 }
20 },
21 {
22 "match": {
23 "remark": {
24 "query": "architect",
25 "boost" : 3
26 }
27 }
28 }
29 ]
30 }
31 }
32 }
5.4、基于dis_max实现best fields策略进行多字段搜索
best fields策略: 搜索的document中的某一个field,尽可能多的匹配搜索
条件。与之相反的是,尽可能多的字段匹配到搜索条件(most fields策略)。如
百度搜索使用这种策略。
优点:精确匹配的数据可以尽可能的排列在最前端,且可以通过
minimum_should_match来去除长尾数据,避免长尾数据字段对排序结果的影响。
长尾数据比如说我们搜索4个关键词,但很多文档只匹配1个,也显示出来了,这些文
档其实不是我们想要的
缺点:相对排序不均匀。
dis_max语法: 直接获取搜索的多条件中的,单条件query相关度分数最
高的数据,以这个数据做相关度排序。
下述的案例中,就是找name字段中rod匹配相关度分数或remark字段中java
developer匹配相关度分数,哪个高,就使用哪一个相关度分数进行结果排序。
1 GET /es_db/_search
2 {
3 "query": {
4 "dis_max": {
5 "queries": [
6 {
7 "match": {
8 "name": "rod"
9 }
10 },
11 {
12 "match": {
13 "remark": "java developer"
14 }
15 }
16 ]
17 }
18 }
19 }
5.5、基于tie_breaker参数优化dis_max搜索效果
dis_max是将多个搜索query条件中相关度分数最高的用于结果排序,忽略其他
query分数,在某些情况下,可能还需要其他query条件中的相关度介入最终的结果
排序,这个时候可以使用tie_breaker参数来优化dis_max搜索。tie_breaker参数
代表的含义是:将其他query搜索条件的相关度分数乘以参数值,再参与到结果排
序中。如果不定义此参数,相当于参数值为0。所以其他query条件的相关度分数被
忽略。
1 GET /es_db/_search
2 {
3 "query": {
4 "dis_max": {
5 "queries": [
6 {
7 "match": {
8 "name": "rod"
9 }
10 },
11 {
12 "match": {
13 "remark": "java developer"
14 }
15 }
16 ],
17 "tie_breaker":0.5
18 }
19 }
20 }
5.6、使用multi_match简化dis_max+tie_breaker
1 GET /es_db/_search
2 {
3 "query": {
4 "dis_max": {
5 "queries": [
6 {
7 "match": {
8 "name": "rod"
9 }
10 },
11 {
12 "match": {
13 "remark": {
14 "query": "java developer",
15 "boost" : 2,
16 "minimum_should_match": 2
17 }
18 }
19 }
20 ],
21 "tie_breaker": 0.5
22 }
23 }
24 }
25
26 #使用multi_match语法为:其中type常用的有best_fields和most_fields。^n代表权重,
相当于"boost":n。
27 GET /es_db/_search
28 {
29 "query": {
30 "multi_match": {
31 "query": "rod java developer",
32 "fields": ["name", "remark^2"],
33 "type": "best_fields",
34 "tie_breaker": 0.5,
35 "minimum_should_match" : "50%"
36 }
37 }
38 }