`
huangyongxing310
  • 浏览: 476232 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

elasticSearch使用

阅读更多
ElasticSearch
基于Apache Lucene构建的开源搜索引擎;
采用Java编写,提供简单易用的 RESTFul API;(Post,put,get,delete)
轻松的横向扩展,可支持PB级的结构化或非结构化数据处理;

应用场景
海量数据分析引擎
站内搜索引擎
数据仓库

一线公司实际应用场景:
英国卫报-实时分析公众对文章的回应;
维基百科、Github-站内实时搜索
百度-实时日志监控平台

ElasticSearch基础概念
集群和节点:
索引:含有相同属性的文档集合;相当于mysql的Database
类型:索引可以定义一个或多个类型,文档必须属于一个类型;类似于mysql中的table
文档:文档是可以被索引的基本数据单位;Document1相当于mysql中某个table的数据
分片:每个索引都有多个分片,每个分片是一个Lucene索引;ES自动管理和组织分片, 并在必要的时候对分片数据进行再平衡分配, 所以用户基本上不用担心分片的处理细节.
备份:拷贝一份分片就完成了分片的备份; ES 默认为一个索引创建 5 个主分片, 并分别为其创建一个副本分片. 也就是说每个索引都由 5 个主分片成本, 而每个主分片都相应的有一个 copy。

ElasticSearch Head插件,ElasticSearch可视化工具。
npm install phantomjs
npm config set registry https://registry.npm.taobao.org
npm install
npm start


Elasticsearch映射
映射是存储在索引中的文档的大纲。它定义数据类型,如geo_point或文档和规则中存在的字段的字符串和格式,以控制动态添加的字段的映射。
Elasticsearch为自动创建映射提供了一个用户友好的机制。用户可以将数据直接发布到任何未定义的映射,Elasticsearch将自动创建映射,这称为动态映射。

Mapping(es对应字段数据类型的信息,字段数据类型与ES对数据进行索引时有影响)
(1)字段类型
字符串(string)
text,keyword
text类型,设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text类型的字段不用于排序,很少用于聚合。
keyword类型,如果字段需要进行过滤(比如查找已发布博客中status属性为published的文章)、排序、聚合。keyword类型的字段只能通过精确值搜索到。
数字类型(Numberic)
long,integer,short,double,byte,float,half_float,scaled_float
日期类型(Date)
date
布尔类型(Boolean)
boolean
二进制类型(Binary)
binary
数组类型(Array)
array
对象类型(Object)
object用于单json对象
嵌套类型(Nested)
用于json对象数组
地理坐标(Geo-points)
geo_point用于描述经纬度坐标
地理图形(Geo-Shape)
geo_shape用于描述复杂类型,如多边形
(2)映射
Mapping用于定义一个文档(document),以及他所包含的属性(field)是如何存储和索引的。比如:使用Mapping来定义:
那些字符串属性应该被全文检索(full test fields)
那些属性包含数字、日期、地理位置信息
文档中的所有数据是否都能被索引(all配置)
日期的格式
自定义映射规则来执行动态增加属性
查看Mapping信息

查看Mapping信息
GET /testaggs/_mapping

设置属性是否被全文检索
PUT /my_index
{
    "mappings":{
        "properties":{
            "age":{
                "type":"integer"
            },
            "email":{
                "type":"keyword"
            },
            "name":{
                "type":"text"
            }
        }
    }
}

添加新的字段映射
PUT /my_index/_mapping
{
    "properties":{
        "employee-id":{
            "type":"keyword",
            "index":false
        }
    }
}

更新映射
对于已经存在的字段映射,我们不能进行更新。更新必须创建新的索引,进行数据迁移
POST _reindex
{
"source":{
"index":"twitter"
},
"dest":{
"index":"new_twitters"
}
}

去掉type就是为了提高ES处理数据的效率。
Elasticsearch 7.x URL中的type参数为可选。比如,索引一个文档不再要求提供文档类型
Elasticsearch 8.x 不再支持URL中的type参数。


版本号(_version)可用于跟踪文档已编入索引的次数。它的主要目的是允许乐观的并发控制,因为可以在索引请求中提供一个版本,
如果提供的版本高于索引中的版本,ElasticSearch将只覆盖文档内容,ID值不变,版本号自动添加。


Mapping 支持属性
"enabled":true (缺省)| false ,enabled:仅存储、不做搜索和聚合分析
"index": true(缺省)| false,index:是否构建倒排索引(即是否分词,设置false,字段将不会被索引)
"index_options": "docs",index_option:存储倒排索引的哪些信息
4个可选参数:
      docs:索引文档号
      freqs:文档号+词频
      positions:文档号+词频+位置,通常用来距离查询
      offsets:文档号+词频+位置+偏移量,通常被使用在高亮字段
分词字段默认是positions,其他默认时docs

通过不同的方法索引相同的字段通常非常有用。这也是多字段的目的。例如,一个字符串字段可以映射为text字段用于全文本搜索,也可以映射为keyword字段用于排序或聚合。
PUT my_index
{
  "mappings": {
    "_doc": {
      "properties": {
        "city": {
          "type": "text",
          "fields": {
            "raw": {
              "type":  "keyword"
            }
          }
        }
      }
    }
  }
}
note:city.raw字段是city字段的keyword版本。


Elasticsearch API约定
逗号分隔符号
POST http://localhost:9200/index1,index2,index3/_search

所有索引的_all关键字
POST http://localhost:9200/_all/_search

通配符(*,+, - )
POST http://localhost:9200/school*/_search
以school 开始

POST http://localhost:9200/school*,-schools_gov /_search
以“school”开头,但不是schools_gov

POST http://localhost:9200/school*,book_shops/_search?ignore_unavailable = true
ignore_unavailable - 如果URL中存在的一个或多个索引不存在,则不会发生错误或操作不会停止

allow_no_indices
如果带有通配符的网址没有索引,这个参数是true值时将防止错误。

通过在post中添加_close或_open来请求索引,可以很容易地关闭或打开一个或多个索引。
例如,关闭索引-
POST http://localhost:9200/schools/_close
或打开索引-
POST http://localhost:9200/schools/_open

索引统计
此API可用于提取有关特定索引的统计信息。只需要发送一个带有索引URL和_stats关键字的get请求。
GET http://localhost:9200/schools/_stats

刷新清除数据
此API用于从索引内存中清除数据,并将其迁移到索引存储,并清除内部事务日志。 例如,
GET http://localhost:9200/schools/_flush

刷新索引
默认情况下,刷新在Elasticsearch中一般按计划来执行,但可以使用_refresh显式刷新一个或多个索引。 例如,
GET http://localhost:9200/schools/_refresh

删除数据
删除单个文档或者一组丈档  Elasticsearch只是将它们标记为删除,所以 它们不会再出现于搜索结果中,稍后 Elasticsearch 通过异步的方式将它们彻底地从索引中移出。
删除整个索引  主要的工作就是移除和那个索引相关的所有文件,几乎是瞬间就能完成 。
关闭索引  关闭的索引不允许读取或者写入操作,数据也不会加载到内存。 这和删除 Elasticsearch数据类似,但是索引还是保留在磁盘上。它也很容易恢复,只要再次打开关闭的索引 。

Elasticsearch集群
Elasticsearch -- 集群内的原理(https://www.jianshu.com/p/698418629e37)
集群: 一个或者多个具有相同 cluster.name 配置的节点组成集群
节点:一个运行的Elasticsearch实例为一个节点
分片:底层的工作单元,简单来说它就是Lucene的一个实例
1)集群内的节点共同承担数据和负载的压力。
2)当有节点加入或者移出集群时,集群会重新平均分配所有的数据。

节点
1)主节点负责集群内的所有变更(如增加、删除节点,增加、删除索引等)
2)主节点并不需要涉及到文档级别的变更和搜索
3)任何节点都可以成为主节点
4)每个节点都知道任意文档所处的位置,当用户请求时无论请求哪个节点都能直接将请求转发给实际存储文档的节点
5)无论用户请求哪个节点,它都能负责从个个包含我们所需文档的各个节点收集回数据并发给客户端,对这一切都是透明的

分片
1)一个分片是一个底层的 工作单元
2)它本身就是一个完整的搜索引擎
3)应用程序是直接与索引而不是与分片进行交互
4)Elasticsearch 是利用分片将数据分发到集群内各处的
5)分片是数据的容器,文档保存在分片内
6)分片又被分配到集群内的各个节点里
7) 当你的集群规模扩大或者缩小时, Elasticsearch 会自动的在各节点中迁移分片,使得数据仍然均匀分布在集群里。
8)一个分片可以是主分片或者副本分片
9)索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量
10)一个副本分片只是一个主分片的拷贝。副本分片作为硬件故障时保护数据不丢失的冗余备份,并为搜索和返回文档等读操作提供服务
11)在索引建立的时候就已经确定了主分片数,但是副本分片数可以随时修改


ElasticSearch的数据存储原理
文档元数据:文档元数据:一个文档不仅仅包含它的数据,也包含元数据—有关文档的信息。三个必须的元数据元素如下:
_index:文档在哪存放
_type:文档表示的对象类别
_id:文档唯一标识

文档的路由机制,当索引一个文档的时候,文档会被存储到一个主分片中。 Elasticsearch 如何知道一个文档应该存放到哪个分片中呢(hash(ID)余数)

步骤分析
1:写入请求,分发节点。
2:数据写入同时写入内存和translog各一份,tanslog为保证数据不丢失,每 5 秒,或每次请求操作结束前,会强制刷新 translog 日志到磁盘上
3:确定数据给那个分片,refresh 刷新内存中数据到分片的segment,默认1秒刷新一次,为了提高吞吐量可以增大60s。参数refresh_interval
4:segment刷新到磁盘中完成持久化,保存成功清除translog,新版本es的 translog 不会在 segment 落盘就删,而是会保留,默认是512MB,保留12小时。每个分片。所以分片多的话 ,要考虑 translog 会带来的额外存储开销
5:segment过多会进行合并merge为大的segment,消耗大量的磁盘io和网络io


索引数据的具体保存方式
elasticsearch底层是lucene存储架构
elasticsearch的数据保存在lucene文件中,es的elasticsearch.yml配置文件中配置数据保存路径。
lucene包的文件是由很多segment文件组成的,segments_xxx文件记录了lucene包下面的segment文件数量。每个segment会主要包含如下的文件。
shard是Elasticsearch数据存储的最小单位,
对于一个shard,Elasticsearch增加了translog的功能,类似于HBase WAL,是数据写入过程中的中间数据,其余的数据都在lucene库中管理的。

lucene数据存储
lucene基本概念
segment : lucene内部的数据是由一个个segment组成的,写入lucene的数据并不直接落盘,而是先写在内存中,经过了refresh间隔,
lucene才将该时间段写入的全部数据refresh成一个segment,segment多了之后会进行merge成更大的segment。lucene查询时会遍历每个segment完成。
由于lucene* 写入的数据是在内存中完成,所以写入效率非常高。但是也存在丢失数据的风险,所以Elasticsearch基于此现象实现了translog,
只有在segment数据落盘后,Elasticsearch才会删除对应的translog。

doc : doc表示lucene中的一条记录
field :field表示记录中的字段概念,一个doc由若干个field组成。
term :term是lucene中索引的最小单位,某个field对应的内容如果是全文检索类型,会将内容进行分词,分词的结果就是由term组成的。如果是不分词的字段,那么该字段的内容就是一个term。
倒排索引(inverted index): lucene索引的通用叫法,即实现了term到doc list的映射。
正排数据:搜索引擎的通用叫法,即原始数据,可以理解为一个doc list。
docvalues :Elasticsearch中的列式存储的名称,Elasticsearch除了存储原始存储、倒排索引,还存储了一份docvalues,用作分析和排序。

lucene包的文件是由很多segment文件组成的,segments_xxx文件记录了lucene包下面的segment文件数量。每个segment会包含如下的文件。

一个分片是一个最小的工作单元,它只是保存了索引中所有数据的一部分。

主分片的数量决定了索引最多能存储多少数据,主分片过小会在索引增长较快的时候,集群无法通过增加节点实现对这个索引的数据扩展;主分片数过大会导致单个shard容量很小,引发一个节点上过多分片,影响性能。

如果主分片数量发生变化,那么所有之前路由的值都会无效,文档就无法被检索,所以Elasticsearch不支持扩展主分片,除非重建索引。
每个主分片应该至少有一个副本分片,当主分片异常时,副本可以promote为主节点。主分片和对应的副本分片是不会在同一个节点上的,所以副本分片数的最大值是 n -1(其中 n 为节点数)。
主分片或者副本分片都可以处理读请求——搜索或文档检索,所以数据的冗余越多,能处理的搜索吞吐量就越大。

Master Node-处理请求,处理创建、删除索引等请求、决定分片分到那个节点,维护并更新Cluster 状态。在每一个节点上都保存了集群的状态信息。但是,只有Master节点上才能修改集群状态的信息,并负责同步给其他节点。

倒排索引是不可变的,不可变意味着新增和修改文档内容,需要重建整个索引,频繁的重建会引起大量的消耗(CPU、IO)。

动态更新索引,Elasticsearch通过增加新的补充索引来反映最近的修改,而不是直接重写整个倒排索引。每一个倒排索引都会从最早的开始被轮流查询,查询完后再对结果进行合并。

Elasticsearch每个segment本身都是一个倒排索引, 但索引在除了表示所有段的集合外,还增加了提交点的概念(一个列出了所有已知段的文件)。

段写入磁盘的流程如下:
1、新的文档首先写入内存区的索引缓存
2、缓存中的内容不时被提交:
一个新的段(额外的倒排索引)写入磁盘。
新的提交点写入磁盘,包括新段的名称
所有写操作等待文件系统缓存同步到磁盘,确保被写入。
3、新的段被打开,它包含的文档可以被检索
4、内存中的缓存被清除,等待接受新的文档。

删除和更新
段是不可改变的,所以既不能从把文档从旧的段中移除,也不能修改旧的段来进行反映文档的更新。 取而代之的是,每个提交点会包含一个 .del 文件,文件中会列出这些被删除文档的段信息。
当一个文档被 “删除” 时,它实际上只是在 .del 文件中被标记删除。一个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。
文档更新也是类似的操作方式:当一个文档被更新时,旧版本文档被标记删除,文档的新版本被索引到一个新的段中。 可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就已经被移除。

近实时搜索
在动态更新机制中,新增加的文档在没有落到磁盘之前是不可检索的,所以新增加的文档是需要延迟一段时间才可以被搜索到,磁盘会是瓶颈(fsync消耗比较大,不能在每个文档被索引时就触发)。
在 Elasticsearch 中,将Index Buffer写入Segment的过程叫Refresh。 默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是近实时搜索:文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。

Segment写入磁盘的过程相对耗时,借助文件系统缓存,Refresh时,先将Segment写入缓存以开放查询
为了保证数据不会丢失。所以在Index文档时,同时写Transaction Log,高版本开始,Transaction Log默认落盘,每个分片有一个Transaction Log
在ES Refresh 时,Index Buffer被清空,Transaction Log不会被清空

段合并
Elasticsearch通过在后台进行段合并来解决这个问题。小的段被合并到大的段,然后这些大的段再被合并到更大的段。
段合并的时候会将那些旧的已删除文档从文件系统中清除。被删除的文档(或被更新文档的旧版本)不会被拷贝到新的大段中。
启动段合并不需要做任何事。进行索引和搜索时会自动进行。

合并大的段需要消耗大量的I/O和CPU资源,如果任其发展会影响搜索性能。Elasticsearch在默认情况下会对合并流程进行资源限制,所以搜索仍然 有足够的资源很好地执行。

1、索引过程中,refresh会创建新的段,并打开它
2、合并过程会在后台选择一些小的段(包含已提交和未提交的)合并成大的段,这个过程不会中断索引和搜索
3、合并后的段会被flush到硬盘,新的提交点会写入新的段,排除旧的段。新的段打开提供搜索,旧段被删除
合并段会消耗大量的IO和CPU,ES会限制合并的过程,保证有足够的资源来进行搜索。

倒排索引(Inverted Index)
每一个文档都对应一个ID。倒排索引会按照指定语法对每一个文档进行分词,然后维护一张表,列举所有文档中出现的terms以及它们出现的文档ID和出现频率。搜索时同样会对关键词进行同样的分词分析,然后查表得到结果。

这里所述倒排索引是针对非结构化的文档构造的,而在ES中存储的文档是基于JSON格式的,因此索引结构会更为复杂。简单来说,ES对于JSON文档中的每一个field都会构建一个对应的倒排索引。
分片(Shard),一个索引中的数据保存在多个分片中,相当于水平分表。一个分片便是一个Lucene 的实例,它本身就是一个完整的搜索引擎。
每一个分片还会进一步拆分为分段(Segment)。这是ES写入文档所采用的机制造成的结果。

每个节点都存储有每个分片存储在哪个节点的信息,因此协调节点会将请求发送给对应的节点。注意这个请求会发送给主分片,等主分片完成索引,会并行将请求发送到其所有副本分片,保证每个分片都持有最新数据。
每次写入新文档时,都会先写入内存中,并将这一操作写入一个translog文件(transaction log)中,此时如果执行搜索操作,这个新文档还不能被索引到。
ES会每隔1秒时间(这个时间可以修改)进行一次刷新操作(refresh),此时在这1秒时间内写入内存的新文档都会被写入一个文件系统缓存(filesystem cache)中,并构成一个分段(segment)。
此时这个segment里的文档可以被搜索到,但是尚未写入硬盘,即如果此时发生断电,则这些文档可能会丢失。
每隔30分钟或者translog文件变得很大,则执行一次fsync操作。此时所有在文件系统缓存中的segment将被写入磁盘,而translog将被删除(此后会生成新的translog)。
由上面的流程可以看出,在两次fsync操作之间,存储在内存和文件系统缓存中的文档是不安全的,一旦出现断电这些文档就会丢失。所以ES引入了translog来记录两次fsync之间所有的操作,
这样机器从故障中恢复或者重新启动,ES便可以根据translog进行还原。
当然,translog本身也是文件,存在于内存当中,如果发生断电一样会丢失。因此,ES会在每隔5秒时间或是一次写入请求完成后将translog写入磁盘。可以认为一个对文档的操作一旦
写入磁盘便是安全的可以复原的,因此只有在当前操作记录被写入磁盘,ES才会将操作成功的结果返回发送此操作请求的客户端。
此外,由于每一秒就会生成一个新的segment,很快将会有大量的segment。对于一个分片进行查询请求,将会轮流查询分片中的所有segment,这将降低搜索的效率。
因此ES会自动启动合并segment的工作,将一部分相似大小的segment合并成一个新的大segment。合并的过程实际上是创建了一个新的segment,当新segment被写入磁盘,
所有被合并的旧segment被清除。

https://blog.csdn.net/wang7075202/article/details/111308905?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-111308905-blog-91838956.pc_relevant_default&spm=1001.2101.3001.4242.2&utm_relevant_index=4

读操作(Read):查询过程
查询的过程大体上分为查询(query)和取回(fetch)两个阶段。这个节点的任务是广播查询请求到所有相关分片,并将它们的响应整合成全局排序后的结果集合,这个结果集合会返回给客户端。
查询阶段
当一个节点接收到一个搜索请求,则这个节点就变成了协调节点。
第一步是广播请求到索引中每一个节点的分片拷贝。 查询请求可以被某个主分片或某个副本分片处理,协调节点将在之后的请求中轮询所有的分片拷贝来分摊负载。
每个分片将会在本地构建一个优先级队列。如果客户端要求返回结果排序中从第from名开始的数量为size的结果集,则每个节点都需要生成一个from+size大小的结果集,因此优先级队列的大小也是from+size。分片仅会返回一个轻量级的结果给协调节点,包含结果集中的每一个文档的ID和进行排序所需要的信息。
协调节点会将所有分片的结果汇总,并进行全局排序,得到最终的查询排序结果。此时查询阶段结束。
取回阶段
查询过程得到的是一个排序结果,标记出哪些文档是符合搜索要求的,此时仍然需要获取这些文档返回客户端。
协调节点会确定实际需要返回的文档,并向含有该文档的分片发送get请求;分片获取文档返回给协调节点;协调节点将结果返回给客户端。
相关性计算
在搜索过程中对文档进行排序,需要对每一个文档进行打分,判别文档与搜索条件的相关程度。在旧版本的ES中默认采用TF/IDF(term frequency/inverse document frequency)算法对文档进行打分。

一个Lucene索引会包含一个提交点和多个段,段被写入到磁盘后会生成一个提交点,提交点是一个用来记录所有提交后段信息的文件。一个段一旦拥有了提交点,就说明这个段只有读的权限,失去了写的权限。ES在启动或重新打开一个索引的过程中使用这个提交点来判断哪些段隶属于当前分片。

https://www.cnblogs.com/aqsaycode/p/14747485.html(ElasticSearch第三弹之存储原理)

lucene 全文检索原理和流程

https://zhuanlan.zhihu.com/p/387916586(lucene 全文检索原理和流程)
索引(Index):
    一个目录一个索引,在Lucene中一个索引是放在一个文件夹中的。
    如左图,同一文件夹中的所有的文件构成一个Lucene索引。
段(Segment):
    一个索引可以包含多个段,段与段之间是独立的,添加新文档可以生成新的段,不同的段可以合并。
    在建立索引的时候对性能影响最大的地方就是在将索引写入文件的时候, 所以在具体应用的时候就需要对此加以控制,段(Segment) 就是实现这种控制的。稍后详细描述段(Segment) 的控制策略。
    如上图,具有相同前缀文件的属同一个段,图中共两个段 "_0" 和 "_1"。
    segments.gen和segments_5是段的元数据文件,也即它们保存了段的属性信息。
文档(Document):
    文档是我们建索引的基本单位,不同的文档是保存在不同的段中的,一个段可以包含多篇文档。
    新添加的文档是单独保存在一个新生成的段中,随着段的合并,不同的文档合并到同一个段中。
域(Field):
    一篇文档包含不同类型的信息,可以分开索引,比如标题,时间,正文,作者等,都可以保存在不同的域里。
    不同域的索引方式可以不同。
词(Term):
    词是索引的最小单位,是经过词法分析和语言处理后的字符串。

Lucene的索引结构中,即保存了正向信息,也保存了反向信息。
按层次保存了从索引,一直到词的包含关系:索引(Index) –> 段(segment) –> 文档(Document) –> 域(Field) –> 词(Term)
也即此索引包含了那些段,每个段包含了那些文档,每个文档包含了那些域,每个域包含了那些词。
既然是层次结构,则每个层次都保存了本层次的信息以及下一层次的元信息,也即属性信息,比如一本介绍中国地理的书,应该首先介绍中国地理的概况,以及中国包含多少个省,每个省介绍本省的基本概况及包含多少个市,
每个市介绍本市的基本概况及包含多少个县,每个县具体介绍每个县的具体情况。
如上图,包含正向信息的文件有:
    segments_N保存了此索引包含多少个段,每个段包含多少篇文档。
    XXX.fnm保存了此段包含了多少个域,每个域的名称及索引方式。
    XXX.fdx,XXX.fdt保存了此段包含的所有文档,每篇文档包含了多少域,每个域保存了那些信息。
    XXX.tvx,XXX.tvd,XXX.tvf保存了此段包含多少文档,每篇文档包含了多少域,每个域包含了多少词,每个词的字符串,位置等信息。

所谓反向信息:
保存了词典到倒排表的映射:词(Term) –> 文档(Document)
如上图,包含反向信息的文件有:
    XXX.tis,XXX.tii保存了词典(Term Dictionary),也即此段包含的所有的词按字典顺序的排序。
    XXX.frq保存了倒排表,也即包含每个词的文档ID列表。
    XXX.prx保存了倒排表中每个词在包含此词的文档中的位置。

段(Segment) 的控制策略
在建立索引的时候对性能影响最大的地方就是在将索引写入文件的时候, 所以在具体应用的时候就需要对此加以控制:
Lucene默认情况是每加入10份文档(Document)就从内存往index文件写入并生成一个段(Segment) ,然后每10个段(Segment)就合并成一个段(Segment). 这些控制的变量如下:

MaxMergeDocs用于控制一个segment文件中最多包含的Document数.比如限制为100的话,即使当前有10个segment也不会合并,因为合并后的segment将包含1000个文档,超过了限制。
MinMergeDocs用于确定一个当内存中文档达到多少的时候才写入文件,该项对segment的数量和大小不会有什么影响,它仅仅影响内存的使用,进一步影响写索引的效率。


Lucene内最核心的倒排索引,本质上就是Term到所有包含该Term的文档的DocId列表的映射。所以Lucene内部在搜索的时候会是一个两阶段的查询,第一阶段是通过给定的Term的条件找到所有Doc的DocId列表,
第二阶段是根据DocId查找Doc。Lucene提供基于Term的搜索功能,也提供基于DocId的查询功能。就是倒排索引和正排信息共同支撑了整个查询过程。

正向信息的存储
按层次保存了从索引,一直到词的包含关系:索引(Index) –> 段(segment) –> 文档(Document) –> 域(Field) –> 词(Term)
也即此索引包含了那些段,每个段包含了那些文档,每个文档包含了那些域,每个域包含了那些词。
既然是层次结构,则每个层次都保存了本层次的信息以及下一层次的元信息,也即属性信息,比如一本介绍中国地理的书,应该首先介绍中国地理的概况,以及中国包含多少个省,每个省介绍本省的基本概况及包含多少个市,每个市介绍本市的基本概况及包含多少个县,每个县具体介绍每个县的具体情况。
包含正向信息的文件有:
segments_N保存了此索引包含多少个段,每个段包含多少篇文档。
XXX.fnm保存了此段包含了多少个域,每个域的名称及索引方式。
XXX.fdx,XXX.fdt保存了此段包含的所有文档,每篇文档包含了多少域,每个域保存了那些信息。
XXX.tvx,XXX.tvd 保存了此段包含多少文档,每篇文档包含了多少域,每个域包含了多少词,每个词的字符串,位置等信息。


https://blog.csdn.net/Mirror_w/article/details/90547584(lucene原理讲解)

Elasticsearch集群API ()


全文查询(match_all)
匹配查询(match)
multi_match查询(multi_match)
"multi_match" : {
"query": "hyderabad",
"fields": [ "city", "state" ]
}
查询字符串查询(query_string)

期限等级查询(这些查询主要处理结构化数据,如数字,日期和枚举。)(term)

范围查询(gte − 大于和等于,gt − 大于,lte − 小于和等于,lt − 小于)

复合查询,这些查询是通过使用如和,或,非和或等,用于不同索引或具有函数调用等的布尔运算符彼此合并的不同查询的集合。


自动索引创建
当请求将JSON对象添加到特定索引时,如果该索引不存在,那么此API会自动创建该索引
以及该特定JSON对象的基础映射。 可以通过将以下参数的值更改为false来禁用此功能,
这个值是存在于elasticsearch.yml文件中,打开elasticsearch.yml文件设置如下 。
action.auto_create_index:false   //限制了自动创建索引
index.mapper.dynamic:false          //限制了自动创建基础映射

版本控制,
在进行修改时带上版本信息(?version=1 ),多个客户端同时对同一个版本号更改时,只有第一个可以修改成功,其他的会报错

自动生成ID
当在创建索引操作中未指定ID时,Elasticsearch自动为文档生成ID。

超时
默认情况下,索引操作将在主分片上最多等待1分钟,超过后就会失败并响应错误。 可以通过将值传递给timeout参数来显式更改这个超时值。(?timeout = 3m)




API格式:
POST/GET/PUT/DELETE http://localhost:9200/<索引>/<类型>/<文档ID>

索引,可以多个用逗号隔开,或者基于正则表达式或其他方便选项的方式

格式例子
/_search
在所有索引的所有类型中搜索
/gb/_search
在索引gb的所有类型中搜索
/gb,us/_search
在索引gb和us的所有类型中搜索
/g*,u*/_search
在以g或u开头的索引的所有类型中搜索
/gb/user/_search
在索引gb的类型user中搜索
/gb,us/user,tweet/_search
在索引gb和us的类型为user和tweet中搜索
/_all/user,tweet/_search
在所有索引的user和tweet中搜索 search types user and tweet in all indices



倒排索引
分词:将整句拆分为单词
分词对应文档的映射关系表,方便记录某些分词在那些文档中有匹配

初步检索
GET _cat/nodes 查看所有节点
GET _cat/health 查看es健康状态
Get _cat/master 查看主节点
GET _cat/indices 查看所有索引
GET /_cat/XXX/?v 加V开启详细输出,就多了表头信息,信息更加直观明了
GET /_cat/XXX/?help 帮助信息
GET /_cat/XXX/?h=column1,column2 指定输出的列
GET /_cat/XXX/?v&s=column1,column2:desc,column3 指定输出的列进行排序,默认按照升序排序,(&为参数分隔符)
GET /_cat/XXX?format=json 指定响应返回的数据格式:text(默认),json,yaml,smile,cbor(通过设置 Accept的HTTP头部的多媒体格式的优先级更高)

索引一个文档,就是对一个文档建立索引,也可以说是向一个索引加入一个文档,或者向ElasticSearch加入一个文档
1、索引库名称必须要全部小写,不能以下划线开头,也不能包含逗号
POST /mall/user/1
{
"name":"hinzzz",
"age":18
}
在mall索引user类型下保存id为1的数据xxx,id可以不指定

Post文档更新
POST /mall/user/1/_update
{
"doc":{
"name":"hinzzz1",
"age":18
}
}

POST /mall/user/1/
{
"doc":{
"name":"hinzzz1",
"age":18
}
}
带_update的时候会比较doc里面的值 和已存在的值是否一样 如果不一样执行修改操作 如果一样 不进行任何操作。重复执行更新操作,数据不会更新

PUT /mall/user/1
{
"name":"wlq",
"age":18
}
mall索引user类型下保存或者修改id为1的数据xxx ,id必须制定
id已存在 执行修改操作 id不存在 新增 ,常用于修改操作

PUT /mall/user/1?if_seq_no=5&if_primary_term=1
可带条件 修改seq_no=5 primary_term=1的数据


定义字段分词以及创建索引(只有建立索引,才能被检索)
no:字段不建立索引,不被检索,无法通过检索查询到该字段。反过来,有些业务要求某些字段不能被搜索,那么index属性设置为no即可。
not_analyzed:字段值不分词,会将整个字段原样写入索引。反过来,如果某些字段需要完全匹配,比如人名、地名,index属性设置为not_analyzed为佳。
analyzed:字段被索引,会做分词,会通过默认的standard分析器进行分词,可搜索。反过来,如果需要根据某个字段进搜索,index属性就应该设置为analyzed。
ES6.3 index属性支持false和true,false不能搜索相当于no,true可以索引。默认使用standar分词,属性指定字段是否索引,不索引也就不可搜索


GET /mall/user/1
获取索引为mall类型为user并且id为1的数据

DELETE mall/user/1 #根据id删除
DELETE mall #删除整个索引


bulk(批量操作)
POST /mall/user/_bulk
{"delete":{"_index":"mall","_type":"user","_id":"4"}} /#删除的批量操作不需要请求体
{"create":{"_index":"mall","_type":"user","_id":"100"}}
{"name":"hinz100"} #请求体
{"index":{"_index":"mall","_type":"user"}} #没有指定_id,elasticsearch将会自动生成_id
{"name":"hinz"} #请求体
{"update":{"_index":"mall","_type":"user","_id":"1"}} #/更新动作不能缺失_id,文档不存在更新将会失败
{"doc":{"name":"hinz1"}} #请求体
create和index的区别:如果数据存在,使用create操作失败,会提示文档已存在,使用index则可以成功执行。


检索
Query DSL
elasticsearch提供了一个可以执行查询的Json风格的DSL,这个被称为Query DSL
GET mall/_search
{
    "query":{
        "match_all":{ //match_all 查询类型:意思是查询所有的数据

        }
    },
    "from":0, //分页查询偏移
    "size":5, //分页查询页大小
    "sort":{ //sort排序可组合多字段
        "age":{
            "order":"desc"
        }
    },
    "_source":[ //_source 指定查询结果字段 可支持多个
        "name",
        "age"
    ]
}


match 匹配查询,精确匹配
GET /mall/_search
{
    "query":{
        "match":{
            "age":"18"
        }
    }
}
查询返回age=18的数据

match在匹配时会对所查找的关键词进行分词,然后按分词匹配查找,而term会直接对关键词进行查找。一般模糊查找的时候,多用match,而精确查找时可以使用term。

GET /mall/_search
{
    "query":{
        "match":{
            "name":"hinzzz wlq hinz100" //使用空隔分开
        }
    }
}
文本类型 会将查询条件进行分词, 全文检索:最终会按照评分进行排序 会对检索条件进行分词匹配

match_phrase 短句匹配,不会对查询条件进行分词检索
GET /mall/_search
{
    "query":{
        "match_phrase":{
            "name":"hinzzz wlq"
        }
    }
}
查询name 包含 "hinzzz wlq"的结果

keyworkd 精确匹配,匹配的条件就是要显示字段的全部值,要进行精确匹配的。
GET /mall/_search
{
    "query":{
        "match_phrase":{
            "name.keyword":"hinzzz wlq"
        }
    }
}
查询name="hinzzz wlq"

multi_math 多字段匹配,
GET /mall/_search
{
    "query":{
        "multi_match":{
            "query":"sz",
            "fields":[
                "name",
                "address"
            ]
        }
    }
}
查询name和address 匹配sz的结果

bool 用来做复合查询,复合语句之间 可以互相嵌套,可以表达非常复杂的逻辑。
must:必须达到must所列举的所有条件
must_not:必须不匹配must_not所列举的所有条件。
should:应该满足should所列举的条件。 类似or

GET /mall/_search
{
    "query":{
        "bool":{
            "should":[
                {
                    "match":{
                        "name":"hinzzz"
                    }
                },
                {
                    "match":{
                        "age":"18"
                    }
                }
            ]
        }
    }
}

filter 结果过滤,不计算相关得分
{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "name":"hinzzz"
                    }
                }
            ],
            "filter":{
                "range":{
                    "age":{
                        "gte":10,
                        "lte":20
                    }
                }
            }
        }
    }
}
先查询name匹配hinzzz的结果 再从结果中获取 age>10 并且 age < 20

term 查找倒排索引中确切的term,并不知道分词器的存在。这种查询适合keyword 、numeric、date
string数据存到es中时,默认是text,被standard analyzer分词器分词,大写字母全部转为了小写字母
term查询并不会对查询条件进行分词,而默认存进去的“bj sz ”则被默认分词器分词了,所以在倒排索引中并不存在整个词“bj sz ”


Aggregation 聚合查询,聚合提供了数据分组和提取数据的能力,类似于mysql中的group by ,avg,max等聚合函数
GET /testaggs/_search
{
    "query":{
        "match":{
            "address":"sz"
        }
    },
    "aggs":{ //聚合查询
        "ageAvg":{ //这次聚合的名字,方便展示在结果集中
            "avg":{ //聚合的类型
                "field":"age"
            }
        }
    },
    "size":0 //不显示搜索数据
}




分词
一个tokenizer(分词器)接收一个字符流,将之分割为独立的tokens(词元,通常是独立的单词),然后输出tokens流。
例如:whitespace tokenizer遇到空白字符时分割文本。它会将文本“Quick brown fox!”分割为[Quick,brown,fox!]。
词元过滤器是小写化 lowercase 处理器,将英语单词小写化。
消除歧义和结果输出

通过上述步骤,有时候会生成很多分词结果集合,比如说,程序员爱编程 会被分成 程序员、程序、员、爱 和 编程 五个结果。
这也是 ik 的 ik_max_word 模式的输出结果。但是有些场景,开发者希望只有 程序员、爱 和 编程 三个分词结果,这时就需
要使用 ik 的 ik_smart 模式,也就是进行消除歧义处理。

ElasticSearch 和 ik 组合是目前较为主流的中文搜索技术方案,理解其搜索和分词的基础流程和原理,有利于开发者更快地构
建中文搜索功能,或基于自身需求,特殊定制搜索分词策略。

POST _analyze //查看分词结果(查看分词成了如何)
{
"analyzer": "standard",
"text": "1红色黑色"
}

POST _analyze
{
"analyzer": "ik_smart",
"text": "阿里巴巴welcome" //空格或者;或者一些其它字符出会引起分词
}


全文搜索和精确匹配
ElasticSearch 支持对文本类型数据进行全文搜索和精确搜索,但是必须提前为其设置对应的类型:
keyword 类型,存储时不会做分词处理,支持精确查询和分词匹配查询;(存储时不会做分词处理)
text 类型,存储时会进行分词处理,也支持精确查询和分词匹配查询。(存储时会进行分词处理)

查询方式
term 查询,也就是精确查询,不进行分词,而是直接根据输入词进行查询;(不进行分词)
match 查询,也就是分词匹配查询,先对输入词进行分词,然后逐个对分词后的词元进行查询。(先对输入词进行分词)




//term与terms均是用来做查询的,两者区别如下:
term 查询某个字段里含有某个关键词的文档
GET /index/type/_search/
{
  "query": {
    "term": {
      "title": "blog"
    }
  }
}

terms 查询某个字段里含有多个关键词的文档
GET /index/type/_search/
{
  "query": {
    "terms": {
      "title": [ "blog","first"]
    }
  }
}


//分页,默认情况下,es一次展示10条数据,通过from和size来控制分页
GET goods/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 100
}

//ElasticSearch两个数据类型
text:会分词,不支持聚合
keyword:不会分词,将全部内容作为一个词条,支持聚合
term查询:不会对查询条件进行分词。
GET goods/_search
{
  "query": {
    "term": {
      "title": {
"type":"text",
        "value": "华为"
      }
    }
  }
}


//match查询:
会对查询条件进行分词。
然后将分词后的查询条件和词条进行等值匹配,默认取并集(OR)
# match查询
GET goods/_search
{
  "query": {
    "match": {
      "title": "华为手机"
    }
  },
  "size": 500
}

例如:华为手机,会分词为 “华为”,“手机” 只要出现其中一个词条都会搜索到
term query会去倒排索引中寻找确切的term,它并不知道分词器的存在。这种查询适合keyword 、numeric、date
match query知道分词器的存在。并且理解是如何被分词的

//模糊查询-脚本,wildcard查询
wildcard查询:会对查询条件进行分词。还可以使用通配符 ?(任意单个字符) 和 * (0个或多个字符)
"*华*"  包含华字的
"华*"   华字后边多个字符
"华?"  华字后边多个字符
"*华"或"?华" 会引发全表(全索引)扫描 注意效率问题
# wildcard 查询。查询条件分词,模糊查询
GET goods/_search
{
  "query": {
    "wildcard": {
      "title": {
        "value": "华*"
      }
    }
  }
}

//正则查询
\W:匹配包括下划线的任何单词字符,等价于 [A-Z a-z 0-9_]   开头的反斜杠是转义符
+号多次出现
(.)*为任意字符
正则查询取决于正则表达式的效率

GET goods/_search
{
  "query": {
    "regexp": {
      "title": "\\w+(.)*"
    }
  }
}

//前缀查询
# 前缀查询 对keyword类型支持比较好
GET goods/_search
{
  "query": {
    "prefix": {
      "brandName": {
        "value": "三"
      }
    }
  }
}

//范围&排序查询
# 范围查询

GET goods/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 2000,
        "lte": 3000
      }
    }
  },
  "sort": [
    {
      "price": {
        "order": "desc"
      }
    }
  ]
}

//queryString查询
queryString 多条件查询
•会对查询条件进行分词。
•然后将分词后的查询条件和词条进行等值匹配
•默认取并集(OR)
•可以指定多个查询字段
query_string:识别query中的连接符(or 、and)
simple_query_string:不识别query中的连接符(or 、and),查询时会将 “华为”、"and"、“手机”分别进行查询
query_string:有default_operator连接符的脚本

//布尔查询-脚本
boolQuery:对多个查询条件连接。连接方式:
•must(and):条件必须成立
•must_not(not):条件必须不成立
•should(or):条件可以成立
filter:条件必须成立,性能比must高。不会计算得分

得分:即条件匹配度,匹配度越高,得分越高
# boolquery
#must和filter配合使用时,max_score(得分)是显示的
#must 默认数组形式
GET goods/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "brandName": {
              "value": "华为"
            }
          }
        }
      ],
      "filter":[
        {
        "term": {
          "title": "手机"
        }
       },
       {
         "range":{
          "price": {
            "gte": 2000,
            "lte": 3000
         }
         }
       }
     
      ]
    }
  }
}

//聚合查询-脚本
•指标聚合:相当于MySQL的聚合函数。max、min、avg、sum等
•桶聚合:相当于MySQL的 group by 操作。不要对text类型的数据进行分组,会失败。
# 聚合查询
# 指标聚合 聚合函数
GET goods/_search
{
  "query": {
    "match": {
      "title": "手机"
    }
  },
  "aggs": {
    "max_price": {
      "max": {
        "field": "price"
      }
    }
  }
}

# 桶聚合  分组
GET goods/_search
{
  "query": {
    "match": {
      "title": "手机"
    }
  },
  "aggs": {
    "goods_brands": {
      "terms": {
        "field": "brandName",
        "size": 100
      }
    }
  }
}

//高亮三要素:
•高亮字段
•前缀
•后缀
默认前后缀 :em
GET goods/_search
{
  "query": {
    "match": {
      "title": "电视"
    }
  },
  "highlight": {
    "fields": {
      "title": {
        "pre_tags": "<font color='red'>",
        "post_tags": "</font>"
      }
    }
  }
}


//_source中的内容就是搜索api返回的内容
Elasticsearch里面有2份内容,一份是原始文档,也就是_source字段里的内容,我们在Elasticsearch中搜索文档,查看的文档内容就是_source中的内容。
另一份是倒排索引,倒排索引中的数据结构是倒排记录表,记录了词项和文档之间的对应关系


//boost


Filter Context
{
    "query":{
        "bool":{
            "filter":{
                "term":{
                    "word_count":1000
                }
            }
        }
    }  
}
在查询过程中,只判断该文档是否满足条件,只有Yes或者No。

固定分数查询
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "title":"elastic search"
                }
            },
            "boost":2 //固定分数查询
        }
    }
}


wildcard 检索可以定义为:支持通配符的模糊检索。类似 Mysql 中的 like 模糊匹配
wildcard 可能的风险,中文含义是:避免以*或?开头的模式。这会增加查找匹配项所需的迭代次数并降低搜索性能。






GET midea~plm~com.midea.part.model.mtpart/_search
{
  "query": {
    "match_all": {"defaultUnit":"Piece"}
  }
}


GET midea~plm~com.midea.part.model.mtpart/_search
{
  "query": {
    "match": {"fullText_zh_CN":"黑色"}
  }
}


查询所有的索引
GET /_cat/indices?v



termsQuery

ignore_above用于设置超过指定字符后,超出的部分不能被索引或者存储
在ElasticSearch中keyword类型字段可以设置ignore_above属性(默认是10) ,表示最大的字段值长度,超出这个长度的字段将不会被索引,但是会存储。
ES 5.X版本以后,keyword支持的最大长度为32766个UTF-8字符,text对字符长度没有限制


ES与关系型数据库对比
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields


GET _search
{
  "query": {
    "match_all": {}
  }
}

GET /_cat/indices?v



复制replica:
网络传输的情况下,故障可能会随时发生,有一个故障恢复机制是必须的,所以ES允许你制作一个或多个副本。复制的两个主要原因
(1)高可用。它提供了高可用的机制以来防止分片或者节点宕机。为此,绝对不要将一个分片的副本放在跟这个分片相同的机器上。
(2)高并发。它允许你的分片可以提供超出自身吞吐量的搜索服务,搜索行为可以在分片所有的拷贝中并行执行。
一个完整的流程就是,ES客户端在主分片(primary shard)写入数据之后,会将数据同步到其他几个复制分片(replica shard)上去。ES客户端取数据的时候就会在主分片或者复制分片中去读。
  1-ES 集群多个节点,会自动选举一个节点为 master 节点,这个 master 节点其实就是干一些管理的工作的,比如维护索引元数据、负责切换 主分片(primary shard) 和 复制分片(replica shard)身份等。要是 master 节点宕机了,那么会重新选举一个节点为 master 节点。
2-如果某个非 master 节点宕机了,那么此节点上的 primary shard 就没了,那么master 会让 primary shard 对应的 replica shard(注在其他机器上的replica)切换为 primary shard。如果宕机的机器修复了,能让集群恢复正常,但修复后的节点也不再是 primary shard,而是 replica shard。 (上述就是 ElasticSearch 作为一个分布式搜索引擎最基本的架构设计)
————————————————
版权声明:本文为CSDN博主「小K哈哈」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lf18879954995/article/details/109747785


五-3、ES写数据的流程:
(1)客户端选择一个节点node发送请求过去,这个节点node成为协调节点coordinating node
(2)协调节点对document进行路由,将请求转发给对应的节点
(3)实际上的节点上的primary shard处理请求,然后将数据同步到复制节点replica node
(4)协调节点如果发现primary node和所有的replica node都搞定之后,就会返回请求到客户端

五-4、ES读数据过程
(1)客户端选择一个节点node发送请求过去,这个节点node成为协调节点coordinating node
(2)coordinate node 对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮训算法,在primary shard以及所有replica shard 中随机选择一个,让读请求负载均衡,
(3)接受请求的node,返回document给协调节点
(4)协调节点返回给客户端
————————————————
版权声明:本文为CSDN博主「小K哈哈」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lf18879954995/article/details/109747785

五-5、ES搜索数据过程
(1)客户端发送一个请求给协调节点coordinate node
(2)协调节点将搜索的请求转发给所有分片shard对应的primary shard 或replica shard
(3)搜索阶段query phase:每一个分片shard 将自己搜索的结果(其实也就是一些唯一标识),返回给协调节点,有协调节点进行数据的合并,排序,分页等操作,产出最后的结果
(4)拉取阶段fetch phase ,接着由协调节点,根据唯一标识去各个节点进行拉取数据,最终返回给客户端

五-6、搜索的底层原理
(1)查询过程大体上分为查询和取回这两个阶段,广播查询请求到所有相关分片,并将它们的响应整合成全局排序后的结果集合,这个结果集合会返回给客户端。
(2)查询阶段:当一个节点接收到一个搜索请求,这个节点就会变成协调节点,第一步就是将广播请求到搜索的每一个节点的分片拷贝,查询请求可以被某一个主分片或某一个副分片处理,协调节点将在之后的请求中轮训所有的分片拷贝来分摊负载。每一个分片将会在本地构建一个优先级队列,如果客户端要求返回结果排序中从from 名开始的数量为size的结果集,每一个节点都会产生一个from+size大小的结果集,因此优先级队列的大小也就是from+size,分片仅仅是返回一个轻量级的结果给协调节点,包括结果级中的每一个文档的ID和进行排序所需要的信息。协调节点将会将所有的结果进行汇总,并进行全局排序,最总得到排序结果。
(3)取值阶段:查询过程得到的排序结果,标记处哪些文档是符合要求的,此时仍然需要获取这些文档返回给客户端。协调节点会确定实际需要的返回的文档,并向含有该文档的分片发送get请求,分片获取的文档返回给协调节点,协调节点将结果返回给客户端。
————————————————
版权声明:本文为CSDN博主「小K哈哈」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lf18879954995/article/details/109747785


ES主从同步
1.主分片执行操作成功,转发请求到相应的从分片中,所有从分片成功回应后,表示操作完成,回应客户端
默认replication为sync,同步复制

数据怎么从Primary复制到Replica?
一次写入要求所有副本都成功吗? (YES)
Primary挂掉会丢数据吗?
数据从Replica读,总是能读到最新数据吗?可能会是旧的,副本不可用时,会告诉master那个副本不能用了,同步好meta信息后读请求不会再到这个分片
故障恢复时,需要拷贝Shard下的全部数据吗?
可以看到,对于ES中的数据一致性,虽然我们可以很容易的了解到其大概原理,但是对其细节我们还有很多的困惑。那么本文就从ES的写入流程,
采用的一致性算法,SequenceId和Checkpoint的设计等方面来介绍ES如何工作,进而回答上述这些问题。
https://zhuanlan.zhihu.com/p/35285514
https://zhuanlan.zhihu.com/p/34669354



ES原理之选主流程
ES使用的是Bully算法,并对其做了一些优化:
每个节点结算最小的ID,把它选举为临时Master,然后对该master进行投票;
每个节点收集票数,当票数大于指定的法定个数时,成为Master,然后对加入的节点进行集群信息广播。

流程
ping所有节点,并获取PingResponse返回结果(findMaster)
过滤出具有Master资格的节点(filterPingResponses)
选出临时Master。根据PingResponse结果构建两个列表:activeMasters和masterCandidates。
如果activeMasters非空,则从activeMasters中选择最合适的作为Master;
如果activeMasters为空,则从masterCandidates中选举,结果可能选举成功,也可能选举失败。
判断临时Master是否是本节点。
如果临时Master是本节点:则等待其他节点选我,默认30秒超时,成功的话就发布新的clusterState。(当选总统候选人,只等选票过半了)
如果临时Master是其他节点:则不再接受其他节点的join请求,并向Master节点发送加入请求。(没资格选举,就只能送人头了)


















分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics