概叙
Elasticsearch是什么?
Elasticsearch(简称ES)是一个分布式、
而 Elasticsearch 中,这个 Quorum 的配置就是 discovery.zen.minimum_master_nodes 。用户可以看到最相关的文档排在最前面,这使得用户能够快速有效地找到他们需要的信息。在Luence中的段有不变性,也就是说段一旦生成,在其上只能有读操作,不能有写操作。文本分析可以帮助 Elasticsearch 更准确地匹配搜索关键字和文档内容。
通过这种方式当断电或需要重启时,ES 不仅要根据提交点去加载已经持久化过的段,还需要工具 Translog 里的记录,把未持久化的数据重新持久化到磁盘上,避免了数据丢失的可能。
内存回收:主节点的角色既为 Master 又为 Data,当 Data 节点上的 ES 进程占用的内存较大,引发 JVM 的大规模内存回收,造成 ES 进程失去响应。你可能会发现没有 3.x 和 4.x,ES 从 2.4.6 直接跳到了 5.0.0。
分片请求缓存:数据节点上的分片请求缓存可以存储查询请求的结果。
内存中的数据被写入到一个新段同时被写入到文件缓存系统,文件系统缓存中数据通过 Fsync 刷新到磁盘中,生成提交点,日志文件被删除,创建一个空的新日志。不适合做复杂聚合,会影响ES集群性能。
每条记录称为一个倒排项(Posting)。总量等。下图中由词典和倒排序两部分组成,其中的词典就是Term的集合。每个数据节点上都存储着一部分索引的数据,并负责处理与这些数据相关的查询请求。只要文件系统缓存中还有足够的空间,那么大部分读请求会直接请求内存,而不会命中磁盘。这样做既能防止脑裂现象的发生,也能最大限度地提升集群的高可用性,因为只要不少于 discovery.zen.munimum_master_nodes 个候选节点存活,选举工作就能正常进行。节点使用发现机制通过 Ping 的方式查找其他节点。
减少映射字段,只提供需要检索,聚合或排序的字段。在内存中用 FST 方式压缩 Term Index,FST 以字节的方式存储所有的 Term,这种压缩方式可以有效的缩减存储空间,使得 Term Index 足以放进内存,但这种方式也会导致查找时需要更多的 CPU 资源。
7.返回结果给客户端
一旦结果准备好,协调节点会将它们封装成一个统一的响应格式,并返回给客户端。
真实的倒排记录也并非一个链表,而是采用了SkipList、实时的搜索与数据分析引擎。
因为索引是基于文档建立的,若是有新的文档加入,直接为该文档建立一个新的索引块,挂接在原来索引文件的后面。节点失效检测等。
我们会将 S0 的副本分片提升为主分片,这个提升主分片的过程是瞬间发生的。一个索引文件由一个或者多个段组成。条带化 RAID 会提高磁盘 I/O,代价显然就是当一块硬盘故障时整个就故障了。
刷新操作是周期性的,可以通过配置来控制刷新的频率。追踪集群中节点的状态等,稳定的主节点对集群的健康是非常重要的。
数据同步是异步进行的,这意味着写入请求在主分片处理完毕后就可以返回给客户端,而不需要等待所有副本分片都完成同步。
性能优化
存储设备
磁盘在现代服务器上通常都是瓶颈。这有助于减少对磁盘I/O的依赖,提高查询速度。这样做可以释放内存空间,并为后续的写入操作做好准备。这个配置在 elasticsearch.yml 文件中:
discovery.zen.ping.unicast.hosts: ["host1", "host2:port"]
节点启动后先 Ping ,如果 discovery.zen.ping.unicast.hosts 有设置,则 Ping 设置中的 Host ,否则尝试 ping localhost 的几个端口。词典的数据结构可以有很多种,每种都有自己的优缺点,比如:排序数组通过二分查找来检索数据:HashMap(哈希表)比排序数组的检索速度更快,但是会浪费存储空间;fst(finite-state transducer)有更高的数据压缩率和查询效率,因为词典是常驻内存的,而fst有很好的压缩率,所以fst在Lucene的最新版本中有非常多的使用场景,也是默认的词典数据结构。在读取数据时,Elasticsearch利用协调节点将请求路由到正确的数据节点,利用Lucene进行高效检索,并聚合、
这棵树不会包含所有的 Term,它包含的是 Term 的一些前缀。67的文章中出现过,elasticsearch和solr同理。RESTful 风格的搜索和数据分析引擎,它底层基于 Apache Lucene
开源库进行封装,其不仅仅提供分布式多用户能力的全文搜索引擎。为了充分发挥其功能,你需要使用Java并将Lucene直接集成到应用程序中。
统一之后,我们选版本就不会犹豫困惑了,我们选定 Elasticsearch 的版本后再选择相同版本的 Kibana 就行了,不用担忧版本不兼容的问题。
2、同时,借助Lucene的强大索引能力,将文档快速转换成可被搜索的形式。磁盘处理能力不足、
使用 RAID 0。这种非结构化数据的处理需要依赖全文搜索,而目前市场上开放源代码的最好全文检索引擎工具包就属于 Apache 的 Lucene了。
Keyword 用于索引结构化内容的字段,例如电子邮件地址,主机名,状态代码,邮政编码或标签。索引与搜索技术、数据节点会根据查询条件在Lucene索引中检索匹配的文档,并生成一个结果集。
段合并的时候会将那些旧的已删除文档从文件系统中清除。这时新数据还不能被检索和查询。
接收到请求的节点会充当协调节点的角色。
当一个节点联系到单播列表中的成员时,它就会得到整个集群所有节点的状态,然后它会联系 Master 节点,并加入集群。
通过这种方式,Elasticsearch支持复杂的全文搜索功能,广泛应用于各种场景中,如日志分析、
4. 将请求转发给数据节点
协调节点根据分片的位置信息将查询请求转发给包含目标分片的数据节点。
3、只有在同一台机器上运行的节点才会自动组成集群。这时虽然新段未被提交到磁盘,但是可以提供文档的检索功能且不能被修改。
ElasticSearch 搜索整体架构如下图所示:

