ElasticSearch创建文档以及索引文档的详细流程

news2024/12/28 20:07:40

        当我们发起一个查询请求之后,ES是怎么处理这个请求然后返回数据的呢?今天就来详细说一下。

首先看一下整体结构:

        在集群模式下一个索引有多个分片,在上图中有三个节点(一个主节点两个从节点),一个索引被分为两个分片(P0、P1),每个主分片有两个副本分片(R0,R1),每个主分片底层都是对应一个Lucene Index(Lucenne索引在前面文章已经解释过,可以往回翻翻),Lucene 索引由多个Segment组成(就是段文件),每个段存储的就是文档了。

 当我们想要添加一个文档的流程是怎样的呢?

        首先ES在接受到这个请求之后,会通过路由策略来确定需要把文档存储在哪一个shard中去,然后节点接受到请求后就会交由底层的Lucene来处理了。

        Lucene Index会准备待索引的原文档,然后对原文档进行分词处理,形成一系列的term(词条),然后索引组件对文档和term处理,形成字典和倒排表。这样一个文档基本就被创建好了。

如果是搜索文档的话又是怎样处理的呢?

        Lucene首先会对语句进行分词处理,形成一系列的term。然后根据倒排索引表查找出包含term的文档,并进行合并形成返回结果。最后对查询语句与各个文档的相关性进行评分,最后按分的高低顺序返回结果。

 ElasticSearch语法分析器:

        我们在进行搜索的时候,ES是怎么进行分词的?分析过程是:

  1. 将文本分成适合倒排索引的独立词条
  2. 将词条统一化为标准格式提高他们的可搜索性。

完成上面的功能主要靠三个东西:

  • 字符过滤器:字符串按顺序一个个通过字符过滤器,主要是为了处理一些特殊字符,比如说将&转为and。
  • 分词器:分词器将字符串分为单个的词条。
  • Token过滤器:将分词器分析出来的词条挨个处理,可能会改变词条(大小写转换),删除无用的词条处理等等...

ES写入文档的详细流程: 

1.当用户发起请求后,首先请求会来到master节点,然后通过文档的id来计算对应的分片,然后再发由相应的节点来处理。

2.当分片所在节点接收到请求后,会把请求先写入Memory Buffer(这个时候数据还没到segment,还搜不到这个文档)。然后每隔1s写入倒File Cache。这个过程叫Refresh。

3.Refresh过程:默认是每隔1s将Memory Buffer的数据写入到File Cache。Segment是存储在文件系统的缓存中的。所以此时文档是可以被搜到的了。refresh后文档存储在文件系统缓存中,这样就避免了性能IO又可以被搜到,refresh默认一秒,为了提高性能可以稍微延长这个时间间隔,比如5s,所以es是准实时,达不到真正的实时。

4.为了防止数据丢失,ES通过Translog来保证数据不会丢失。就是在接收到请求后,数据同时也会写入translog中,当Filesystem Cache中的数据写入到磁盘中之后,这里面的数据才会被清除。这个过程叫flush。

5.文档在文件系统缓存中可能会有意外情况导致文档丢失,需要将文档写入磁盘,将文档从文件缓存系统写入磁盘的过程就叫flush,写入磁盘后translog就会被清空。

flush过程如下:

(1)缓冲区的文档都被写入到一个新的段,然后缓冲区会被清空。

(2)一个commit point被写入硬盘。

(3)文件系统缓存通过fsync被刷新。

(4)老的translog被删除。

merge段

每个文档到FileCache都会创建一个新的段,段太多了怎么办?merge过程:

前面说过,在Lucene Index中每次刷新都会产生一个新的段,那么段会越来越多。每一个段都会文件句柄、内存和CPU运行周期,所以段越多那么搜索也会越慢。所以ES会在后台通过Merge Segment来解决这个问题。

当索引的时候Refresh操作会创建一个新的段并且将段打开以供搜索使用。这时候后台的合并进程选择一部分大小相似的段,然后将它合并到更大的段当中,这并不会中断索引和搜索。当合并结束之后,老的段就会被删除:新的段(指合并之后的段)就会被刷新到磁盘,新的段被打开用来搜索,老的段被删除。

注意:合并大的段需要消耗大量的i/o和CPU资源,如果仍其发展会影响搜索性能。ES默认情况下会对合并流程进行资源控制,所以搜索仍然有足够的资源很好的执行。

分布式的写入流程 

在ES中一般一个索引都会被设置为多个shard,通过路由规则将数据分为多个数据子集,每个数据子集提供独立的索引和搜索功能。在写入文档的时候也会根据路由规则(默认通过id),将文档发给特定的shard进行处理,这样就实现了分布式。

