一. Elasticsearch架构原理
1、Elasticsearch的节点类型
在Elasticsearch主要分成两类节点,一类是Master,一类是DataNode。
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 指定分片、副本数量
// 创建指定分片数量、副本数量的索引 PUT /job_idx_shard_temp { "mappings":{ "properties":{ "id":{"type":"long","store":true}, "area":{"type":"keyword","store":true}, "exp":{"type":"keyword","store":true}, "edu":{"type":"keyword","store":true}, "salary":{"type":"keyword","store":true}, "job_type":{"type":"keyword","store":true}, "cmp":{"type":"keyword","store":true}, "pv":{"type":"keyword","store":true}, "title":{"type":"text","store":true}, "jd":{"type":"text"} } }, "settings":{ "number_of_shards":3, "number_of_replicas":2 } } // 查看分片、主分片、副本分片 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都保存好了文档,返回client
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 词组,都符合搜索条件。
GET /es_db/_search { "query": { "match": { "remark": "java developer" } } }
如果需要搜索的document中的remark字段,包含java和developer词组,则需要使
用下述语法:
GET /es_db/_search { "query": { "match": { "remark": { "query": "java developer", "operator": "and" } } } }
上述语法中,如果将operator的值改为or。则与第一个案例搜索语法效果一致。默认的ES执行搜索的时候,operator就是or。
如果在搜索的结果document中,需要remark字段中包含多个搜索词条中的一定比例,可以使用下述语法实现搜索。其中minimum_should_match可以使用百分比或固定数字。百分比代表query搜索条件中词条百分比,如果无法整除,向下匹配(如,query条件有3个单词,如果使用百分比提供精准度计算,那么是无法除尽的,如果需要至少匹配两个单词,则需要用67%来进行描述。如果使用66%描述,ES 则认为匹配一个单词即可。)。固定数字代表query搜索条件中的词条,至少需要 匹配多少个。
GET /es_db/_search { "query": { "match": { "remark": { "query": "java architect assistant", "minimum_should_match": "68%" } } } }
如果使用should+bool搜索的话,也可以控制搜索条件的匹配度。具体如下:下述
案例代表搜索的document中的remark字段中,必须匹配java、developer、 assistant三个词条中的至少2个。
GET /es_db/_search { "query": { "bool": { "should": [ { "match": { "remark": "java" } }, { "match": { "remark": "developer" } }, { "match": { "remark": "assistant" } } ], "minimum_should_match": 2 } } }
5.2、match 的底层转换
其实在ES中,执行match搜索的时候,ES底层通常都会对搜索条件进行底层转换,
来实现最终的搜索结果。如:
GET /es_db/_search { "query": { "match": { "remark": "java developer" } } } # 转换后是: GET /es_db/_search { "query": { "bool": { "should": [ { "term": { "remark": "java" } }, { "term": { "remark": { "value": "developer" } } } ] } } } # 完全匹配 GET /es_db/_search { "query": { "match": { "remark": { "query": "java developer", "operator": "and" } } } } # 转换后是: GET /es_db/_search { "query": { "bool": { "must": [ { "term": { "remark": "java" } }, { "term": { "remark": { "value": "developer" } } } ] } } } # 匹配度 GET /es_db/_search { "query": { "match": { "remark": { "query": "java architect assistant", "minimum_should_match": "68%" } } } } # 转换后为: GET /es_db/_search { "query": { "bool": { "should": [ { "term": { "remark": "java" } }, { "term": { "remark": "architect" } }, { "term": { "remark": "assistant" } } ], "minimum_should_match": 2 } } }
**建议,如果不怕麻烦,尽量使用转换后的语法执行搜索,效率更高。 **
**如果开发周期短,工作量大,使用简化的写法。 **