ElasticSearch特点
优点:
1、这个过程可能需要消耗一定的计算资源,特别是当结果集很大时。无法足够快的响应客户端的请求等,一个节点可能不够。
协调节点在收到所有分片返回的结果后,会进行结果的合并和排序,并将最终的结果返回给客户端。
它提供单播和基于文件的发现,并且可以扩展为通过插件支持云环境和其他形式的发现。
具体的存储路径可在配置文件 ../config/elasticsearch.yml 中进行设置,默认存储在安装目录的 Data 文件夹下。改、
queryParser模块:主要负责语法分析,把我们的查询语句生成Lucene底层可以识别的条件。而旧数据只能等到段更新时才能被移除,这样会造成大量的空间浪费。段合并的计算量庞大, 而且还要吃掉大量磁盘 I/O,段合并会拖累写入速率,如果任其发展会影响搜索性能。S3)和 8 个副本分片(R0、
倒排索引也可以称反向索引,倒排索引是搜索引擎到核心,主要包括两部分:
(1)单词词典(Term Dictionary)
记录所有文档的单词,一般都比较大
记录单词到倒排列表的关联信息(文档ID)
(2)倒排列表(Posting List):
记录了单词对应的文档集合,由倒排索引项(Posting)组成
单词词典的实现一般是 B+ Tree
倒排索引项(Posting)主要包含如下信息:
1、偏移(Offset),记录单词在文档的开始和结束位置,用于做高亮显示
例子1:

分词和倒排查询时间复杂度都是 O(1),整个搜索的时间复杂度取决于「求list< id>的交集」,因此搜索实际上问题也变成了求两个集合的交集。这些字段是被分词的,它们通过分词器传递 ,以在被索引之前将字符串转换为单个术语的列表。
5.2. 刷新(Refresh)操作
随着时间的推移,缓冲区中的数据会积累到一定量,此时需要将这些数据刷新(refresh)到Lucene的索引中。
可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就会被移除。
- 角色分离。Translog是一个追加写入的日志文件,它记录了所有对索引的更改。
- 当达到默认的刷新时间或内存中的数据达到一定量后,会触发一次 Refresh,将内存中的数据以一个新段形式刷新到文件缓存系统中并清空内存。
段的概念提出主要是因为:在早期全文检索中为整个文档集合建立了一个很大的倒排索引,并将其写入磁盘中。
虽然对节点做了角色区分,但是用户的请求可以发往任何一个节点,并由该节点负责分发请求、
- 副本越多,集群的可用性就越高,但是由于每个分片都相当于一个 Lucene 的索引文件,会占用一定的文件句柄、写入速率和磁盘I/O能力等因素来动态调整。
这些分数用于对结果进行排序,以确保最相关的结果排在最前面。
目前以 Lucene 为基础建立的开源可用全文搜索引擎主要是 Solr 和 Elasticsearch。
“脑裂”问题可能有以下几个原因造成:
- 网络问题:集群间的网络延迟导致一些节点访问不到 Master,认为 Master 挂掉了从而选举出新的 Master,并对 Master 上的分片和副本标红,分配新的主分片。它们不需要在每次数据改变时被重建,因为数据不会变化。
段的不变性的缺点如下:
- 当对旧数据进行删除时,旧数据不会马上被删除,而是在 .del 文件中被标记为删除。
所以,Elasticsearch的架构结合了分布式处理、
合并结束后老的段会被删除,新的段被 Flush 到磁盘,同时写入一个包含新段且排除旧的和较小的段的新提交点,新的段被打开可以用来搜索。排序结果,最终返回给客户端。
像 B+ 树一样,可以在页里实现二分查找。删除索引、
对于存储在磁盘上的倒排表同样也采用了压缩技术减少存储所占用的空间。内存和 CPU 运行周期。
不管是 Solr 还是 Elasticsearch 底层都是依赖于 Lucene,而 Lucene 能实现全文搜索主要是因为它实现了倒排索引的查询结构。
在讲解动态映射和静态映射的使用前,我们先来了解下 ES 中的数据有哪些字段类型?之后我们再讲解为什么我们创建索引时需要建立静态映射而不使用动态映射。

在这张图中,你可以看到一个示例数据“The cat in the tree”,这段文本被转换成 JSON 格式并准备导入到 Elasticsearch 中。
- 节点负载:主节点的角色既为 Master 又为 Data,访问量较大时可能会导致 ES 停止响应(假死状态)造成大面积延迟,此时其他节点得不到主节点的响应认为主节点挂掉了,会重新选取主节点。通过 Term Index 可以快速地定位到 Term Dictionary 的某个 Offset,然后从这个位置再往后顺序查找。是根据词条找文档的过程。这提供了很大的性能提升。
3、将搜索的文档最终以Document方式存储起来。
2、文档有一个或多个域组成,每个域拥有一个名字及一个或多个值,有多个值的域通常被称为 多值域,每个文档可以存储不同的域集,但同一类型下的文档至应该有某种程度上的相似之处。协调节点负责处理客户端的请求,并将请求路由到正确的数据节点。内存和 I/O 的消耗很大。为了实现这些功能,Elasticsearch采用了分片和副本的机制,使得数据可以分布在多个节点上,并且具有容错性和可扩展性。当段的数量太多时,对服务器的资源例如文件句柄的消耗会非常大。删除、
在我们关系型库中索引为了兼顾插入和查询的性能,都采用了排序树例如:B-Tree/B+Tree这样的数据结构来存储索引。每个字段的数据类型。Lucene是一个高性能、收集结果等操作,而不需要主节点转发。删、当 refresh_interval=-1 时表示关闭索引的自动刷新。这种架构提高了系统的扩展性和容错能力。而且并不是所有的情况都需要每秒刷新。
为了提升写的性能,ES 并没有每新增一条数据就增加一个段到磁盘上,而是采用延迟写的策略。
一个 索引 可以存储超出单个结点硬件限制的大量数据。es读取数据流程
下面来解释Elasticsearch读取数据的流程,包括其中的关键步骤和涉及的组件。R1、
同时,为了确保数据的持久性和可靠性,每一个写入操作也会被记录到事务日志(Translog)中。ik_maxword等模式
- 可自定义词库,支持热更新分词词典
- https://github.com/medcl/elasticsearch-analysis-ik
- jieba
- python中最流行的分词系统,支持分词和词性标注
- 支持繁体分词、
如果 Node1 依然拥有着之前的分片,它将尝试去重用它们,只不过这时 Node1 节点上的分片不再是主分片而是副本分片了,如果期间有更改的数据只需要从主分片上复制修改的数据文件即可。
- 如果你的搜索结果不需要近实时的准确度,考虑把每个索引的 index.refresh_interval 改到 30s 。
- ES1 节点将请求转发到 S0 主分片所在的节点 ES3,ES3 接受请求并写入到磁盘。故障恢复和读取负载均衡。相当于 mysql 表中的 row 。

打分机制通常依赖于因素如关键词的出现频率、
5. 在数据节点上执行查询
数据节点接收到查询请求后,会使用Lucene库来执行实际的搜索操作。负载均衡、
例子2:

为了创建倒排索引,我们通过分词器将每个文档的内容域拆分成单独的词(我们称它为词条或 Term),创建一个包含所有不重复词条的排序列表,然后列出每个词条出现在哪个文档。不要使用镜像或者奇偶校验 RAID 因为副本已经提供了这个功能。
5、
- 并发将数据复制到两个副本分片 R0 上,其中通过乐观并发控制数据的冲突。
五、Lucene的写流程和读流程

Lucene的写流程和读流程
其中,虚线箭头(a、es的数据写入流程与原理
在写入数据时,Elasticsearch遵循以下原理和步骤:

1. 客户端请求与协调节点
客户端向Elasticsearch集群发送一个写入请求,这个请求可以发送到集群中的任何一个节点。
这一步骤是通过Elasticsearch 的分词器完成的,它将文本拆分成更易于搜索的单词或短语,即“tokens”。聚合数据(如果有的话)等信息。

Lucene的底层存储格式
如上图所示:的词典部分包含三个词条(Term):elasticsearch、
索引文件分段存储并且不可修改,那么新增、可扩展、
过滤器是一种能够过滤掉不符合条件的文档的查询方式,它可以用来限定搜索结果的数量和质量。
所以创建索引的时候一个完整的格式应该是指定分片和副本数以及 Mapping 的定义,如下:
PUT my_index { "settings" : { "number_of_shards" : 5, "number_of_replicas" : 1 } "mappings": { "_doc": { "properties": { "title": { "type": "text" }, "name": { "type": "text" }, "age": { "type": "integer" }, "created": { "type": "date", "format": "strict_date_optional_time||epoch_millis" } } } } }
三、Node:节点
形成集群的每个服务器称为节点。被删除的文档不会被拷贝到新的大段中。
调整配置参数
调整配置参数建议如下:
- 给每个文档指定有序的具有压缩良好的序列模式 ID,避免随机的 UUID-4 这样的 ID,这样的 ID 压缩比很低,会明显拖慢 Lucene。
Routing 通过 Hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到余数。
虽然通过延时写的策略可以减少数据往磁盘上写的次数提升了整体的写入能力,但是我们知道文件缓存系统也是内存空间,属于操作系统的内存,只要是内存都存在断电或异常情况下丢失数据的危险。
默认情况下每个分片会每秒自动刷新一次。这可以减少对Lucene索引的重复访问,提高查询性能。高性能、
2、内存及 CPU。一般来说,类型就是为那些拥有相同的域的文档做的预定义。
Elasticsearch 默认被配置为使用单播发现,以防止节点无意中加入集群。聚合、
Lucene官网地址:Apache Lucene - Welcome to Apache Lucene
鉴于Lucene如此强大却难以上手的特点,诞生了ES。词典中的Term指向的文档链表的集合,叫做倒排表。但是,在Elasticsearch中,flush操作是自动管理的,会根据索引的大小、15、若是有文档删除,则直接找到该文档号文档对应的索引信息,将其直接删除。
Lucene 的实现会要更加复杂,针对不同的数据结构采用不同的字典索引,使用了FST模型、
通过对生活中数据的类型作了一个简短了解之后,我们知道关系型数据库的 SQL 检索是处理不了这种非结构化数据的。相反,当段在内存中时,就只有写的权限,而不具备读数据的权限,意味着不能被检索。
为了避免丢失数据,Elasticsearch 添加了事务日志(Translog),事务日志记录了所有还没有持久化到磁盘的数据。 全文索引就是把内容根据词的意义进行分词,然后分别创建索引,例如”你们的激情是因为什么事情来的” 可能会被分词成:“你们“,”激情“,“什么事情“,”来“ 等token,这样当你搜索“你们” 或者 “激情” 都会把这句搜出来。
段合并:为了优化存储和搜索性能,Lucene会定期进行段合并(Segment Merging)操作。Lucene 的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。其他节点也通过 Ping 的方式判断主节点是否处于可用状态。
如果采用动态映射是不能精确做到这些的,自动识别常常会与我们期望的有些差异。排序速度非常快
缺点:
根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。
由内存刷新到文件缓存系统的时候会生成新的段,并将段打开以供搜索使用,而不需要等到被刷新到磁盘。其他字段可存在其他存储设备上,例如 Hbase,在 ES 中得到结果后再去 Hbase 查询这些字段。d)表示写索引的主要过程,实线箭头(1-9)表示查询的主要过程。天生索引,ES 所有数据都是默认进行索引的,这点和mysql正好相反,mysql是默认不加索引,要加索引必须特别说明,ES只有不加索引才需要说明。Lucene构建倒排索引(Inverted Index)来加速搜索过程。
为了解决这个问题,Elasticsearch 提供了将索引划分成多份的能力,这些份就叫做 分片。缓存和优化策略

优化策略
查询缓存:Elasticsearch会对某些查询结果进行缓存,以便快速响应相同的查询请求。分页等处理。文档中的位置等。正向索引
正排表是以文档的 ID 为关键字,表中记录文档中每个 Term 的位置信息,查找时扫描表中每个文档中 Term 的信息直到找出所有包含查询关键字的文档。
- 若有一条数据频繁的更新,每次更新都是新增新的标记旧的,则会有大量的空间浪费。
存储原理
上面介绍了在 ES 内部索引的写处理流程,这个流程是在 ES 的内存中执行的,数据被分配到特定的分片和副本上之后,最终是存储到磁盘上的,这样在断电的时候就不会丢失数据。
2、
如果索引有更新,就需要重新全量创建一个索引来替换原来的索引。由于每个分片都只需要检索自己本地的数据,因此 Elasticsearch 具有很高的横向扩展能力,可以处理大规模数据的搜索和分析任务。这就是为什么我们说 Elasticsearch 是近实时搜索,因为文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。别忘记在完工的时候重新开启它。
ES 为了提高写入的能力这个过程是并发写的,同时为了解决并发写的过程中数据冲突的问题,ES 通过乐观锁的方式控制,每个文档都有一个 _version (版本)号,当文档被修改时版本号递增。
什么是 Document(文档)?
文档是 Lucene 索引和搜索的 原子单位,它是包含了一个或多个域的容器,基于 Json 格式进行表示。
Lucene中的核心术语
ElasticSearch核心技术分词与倒排索引都是基于Lucene实现的。查和聚合等操作,所以数据节点(Data 节点)对机器配置要求比较高,对 CPU、
不断有新的文档被写入到内存,同时也都会记录到事务日志中。数据写入与持久化机制以及缓存与性能优化策略等多个方面来实现高效、
Cluster:集群,ES可以作为一个独立的单个搜索服务器。
- 随着新文档索引不断被写入,当日志数据大小超过 512M 或者时间超过 30 分钟时,会触发一次 Flush。这等等
- 其组成如图,特性为:
- 相比Simple Analyzer多了stop Word处理
Keyword Analyzer Pattern Analyze - 其组成如下,特性为:
- 通过正则表达式自定义分隔符
- 默认是\W+,即非字词的符号作为分隔符
language Analyze - 提供了30+常见语言的分词器
- Arabic,Armenian,basque,bengali,Brazilian,Bulgarian,catAlan,cjk,Czech,Danish,Dutch,English...
中文分词
- 难点
- 中文分词指的是将一个汉字序列切分成一个一个单独的词。最小值、
这整个过程不仅高效而且具有很高的可扩展性,使Elasticsearch成为处理大规模数据集的理想选择。更新和删除如何处理呢?
- 新增,新增很好处理,由于数据是新的,所以只需要对当前文档新增一个段就可以了。

Lucene 的倒排索引,增加了最左边的一层「字典树」term index,它不存储所有的单词,只存储单词前缀,通过字典树找到单词所在的块,也就是单词的大概位置,再在块里二分查找,找到对应的单词,再找到单词对应的文档列表。
1、地理位置和对象间关联关系等。
- 倒排表(Post list):一个文档通常由多个词组成,倒排表记录的是某个词在哪些文档里出现过以及出现的位置。
每一个段都会消耗文件句柄、
查询执行:当客户端发送搜索请求时,请求首先到达一个协调节点。Elasticsearch 重度使用磁盘,你的磁盘能处理的吞吐量越大,你的节点就越稳定。ES不仅仅只是全文搜索,还支持结构化搜索、例如在以下的应用场景中,都会使用到es
- 在Github上搜索代码
- 在电商网站搜索商品
- 在百度搜索答案
- 在打车软件搜索附近的车(具体这个为什么后续系列会详细说明的)
ES 的版本问题
在决定使用 Elasticsearch 的时候首先要考虑的是版本问题,Elasticsearch (排除 0.x 和 1.x)目前有如下常用的稳定的主版本:2.x,5.x,6.x,7.x(current)。
Elasticsearch 还提供了一些功能来实现自动化的扩展和负载均衡,例如:自动分片、
确定目标主分片后,协调节点将请求转发给该主分片所在的数据节点。
通过这个底层写入机制,Elasticsearch能够在保证数据可靠性的同时提供高效的搜索和分析功能。当主分片不可用时,副本分片可以被提升为新的主分片。Tokenizer Filter实现
- Character Filters
- 在Tokenizer之前对原始文本进行处理,比如增加、
这时可以在创建索引时在 Settings 中通过调大 refresh_interval = "30s" 的值 , 降低每个索引的刷新频率,设值时需要注意后面带上时间单位,否则默认是毫秒。倒排索引

逻辑结构部分是一个倒排索引列表:
1、
基于这些详细的步骤和优化策略,Elasticsearch能够高效地处理读取数据的请求,并提供快速、
正向索引:
优点:
可以给多个字段创建索引
根据索引字段搜索、ES中可以有许多相同的分片,其中之一被选择更改索引操作,这种特殊的分片称为主分片。Elasticsearch写索引原理
写入流程:当文档被写入Elasticsearch时,它们首先被放置在内存中的一个缓冲区中,并同时记录到事务日志(Translog)中以确保数据的持久性。倒排索引将文档中的单词映射到包含这些单词的文档列表,从而实现快速查找和检索。这意味着数据被真正写入到了物理存储中,而不仅仅是保存在操作系统的文件系统缓存中。
6.聚合和排序结果
数据节点将查询结果返回给协调节点。全功能的文本搜索引擎库,它提供了强大的索引和搜索功能。ES也是使用Java编写的,它的内部使用Lucene做索引与搜索,它的目的是隐藏Lucene的复杂性,取而代之的提供一套简单一致的RESTful API。
这就解释了为什么我们要在创建索引的时候就确定好主分片的数量并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。Doc Values 是有序的基于 document=>field value 的映射列表。
因此为了提高集群的健康性,我们应该对 Elasticsearch 集群中的节点做好角色上的划分和隔离。35、

添加了事务日志后整个写索引的流程如上图所示:
- 一个新文档被索引之后,先被写入到内存中,但是为了防止数据的丢失,会追加一份数据到事务日志中。
优化策略:为了提高性能,Elasticsearch还提供了多种优化策略,如使用合适的分析器(Analyzer)和查询语句、事务日志、
- search模块:主要负责对索引的搜索工作。模糊搜索时,速度非常快
缺点:
只能给词条创建索引,而不是字段
无法根据字段做排序Elasticsearch 的基本概念
首先,从架构的角度来看,Elasticsearch是一个分布式的搜索和分析引擎,它能够存储、这个过程通常涉及将数据格式化为 JSON 格式,因为 Elasticsearch 使用 JSON 作为数据交换格式。可靠和可扩展的数据写入功能。
- 写入单个大的倒排索引允许数据被压缩,减少磁盘 I/O 和需要被缓存到内存的索引的使用量。
那么在 Kibana 的下一主版本肯定是 5.x 了,所以 Elasticsearch 直接将自己的主版本发布为 5.0.0 了。其实是为了 ELK(ElasticSearch,Logstash,Kibana)技术栈的版本统一,免的给用户带来混乱。因此,一个索引内部可定义一个或多个类型(type)。
elasticsearch的作用
elasticsearch(es)是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容。自定义词典、这些段是不可变的,一旦被写入就不能被修改。
- 更新,不能修改旧的段来进行反映文档的更新,其实更新相当于是删除和新增这两个动作组成。即是上面我们提到的候选主节点和数据节点进行角色分离,这样可以减轻主节点的负担,防止主节点的假死状态发生,减少对主节点“已死”的误判。当写测试的时候, 手动刷新很有用,但是不要在生产>环境下每次索引一个文档都去手动刷新。
- ▪️Term:是索引里最小的存储和查询单元,对于英文来说一般是指一个单词,对于中文来说一般是指一个分词后的词。而段数目太多会带来较大的麻烦。这是因为 Elasticsearch 采用了一种倒排索引(Inverted Index)的数据结构,它可以快速地找到符合搜索条件的文档。
候选主节点可以被选举为主节点(Master 节点),集群中只有候选主节点才有选举权和被选举权,其他节点不参与选举的工作。当相同的查询再次到达时,可以直接从缓存中获取结果,而无需再次访问Lucene索引。
这个在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。倒排表是每个单词所对应的文档编号列表,每个文档编号都按照某种方式排序,以便支持更快地搜索和排名计算。S2、
2. 请求到达协调节点
请求首先到达Elasticsearch集群中的一个节点,这个节点被称为协调节点(Coordinating Node)。每个分片放到不同的服务器上。
官网地址:Elastic — The Search AI Company | Elastic
ES具有如下特点:
- 一个分布式的实时文档存储引擎,每个字段都可以被索引与搜索
- 一个分布式实时分析搜索引擎,支持各种查询和聚合操作
- 能胜任上百个服务节点的扩展,并可以支持PB级别的结构化或者非结构化数据
ElasticSearch(弹性搜索):是一款开源的分布式、
②延迟写策略
介绍完了存储的形式,那么索引写入到磁盘的过程是怎样的?是否是直接调 Fsync 物理性地写入磁盘?
答案是显而易见的,如果是直接写入到磁盘上,磁盘的 I/O 消耗上会严重影响性能。避免使用高开销的查询操作(如通配符查询、
Solr 和 Elasticsearch 都是比较成熟的全文搜索引擎,能完成的功能和性能也基本一样。刷新和flush操作等机制,确保了数据的可靠性与持久性。
5.3. Flush操作
与刷新不同,flush操作会将内存中的数据以及Translog中的更改持久化到磁盘上。
ES(v6.8)中字段数据类型主要有以下几类:

Text 用于索引全文值的字段,例如电子邮件正文或产品说明。
②节点的角色
每个节点既可以是候选主节点也可以是数据节点,通过在配置文件 ../config/elasticsearch.yml 中设置即可,默认都为 true。
这类似于 MySQL 的分库分表,只不过 MySQL 分库分表需要借助第三方组件而 ES 内部自身实现了此功能。分布式的处理过程。频繁的刷新会提高数据的实时性,但也会增加I/O负担和CPU使用率;而较少的刷新则会减少I/O操作,但可能会降低数据的实时性。
Node:节点,形成集群的每个服务器称为节点,一个节点可以包含多个shard
3、

1、
1.2 数据的分析和索引
导入Elasticsearch后,数据会被分析和索引。
Elasticsearch 通过在后台定期进行段合并来解决这个问题。词典是所有文档中出现的单词的集合,它以字典序排序。
可能你正在使用 Elasticsearch 索引大量的日志文件, 你可能想优化索引速度而不是>近实时搜索。
并且分片间的数据同步也会占用一定的网络带宽,所以索引的分片数和副本数也不是越多越好。
只不过关系型数据库建表时必须指定字段类型,而 ES 对于字段类型可以不指定然后动态对字段类型猜测,也可以在创建索引时具体指定字段的类型。 当你查询的索引分布在多个分片上时,Elasticsearch会把查询发送给每个相关的分片,并将结果组合在一起,而应用程序并不知道分片的存在。
- ES 非常依赖文件系统缓存(Filesystem Cache),快速搜索。在写入数据时,它通过缓冲区、其中IK分词器对中文很好,一般都使用它。会将旧的文档在 .del 文件中标记删除,然后文档的新版本被索引到一个新的段中。BKDTree等结构。
在一个写请求被发送到某个节点后,该节点即为前面说过的协调节点,协调节点会根据路由公式计算出需要写到哪个分片上,再将请求转发到该分片的主分片节点上。协调节点聚合来自各个数据节点的结果,并进行排序、可以使用几个配置较低的机器群作为候选主节点群。但根据词条查询时,必须先逐条获取每个文档,然后判断文档中是否包含所需要的词条,是根据文档找词条的过程。将要搜索的文档内容分词,所有不重复的词组成分词列表。持久化并可以被高效搜索的关键部分:

5.1. 缓冲区(Buffer)和事务日志(Translog)
当文档被写入Elasticsearch时,它们首先被放置在内存中的一个缓冲区中。

从上图可以看出为了达到高可用,Master 节点会避免将主分片和副本分片放在同一个节点上。
总结
Elasticsearch的读写流程是一个精心设计的、
Elasticsearch 支持同一个主机启动多个节点,Ping 的 Response 会包含该节点的基本信息以及该节点认为的 Master 节点。词干提取、这是通过一个哈希函数和模运算来实现的,确保同一个_id的文档总是路由到同一个主分片。
对字段类型根据数据格式自动识别的映射称之为动态映射(Dynamic Mapping),我们创建索引时具体定义字段类型的映射称之为静态映射或显示映射(Explicit Mapping)。

段合并在进行索引和搜索时会自动进行,合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中,这些段既可以是未提交的也可以是已提交的。
实际上,这个过程是根据下面这个公式决定的:
shard = hash(routing) % number_of_primary_shards
Routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。
通常随着集群的扩大,需要增加更多的数据节点来提高性能和可用性。
小结:
- 将数据分片是为了提高可处理数据的容量和易于进行水平扩展,为分片做副本是为了提高集群的稳定性和提高并发量。
①发现机制
那么有一个问题,ES 内部是如何通过一个相同的设置 cluster.name 就能将不同的节点连接到同一个集群的?答案是 Zen Discovery。
副本是一个分片的精确复制,每个分片可以有零个或多个副本。
- 倒排文件(Inverted File):所有单词的倒排列表往往顺序地存储在磁盘的某个文件里,这个文件被称之为倒排文件,倒排文件是存储倒排索引的物理文件。
基于以上这些原理和步骤,Elasticsearch能够实现高效、
大多数解决方案就是设置一个 Quorum 值,要求可用节点必须大于 Quorum(一般是超过半数节点),才能对外提供服务。
则具体流程如下:
- 客户端向 ES1 节点(协调节点)发送写请求,通过路由计算公式得到值为 0,则当前数据应被写到主分片 S0 上。全功能的搜索引擎库。一旦所有的副本分片都报告成功,则节点 ES3 将向协调节点报告成功,协调节点向客户端报告成功。准确的结果给用户。搜索和分析大量数据。
倒排索引:
优点:
根据词条搜索、
Lucene的底层存储格式如下图所示。小的段被合并到大的段,然后这些大的段再被合并到更大的段。
四、在图中,你可以看到数据被存储在不同的服务器上,这有助于分散负载和提高查询效率。写索引原理
下图描述了 3 个节点的集群,共拥有 12 个分片,其中有 4 个主分片(S0、
优化查询语句:为了提高查询性能,用户应该编写高效的查询语句。快速地写入到索引中,并可以被用户查询到。查询类型(如匹配查询、
现在再看起来,似乎和传统数据库通过 B-Tree 的方式类似。
如果我们同样关闭了 Node2 ,我们的程序依然可以保持在不丢失任何数据的情况下运行,因为 Node3 为每一个分片都保留着一份副本。
在 Elasticsearch 是 2.x (2.x 的最后一版 2.4.6 的发布时间是 July 25, 2017) 的情况下,Kibana 已经是 4.x(Kibana 4.6.5 的发布时间是 July 25, 2017)。聚合查询等。
主节点负责创建索引、词典数据是查询的入口,所以这部分数据是以fst的形式存储在内存中的。Cluster:集群
Elasticsearch可以作为一个独立的单个搜索服务器,不过,为了处理大型数据集,实现容错和高可用性,Elasticsearch可以运行在许多互相合作的服务器上。此外,每个分片可以有多个副本(Replica),用于提供数据冗余、内存核 I/O 消耗都很大。协调节点是负责接受请求的 Elasticsearch 节点,它会根据文档的哈希值把它路由到对应的主分片中,主分片再将文档写入自己的本地硬盘。
六、
- 另外,使用多块硬盘,并允许 Elasticsearch 通过多个 path.data 目录配置把数据条带化分配到它们上面。lucene和solr。如果真是这样 ES 也就不会称之为近实时全文搜索引擎了。
Zen Discovery 与其他模块集成,例如,节点之间的所有通信都使用 Transport 模块完成。随着时间的推移或达到一定的条件,缓冲区中的数据会被刷新(Refresh)到Lucene的索引中,形成新的段(Segment)。
JVM 调优
JVM 调优建议如下:
- 确保堆内存最小值( Xms )与最大值( Xmx )的大小是相同的,防止程序在运行时改变堆内存大小。事务日志、
集群(Cluster)
ES 的集群搭建很简单,不需要依赖第三方协调管理组件,自身内部就实现了集群的管理功能。
如果当前节点是 Master ,则开始等待节点数达到 discovery.zen.minimum_master_nodes,然后提供服务。
但分布式系统的问题就出在信息不对等的情况,这时候很容易出现脑裂(Split-Brain)的问题。7、 当主分片丢失时,如:该分片所在的数据不可用时,集群将副本提升为新的主分片。可通过 ../config/jvm.option 文件进行配置,但是最好不要超过物理内存的50%和超过 32GB。
那么当写数据量大的时候会造成 ES 停顿卡死,查询也无法做到快速响应。
分片与副本:为了支持大规模数据,Elasticsearch将索引划分为多个分片(Shard),每个分片可以独立存储和处理数据。正向和倒排

那么为什么一个叫做正向索引,一个叫做倒排索引呢?
正向索引是最传统的,根据id索引的方式。即便是基于 SSD 的 EBS,通常也比本地实例的存储要慢。R3),每个主分片对应两个副本分片,节点 1 是主节点(Master 节点)负责整个集群的状态。过滤器、单词频率(TF, Term Frequency),记录该单词在该文档中的出现次数,用于后续相关性算法
3、分页等处理,最终将结果返回给客户端。
为了避免脑裂现象的发生,我们可以从原因着手通过以下几个方面来做出优化措施:
- Character Filters测试时可以采用如下api:
POST _analyze{"tokenizer":"keyword", #keyword类型的Tokenizer可以直接看到输出结果"char_filter":["html_strip"], #指明要使用的char_filter"text":"<p>I'm so<b>happy</b>!</p>"}
- Tokenizer
- Token Filters
- 对于Tokenizer输出的单词(term)进行增加、分析和计算等操作,例如:计算平均值、an、聚合查询可以帮助我们更深入地理解我们的数据,并提供更好的业务决策支持。修改等操作
- 自带的如下:
- lowercase将所有term转换为小写
- stop删除stop words
- NGram和Edge NGram连词分割
- Synonym添加近义词的term
- Filter测试时可以采用如下api:
POST _analyze{"text":"a hello world","tokenizer":"standard","filter":["stop","lowercase",{"type":"ngram","min_gram":4,"max_gram":4}]}
自定义分词的api
分词使用说明
- 分词会在如下两个时机使用:
- 创建或更新文档时(Index Time),会对相应的文档进行分词处理
- 查询时(Search Time),会对查询语句进行分词
- 索引时分词是通过配置Index Mapping中每个字段的analyzer属性实现的,如下:
查询时分词的指定方式有如下几种:
- 通过index mapping设置search_analyzer实现
PUT test_index{ "mappings":{ "doc":{ "properties":{ "title":{ "type":"text", "analyzer":"whitespace", "search_analyzer":"standard" } } } }}
- 一般不需要特别指定查询时分词器,直接使用索引时分词器即可,否则会出现无法匹配的情况下
分词使用建议
- 明确字段是否需要分词,不需要分词的字段就将type设置为keyword,可以节省空间和提高写性能
- 善用_analyze API,查看文档的具体分词结果
- 动手测试
3、二、全文检索
全文检索就是对一篇文章进行索引,可以根据关键字搜索,类似于mysql里的like语句。文本字段不用于排序,很少用于聚合。
- 每次新增数据时都需要新增一个段来存储数据。
倒排索引将每个唯一的单词映射到包含该单词的所有文档,这在动图中通过连接线和节点表示。
就像字典里的索引页一样,A 开头的有哪些 Term,分别在哪页,可以理解 Term Index是一棵树。这个缓冲区是临时的,用于快速接收并处理写入请求。
- 副本是乘法,越多消耗越大,但也越保险。通过参数 discovery.zen.ping_timeout 设置节点状态的响应时间,默认为 3s,可以适当调大。
1.5 得分和排序
一旦Elasticsearch找到了所有相关的文档,它将基于相关性给这些文档打分。优化查询语句和分布式处理等技术,确保了查询的高性能与低延迟。
但是 ES 本身就具有分布式的特性和易安装使用的特点,而 Solr 的分布式需要借助第三方来实现,例如通过使用 ZooKeeper 来达到分布式协调管理。
5. 底层写入机制
在Elasticsearch中,底层写入机制是确保数据可靠、
Lucene中的主要模块(见图5-1)及模块说明如下:
- analysis:主要负责词法分析及语言处理,也就是我们常说的分词,通过该模块可最终形成存储或者搜索的最小单元Term。水平扩展指的是通过添加新的节点来分散索引和分片的存储,垂直扩展指的是通过升级硬件来提高单个节点的性能。天生分片,天生集群,从ES出生开始就天然的支持分布式的特征,且无需第三方组件,自带。Elasticsearch中的每个索引都被分割成多个分片,并且这些分片可以分布在集群的多个节点上以提高可扩展性和性能。

写索引是只能写在主分片上,然后同步到副本分片。ES耗CPU和内存资源,需要用高配置的机器来搭建集群,使用成本比较高。
在倒排表中,“lucene”指向有序链表3,7,15,30,35,67,表示字符串“lucene”在文档编号为3、支持PB级海量数据实时全文搜索。
Elasticsearch 在默认情况下会对合并流程进行资源限制,所以搜索仍然有足够的资源很好地执行。
如果集群的节点运行在不同的机器上,使用单播,你可以为 Elasticsearch 提供一些它应该去尝试连接的节点列表。
Tips:尽管刷新是比提交轻量很多的操作,它还是会有性能开销。
如果当前节点不是 Master ,则尝试加入 Master 。此外,还有分片请求缓存等机制用于减少不必要的计算和I/O操作。删除或新增等处理
Analyize API
es提供了一个测试分词的api接口,方便验证分词效果,endpoint是_analyze - 可以直接指定analyzer进行测试
- 可以直接指定索引中的字段进行测试
- 可以自定义分词器进行测试
- 直接指定analyzer进行测试,接口如下:
POST _analyze{"analyzer":"standard", #分词器"text":"hello,world" #测试文本}
- 自定义分词器进行测试,接口如下:
POST _analyze{"tokenizer":"standard","filterf":["lowercase"], #自定义analyzer"text":"hello world"}
预定义的分词器
- es自带如下的分词器
- Standard
- Simple
- Whitespace
- Stop
- Keyword
- Pattern
- Language
- Standard Analyzer
- Simple Analyzer
- Whitespace Analyzer
- Stop Analyzer
- Stop Word指语气助词等修饰性的词语,比如the、更糟糕的是,您可能需要获得信息检索学位才能了解其工作原理,因为Lucene非常复杂。
什么是 Field (字段)?
Field 是相当于数据库中的 Column
什么是 Mapping(映射)?
Mapping 是定义文档及其包含的字段如何存储和索引的过程。
主节点和其他节点之间通过 Ping 的方式互检查,主节点负责 Ping 所有其他节点,判断是否有节点已经挂掉。这种机制类似于数据库中的写前日志(WAL)或重做日志(redo log),用于在系统崩溃后恢复数据。
什么是 Type(类型)?
类型是索引内部的逻辑分区(category/partition),然而其意义完全取决于用户需求。这是为了保证数据的冗余和可用性。
- 不要使用远程挂载的存储,比如 NFS 或者 SMB/CIFS。
通过对字段类型的了解我们知道有些字段需要明确定义的,例如某个字段是 Text 类型还是 Keyword 类型差别是很大的,时间字段也许我们需要指定它的时间格式,还有一些字段我们需要指定特定的分词器等等。
假设这时节点 Node1 服务宕机了或者网络不可用了,那么主节点上主分片 S0 也就不可用了。
数据的写入
当一个文档需要写入 Elasticsearch 时,它首先会通过 HTTP 请求发送到一个节点,我们称为协调节点。索引与搜索
Document:文档,指一行数据;
Index:索引,是多个document的集合(和sql数据库的表对应);
倒排索引:Elasticsearch使用Lucene作为其底层的搜索库。刷新和flush操作共同协作,确保数据被正确、
这里有个限制条件就是 discovery.zen.minimum_master_nodes ,如果节点数达不到最小值的限制,则循环上述过程,直到节点数足够可以开始选举。
这个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。
下面是详细的ES工作流程

1.1 数据的导入和解析
在Elasticsearch中,首先需要导入数据。
ES 集群由一个或多个 Elasticsearch 节点组成,每个节点配置相同的 cluster.name 即可加入集群,默认值为 “elasticsearch”。路由的选择需要注意数据的分布均衡。
主分片和对应的副本分片是不会在同一个节点上的,所以副本分片数的最大值是 N-1(其中 N 为节点数)。如果查询涉及多个分片,协调节点需要聚合来自不同分片的结果,并根据需要对结果进行排序、
- 创建索引和查询时指定路由 Routing 值,这样可以精确到具体的分片查询,提升查询效率。
一旦所有的副本分片都报告写成功才会向协调节点报告成功,协调节点向客户端报告成功。c、倒排表记录的不单是文档编号,还存储了词频等信息。
Flush操作会调用操作系统的fsync函数来确保数据被写入磁盘,并且会清空相关的缓存和文件(如Translog)。
PUT /myIndex { "settings" : { "number_of_shards" : 5, "number_of_replicas" : 1 } }
ES 通过分片的功能使得索引在规模上和性能上都得到提升,每个分片都是 Lucene 中的一个索引文件,每个分片必须有一个主分片和零到多个副本。
当达到默认的时间(1 秒钟)或者内存的数据达到一定量时,会触发一次刷新(Refresh),将内存中的数据生成到一个新的段上并缓存到文件缓存系统 上,稍后再被刷新到磁盘中并生成提交点。
3. 数据同步与副本分片
一旦文档被写入到主分片,主分片会开始将数据同步到其对应的副本分片上。
③段合并
由于自动刷新流程每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增。
- store模块:主要负责索引的读写,主要是对文件的一些操作,其主要目的是抽象出和平台文件系统无关的存储。
映射(Mapping)
映射是用于定义 ES 对索引中字段的存储类型、
- 不需要做模糊检索的字段使用 Keyword 类型代替 Text 类型,这样可以避免在建立索引前对这些文本进行分词。
一个 Elasticsearch 服务启动实例就是一个节点(Node)。调大参数(如 6s,discovery.zen.ping_timeout:6),可适当减少误判。
在一个多分片的索引中写入数据时,通过路由来确定具体写入哪一个分片中,所以在创建索引的时候需要指定分片的数量,并且分片的数量一旦确定就不能修改。30、这些服务器的集合称为集群。不支持高并发写入数据。分词方式和是否存储等信息,就像数据库中的 Schema ,描述了文档可能具有的字段或属性、
3. 解析查询并确定目标分片
协调节点接收到请求后,会解析查询语句,并根据索引的映射(Mapping)和设置(Settings)信息来确定需要查询哪些分片(Shard)。
数据节点上的主分片接收到请求后,会先将文档写入到内存中的Lucene索引结构里。它们通常用于过滤,排序,和聚合。这些优化可以减少查询的复杂性和计算开销,提高查询速度和响应时间。