通过前面介绍我们知道了,当数据写入之后一般不会立即写入磁盘而是在File Cache的Lucene Index中,这时候数据还没有写入磁盘中,那么有个问题就是这时候机器宕机内存中的数据就会丢失。这时候如何保证?我们前面也就知道是通过trans log。

  • 在每个shard中,写入就被分为两步,就是先写Lucene 在写translog。

  • 意思就是写入请求到达shard后,先写Lucene文件,再写translog文件,然后刷新translog到磁盘上,磁盘写入成功之后请求返回给用户。

  • 这里为什么会先写lucene文件再写translog文件?原因可能就是Lucen的内存写入会有很复杂的逻辑容易失败,比如超时分词等,为了避免translog中有大量的无效记录,所以就放在前面了。写入Lucene内存后并不是马上就可以被搜索到了,需要refresh把内存中的对象转换为segment后,才可以被搜索到。

  • 每隔一段较长的时间,Lucene会把内存中的新Segment刷到磁盘,然后索引文件就把持久化了,translog就没用了,就会被删掉。

更新文档

ES的不支持部分字段的更新,更新都是将整个文档更新,流程如下:

  • 收到更新请求后会先从Segment或者translog中读取出完整的文档,记录版本号为V1。

  • 然后将请求中的部分要更新的字段和读取出来的文档组合成新的完整的文档,同时更新内存中的Version Map。

  • 然后再从version Map中读取该id的最大版本号V2,如果version map中没有,则从segment或者translog中读取一下,这里基本都会从versionMap中读取出来。

  • 检查版本是否冲突,如果冲突了就会回退重新执行,如果不冲突就会执行新的add请求。

  • 然后将文档doc写入到Lucene中吗,回删除相同id的文档,然后再将这个文档写入进去。

  • 释放锁

读取文档流程

        搜索一般都是分两阶段的,首先是匹配文档id,第二步是在根据文档id查找对应的文档id,有点类似mysql的索引回表过程。

1.在初始化查询阶段,查询会广播到索引中的每一个分片拷贝。每个分片在本地执行搜索并构建一个匹配文档的大小为from+size的优先级队列。

2.每个分片返回各自的优先级队列中 所有文档的id和排序值 给协调节点,它合并这些值到自己的优先级队列中来产生一个全局排序后的结果列表。

3.接下来协调节点辨别出那些文档需要被取回并且向相关的分片提交多个GET请求,每个分片加载文档一旦所有文档都被取回,协调节点返回结果给客户端。

        我们知道在Es集群中一般一个索引会被分为多个shard,每个shard在不同的node中,而且每个shard一般还会有副本,增加数据的可靠性。那么在查询的时候会从主节点或者副本节点任意选一个来进行查询。在处理一个查询请求的时候首先需要查询所有的shard(同一个shard的primary和replica任选一个即可)。每一个shrad都是一个独立的搜索引擎,然后返回最匹配的TOP10的结果。然后返回给协调节点,协调节点收集所有的shard的返回结果,然后通过优先级队列二次排序,选择top10的结果,然后再通过id去取完整的文档,然后返回给用户。

        上面所说的先根据查询请求取找到合适的id,然后在通过id去取完成的文档这中两阶段的查询在ES中称为query_then_fetch,还有一种一阶段就返回完整doc的称为query_and_fetch,但是一般一阶段就返回文档的适用于只需查询一个shard的请求。

 

 

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/477032.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于协同过滤的旅游推荐系统设计与实现(论文+源码)_kaic

1 绪论 1.1 研究背景及意义 1.2 国内外研究现状 1.3 研究目标与意义 1.4 主要研究工作 2 相关理论介绍 2.1HTML与JavaScript 2.2 MySQL数据库 2.3 协同过滤算法简介 3 系统分析与设计 3.1 系统需求分析 3.1.1 功能性需求 3.1.2 安全性需求 3.2 系统总体架构 3.3 功能模块设计 3…

vue3的props和defineProps

文章目录 1. Props 声明1.1 props用字符串数组来声明Blog.vueBlogPost.vue 1.2 props使用对象来声明Blog.vueBlogPost.vue 2. 传递 prop 的细节2.1 Prop 名字格式2.1 静态Prop & 动态 Prop静态prop动态prop示例Blog.vueBlogPost.vue 2.3 传递不同的值类型NumberBooleanArra…

【Java笔试强训 11】

🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一、选择题 二、编程题 🔥最近公共…

算法记录 | Day46 动态规划

139.单词拆分 思路: 1.确定dp数组以及下标的含义 dp[i] : 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词。 2.确定递推公式 如果 s[0: j] 可以拆分为单词(即 dp[j] True)&#xff…

Linux RHCE解题方法

目录 安装和配置Ansible 创建和运行Ansible临时命令 安装软件包 使用RHEL系统角色 使用 Ansible Galaxy 安装角色 创建和使用角色 从 Ansible Galaxy 使用角色 创建和使用逻辑卷 生成主机文件 修改文件内容 创建 Web 内容目录 生成硬件报告 创建密码库 创建用户帐…

C++中stringstream类详解

本文主要介绍 C 编程语言中 stringstream 类的相关知识&#xff0c;同时通过示例代码介绍 stringstream 类的使用方法。 1 概述 <sstream> 定义了三个类&#xff1a;istringstream、ostringstream 和 stringstream&#xff0c;分别用来进行流的输入、输出和输入输出操作…

快速傅里叶变换FFT学习笔记

点值表示法 我们正常表示一个多项式的方式&#xff0c;形如 A ( x ) a 0 a 1 x a 2 x 2 . . . a n x n A(x)a_0a_1xa_2x^2...a_nx^n A(x)a0​a1​xa2​x2...an​xn&#xff0c;这是正常人容易看懂的&#xff0c;但是&#xff0c;我们还有一种表示法。 我们知道&#xf…

java结束当前循环

在 Java中&#xff0c;当我们要结束一个循环时&#xff0c;通常会使用循环变量的实现类来结束&#xff0c;但在实际开发中&#xff0c;我们经常会遇到某个循环结束后需要进行其他的操作的情况。此时&#xff0c;就需要使用循环变量来结束当前循环。 1、创建一个新的类&#xff…

数据结构_双链表、循环链表、静态链表

目录 1. 双链表 1.1 双链表的初始化 1.2 双链表的插入操作 1.3 双链表的删除操作 1.4 双链表的遍历 2. 循环链表 2.1 循环单链表 2.2 循环双链表 3. 静态链表 4. 顺序表和链表的比较 5. 相关练习 1. 双链表 单链表结点中只有一个指向其后继的指针&#xff0c;使得单…

电子电气架构——车辆E/E架构软硬件解耦

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 人只有在举棋不定,无从把握的时候才感到疲惫。只有去行动就能获得解放,哪怕做的不好也比无所作为强! 本文主要介绍车辆E/E架构常识,主要涉及内容是行业最…

Python实现LBP纹理提取

1、什么是LBP纹理特征&#xff1f; LBP&#xff08;Local Binary Patterns&#xff0c;局部二值模式&#xff09;是提取局部特征作为判别依据的&#xff0c;一种有效的纹理描述算子&#xff0c;度量和提取图像局部的纹理信息。它具有旋转不变性和灰度不变性等显著的优点&#…

uniapp中使用vuex(解决uniapp无法在data和template中获取vuex数据问题)

uniapp中使用vuex&#xff08;解决uniapp无法在data和template中获取vuex数据问题&#xff09; 1. uniapp中引入vuex2. uniapp中使用vuex3. 解决uniapp无法在data和template中获取vuex数据问题 1. uniapp中引入vuex 1 .在根目录下新建文件夹store,在此目录下新建index.js文件&…

第五章——动态规划3

蒙德里安的梦想 我们在黑框内横着放红框&#xff0c;我们发现当横向小方格摆好之后&#xff0c;纵向小方格只能一次纵向摆好&#xff0c;即纵向小方格只有一种方案&#xff0c;即整个摆放小方格的方案数等于横着摆放小方格的方案数 f[i,j]表示的是现在要在第i列摆&#xff0c;j…

代码随想录Day64(一刷完结)

今天学习单调栈解决最后一道题 84.柱状图中的最大矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: 输入&#xff1a;heights [2,1,5,6,…

C++中的list容器

文章目录 list的介绍list的使用list的构造list iterator的使用list capacitylist元素访问list modifierslist的迭代器失效 list与vector的对比 list的介绍 list是可以在常数范围内的任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代&#xff1b;   …

FFMPEG中的filter使用二

上一篇我们在使用滤镜时是手动创建各种滤镜&#xff0c;然后根据处理链路手动链接不同的过滤器&#xff0c;有助于我们理解滤镜的流程。这一篇我们使用参数形式&#xff0c;让ffmpeg自动帮我们创建和链接过滤器&#xff0c;这样可以减少代码量&#xff0c;同时我们可以先使用参…

学系统集成项目管理工程师(中项)系列15_质量管理

1. 质量&#xff08;Quality&#xff09;的定义 1.1. 反应实体满足主体明确和隐含需求的能力的特性总和 1.2. 明确需求是指在标准、规范、图样、技术要求、合同和其他文件中用户明确提出的要求与需要 1.3. 隐含需求是指用户和社会通过市场调研对实体的期望以及公认的、不必明…

thinkphp路由,请求和响应

文章目录 定义获取路由后面的参数跨域请求请求响应 定义 thinkphp定义路由一般在route路由下的app.php中 下面这是一个简单的路由 Route::rule(admin/login,/app/controller/Admin/login)->middleware(\app\middleware\MyMiddleware::class);该路由表示当访问admin/login时…

人工智能课程笔记(7)强化学习(基本概念 Q学习 深度强化学习 附有大量例题)

文章目录 1.强化学习与深度学习的区别2.强化学习中的基本概念3.强化学习、有监督学习和无监督学习的区别4.强化学习的特点5.离散马尔可夫过程6.马尔可夫奖励过程7.马尔可夫决策过程8.策略学习8.1.策略学习概念8.2.策略评估与贝尔曼方程 9.强化学习的最优策略求解10.基于价值的强…

K8s基础1——发展起源、资源对象、集群架构

文章目录 一、发展起源二、资源对象2.1 集群类2.2 应用类2.3 存储类2.4 安全类 三、集群架构 一、发展起源 K8s官方文档 K8s怎么来的&#xff1f; 十几年来&#xff0c;谷歌内部使用的大规模集群管理系统是Brog&#xff0c;基于容器技术实现了资源管理的自动化和跨多个数据中心…