Elasticsearch 查询数据的工作原理是什么?-程序员宅基地

技术标签: java  elasticsearch  搜索引擎  redis  es  

来源:8rr.co/GsAa

面试题

ES 写入数据的工作原理是什么啊?ES 查询数据的工作原理是什么啊?底层的 Lucene 介绍一下呗?倒排索引了解吗?

面试官心理分析

问这个,其实面试官就是要看看你了解不了解 es 的一些基本原理,因为用 es 无非就是写入数据,搜索数据。你要是不明白你发起一个写入和搜索请求的时候,es 在干什么,那你真的是......

对 es 基本就是个黑盒,你还能干啥?你唯一能干的就是用 es 的 api 读写数据了。要是出点什么问题,你啥都不知道,那还能指望你什么呢?

面试题剖析

es 写数据过程

  • 客户端选择一个 node 发送请求过去,这个 node 就是 coordinating node (协调节点)。

  • coordinating node 对 document 进行路由,将请求转发给对应的 node(有 primary shard)。

  • 实际的 node 上的 primary shard 处理请求,然后将数据同步到 replica node 。

  • coordinating node 如果发现 primary node 和所有 replica node 都搞定之后,就返回响应结果给客户端。

es-write

es 读数据过程

可以通过 doc id 来查询,会根据 doc id 进行 hash,判断出来当时把 doc id 分配到了哪个 shard 上面去,从那个 shard 去查询。

  • 客户端发送请求到任意一个 node,成为 coordinate node 。

  • coordinate node 对 doc id 进行哈希路由,将请求转发到对应的 node,此时会使用 round-robin 随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡。

  • 接收请求的 node 返回 document 给 coordinate node 。

  • coordinate node 返回 document 给客户端。

es 搜索数据过程

es 最强大的是做全文检索,就是比如你有三条数据:

java真好玩儿啊
java好难学啊
j2ee特别牛Copy to clipboardErrorCopied

你根据 java 关键词来搜索,将包含 java 的 document 给搜索出来。es 就会给你返回:java真好玩儿啊,java好难学啊。

  • 客户端发送请求到一个 coordinate node 。

  • 协调节点将搜索请求转发到所有的 shard 对应的 primary shard 或 replica shard ,都可以。

  • query phase:每个 shard 将自己的搜索结果(其实就是一些 doc id )返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。

  • fetch phase:接着由协调节点根据 doc id 去各个节点上拉取实际的 document 数据,最终返回给客户端。

写请求是写入 primary shard,然后同步给所有的 replica shard;读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法。

写数据底层原理

es-write-detail

先写入内存 buffer,在 buffer 里的时候数据是搜索不到的;同时将数据写入 translog 日志文件。

如果 buffer 快满了,或者到一定时间,就会将内存 buffer 数据 refresh 到一个新的 segment file 中,但是此时数据不是直接进入 segment file 磁盘文件,而是先进入 os cache 。这个过程就是 refresh 。

每隔 1 秒钟,es 将 buffer 中的数据写入一个新的 segment file ,每秒钟会产生一个新的磁盘文件 segment file ,这个 segment file 中就存储最近 1 秒内 buffer 中写入的数据。

但是如果 buffer 里面此时没有数据,那当然不会执行 refresh 操作,如果 buffer 里面有数据,默认 1 秒钟执行一次 refresh 操作,刷入一个新的 segment file 中。

操作系统里面,磁盘文件其实都有一个东西,叫做 os cache ,即操作系统缓存,就是说数据写入磁盘文件之前,会先进入 os cache ,先进入操作系统级别的一个内存缓存中去。只要 buffer 中的数据被 refresh 操作刷入 os cache 中,这个数据就可以被搜索到了。

为什么叫 es 是准实时的?NRT ,全称 near real-time 。默认是每隔 1 秒 refresh 一次的,所以 es 是准实时的,因为写入的数据 1 秒之后才能被看到。可以通过 es 的 restful api 或者 java api ,手动执行一次 refresh 操作,就是手动将 buffer 中的数据刷入 os cache 中,让数据立马就可以被搜索到。只要数据被输入 os cache 中,buffer 就会被清空了,因为不需要保留 buffer 了,数据在 translog 里面已经持久化到磁盘去一份了。

重复上面的步骤,新的数据不断进入 buffer 和 translog,不断将 buffer 数据写入一个又一个新的 segment file 中去,每次 refresh 完 buffer 清空,translog 保留。随着这个过程推进,translog 会变得越来越大。当 translog 达到一定长度的时候,就会触发 commit 操作。

commit 操作发生第一步,就是将 buffer 中现有数据 refresh 到 os cache 中去,清空 buffer。然后,将一个 commit point 写入磁盘文件,里面标识着这个 commit point 对应的所有 segment file ,同时强行将 os cache 中目前所有的数据都 fsync 到磁盘文件中去。最后清空 现有 translog 日志文件,重启一个 translog,此时 commit 操作完成。

这个 commit 操作叫做 flush 。默认 30 分钟自动执行一次 flush ,但如果 translog 过大,也会触发 flush 。flush 操作就对应着 commit 的全过程,我们可以通过 es api,手动执行 flush 操作,手动将 os cache 中的数据 fsync 强刷到磁盘上去。

translog 日志文件的作用是什么?你执行 commit 操作之前,数据要么是停留在 buffer 中,要么是停留在 os cache 中,无论是 buffer 还是 os cache 都是内存,一旦这台机器死了,内存中的数据就全丢了。所以需要将数据对应的操作写入一个专门的日志文件 translog 中,一旦此时机器宕机,再次重启的时候,es 会自动读取 translog 日志文件中的数据,恢复到内存 buffer 和 os cache 中去。

translog 其实也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去,所以默认情况下,可能有 5 秒的数据会仅仅停留在 buffer 或者 translog 文件的 os cache 中,如果此时机器挂了,会丢失 5 秒钟的数据。但是这样性能比较好,最多丢 5 秒的数据。也可以将 translog 设置成每次写操作必须是直接 fsync 到磁盘,但是性能会差很多。

实际上你在这里,如果面试官没有问你 es 丢数据的问题,你可以在这里给面试官炫一把,你说,其实 es 第一是准实时的,数据写入 1 秒后可以搜索到;可能会丢失数据的。有 5 秒的数据,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盘上,此时如果宕机,会导致 5 秒的数据丢失

总结一下,数据先写入内存 buffer,然后每隔 1s,将数据 refresh 到 os cache,到了 os cache 数据就能被搜索到(所以我们才说 es 从写入到能被搜索到,中间有 1s 的延迟)。每隔 5s,将数据写入 translog 文件(这样如果机器宕机,内存数据全没,最多会有 5s 的数据丢失),translog 大到一定程度,或者默认每隔 30mins,会触发 commit 操作,将缓冲区的数据都 flush 到 segment file 磁盘文件中。

数据写入 segment file 之后,同时就建立好了倒排索引。

删除/更新数据底层原理

如果是删除操作,commit 的时候会生成一个 .del 文件,里面将某个 doc 标识为 deleted 状态,那么搜索的时候根据 .del 文件就知道这个 doc 是否被删除了。

如果是更新操作,就是将原来的 doc 标识为 deleted 状态,然后新写入一条数据。

buffer 每 refresh 一次,就会产生一个 segment file ,所以默认情况下是 1 秒钟一个 segment file ,这样下来 segment file 会越来越多,此时会定期执行 merge。每次 merge 的时候,会将多个 segment file 合并成一个,同时这里会将标识为 deleted 的 doc 给物理删除掉,然后将新的 segment file 写入磁盘,这里会写一个 commit point ,标识所有新的 segment file ,然后打开 segment file 供搜索使用,同时删除旧的 segment file 。

底层 lucene

简单来说,lucene 就是一个 jar 包,里面包含了封装好的各种建立倒排索引的算法代码。我们用 Java 开发的时候,引入 lucene jar,然后基于 lucene 的 api 去开发就可以了。

通过 lucene,我们可以将已有的数据建立索引,lucene 会在本地磁盘上面,给我们组织索引的数据结构。

倒排索引

在搜索引擎中,每个文档都有一个对应的文档 ID,文档内容被表示为一系列关键词的集合。例如,文档 1 经过分词,提取了 20 个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。

那么,倒排索引就是关键词到文档 ID 的映射,每个关键词都对应着一系列的文件,这些文件中都出现了关键词。

举个栗子。

有以下文档:

DocId Doc
1 谷歌地图之父跳槽 Facebook
2 谷歌地图之父加盟 Facebook
3 谷歌地图创始人拉斯离开谷歌加盟 Facebook
4 谷歌地图之父跳槽 Facebook 与 Wave 项目取消有关
5 谷歌地图之父拉斯加盟社交网站 Facebook

对文档进行分词之后,得到以下倒排索引

WordId Word DocIds
1 谷歌 1, 2, 3, 4, 5
2 地图 1, 2, 3, 4, 5
3 之父 1, 2, 4, 5
4 跳槽 1, 4
5 Facebook 1, 2, 3, 4, 5
6 加盟 2, 3, 5
7 创始人 3
8 拉斯 3, 5
9 离开 3
10 4
.. .. ..

另外,实用的倒排索引还可以记录更多的信息,比如文档频率信息,表示在文档集合中有多少个文档包含某个单词。

那么,有了倒排索引,搜索引擎可以很方便地响应用户的查询。比如用户输入查询 Facebook ,搜索系统查找倒排索引,从中读出包含这个单词的文档,这些文档就是提供给用户的搜索结果。

要注意倒排索引的两个重要细节:

  • 倒排索引中的所有词项对应一个或多个文档;

  • 倒排索引中的词项根据字典顺序升序排列

上面只是一个简单的例子,并没有严格按照字典顺序升序排列。

回复 【idea激活】即可获得idea的激活方式

回复 【Java】获取java相关的视频教程和资料

回复 【SpringCloud】获取SpringCloud相关多的学习资料

回复 【python】获取全套0基础Python知识手册

回复 【2020】获取2020java相关面试题教程

阅读更多

我从外包公司离职了…

最近面试Java后端开发的感受

Java 的 JSP 已经被淘汰了吗?

年前的一波内推,一个公司,两个职位!

淘宝为什么能抗住双 11 ?看完这篇文章你就明白了!

来,教你做个属于自己的 Markdown 编辑器

相信自己,没有做不到的,只有想不到的

在这里获得的不仅仅是技术!


喜欢就给个“在看

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/androidstarjack/article/details/108373410

智能推荐

Docker最全教程之使用Docker搭建Java开发环境_为什么docker不用java开发-程序员宅基地

文章浏览阅读1.8k次。前言Java是一门面向对象的优秀编程语言,市场占有率极高,但是在容器化实践过程中,发现官方支持并不友好,同时与其他编程语言的基础镜像相比(具体见各语言镜像比较),确实是非常臃肿。JavaJava是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此[Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。Java具有简单性、面向对象、分布式、健壮性、_为什么docker不用java开发

如何利用装饰者模式在不改变原有对象的基础上扩展功能-程序员宅基地

文章浏览阅读421次。作者:双子孤狼blog.csdn.net/zwx900102/article/details/107740212阅读目录什么是装饰者模式普通示例装饰者模式示例类图关系装饰者模式使用场景装..._java,不影响原有程序基础上,运行别的功能

json的中换行符的处理_josn文件中的\处理-程序员宅基地

文章浏览阅读3.3w次,点赞2次,收藏5次。json作为ajax常用的一种数据类型,经常使用。但如果字段中出现换行符如何处理? 去掉显然不合适。有些字段本来就有换行符,如何能去掉? 测试一下json类的处理,也没有发现。想不到最终的处理确实如此简单:后台代码把换行符\r\n替换为\\r\\n,前台代码js收到的字符就是\r\n_josn文件中的\处理

vue render 函数详解 (配参数详解)_vue的render函数-程序员宅基地

文章浏览阅读519次,点赞5次,收藏7次。vue render 函数详解 (配参数详解)_vue的render函数

阿里百秀移动端首页-程序员宅基地

文章浏览阅读543次,点赞12次,收藏7次。bootstrap在设置字体图标时,通过引用相关字体图标的类名,就可直接在该元素前面添加一个伪元素放至字体图标,调整字体图标的位置时直接设置该元素的before伪元素即可。超小屏幕时阿里百秀图片隐藏,被替代为文字,给图片添加类名hidden-xs即可,事先准备好一个盒子来装文字,再让该文字只在超小屏幕显示即可,即添加类名visible-xs。,里面的a元素宽高撑满,a里的元素宽高也撑满,切记不可设置margin,设置li的宽度时,左边为50%,右边为25%,若使用margin则会把右边的图片挤下去。

百度最近K淘客站,K的挺凶啊!_淘客站百度-程序员宅基地

文章浏览阅读2.3k次。很多之前收录几万,几十万的站,都被K的不行了。。。不知道收入是不是也影响很大呢。。看来靠百度SEO还是不太靠谱啊!还是要靠内容!_淘客站百度

随便推点

异常 Non-terminating decimal expansion; no exact representable decimal result的解决方法_non-terminating decimal expansion; no exact repres-程序员宅基地

文章浏览阅读4.3k次。今天在写多线程分页同步数据的时候报错:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result。发现报错的语句是:int pageSize = new BigDecimal(rCnt).divide(new BigDecimal(300)).setScale(0, BigDecimal.ROUND_UP).intValue();解决办法在 java _non-terminating decimal expansion; no exact representable decimal result.

Android DrawerLayout 和ViewPager滑动冲突解决_drawerlayout和viewpager冲突-程序员宅基地

文章浏览阅读2.3k次。最近遇到项目整体是Activity搭配DrawerLayout的抽屉样式,在左侧抽屉的顶部,有一个ViewPager无限轮播。并要求ViewPager左滑下一页,右滑上一页,3秒自动轮播下一页,点击按住停止轮播。同时DrawerLayout的NavigationMenuView左滑打开,右滑关闭。滑动事件同时存在,手指滑动头部区域ViewPager响应,滑动其他区域DrawerLayout打开or..._drawerlayout和viewpager冲突

Unity3d-Unable to locate Android SDK &&Failed to re-package resources._unityexception: android sdk not found unable to lo-程序员宅基地

文章浏览阅读6.6k次,点赞2次,收藏3次。在设置里面配置 sdk 路径。 Unity-Preferences-external tools-sdk(具体的sdk可以去官网下载)解决办法,删除build tool 24,unity就会使用build tool 23进行打包!!根本不支持build tool 24_unityexception: android sdk not found unable to locate android sdk. unityeng

《数据结构》— 线段树知识点模版详解_线段树考点-程序员宅基地

文章浏览阅读696次。线段树详解第一部分1.定义:线段树(Segment Tree)是一种二叉搜索树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2,b]。因此线段树是满二叉树,最后的子节点数目为N,即整个线段区间的长度。使用线段树可以快速的查找某一..._线段树考点

工业自动化使用机器视觉检测的优势_视觉抓捕用什么-程序员宅基地

文章浏览阅读2.3k次。所谓视觉检测,就是用机器视觉代替人眼进行观察和判断。视觉检测系统是指通过摄像头等产品将捕捉到的目标转化为图像信号,传输到专用的图像处理软件,再根据像素分布和亮度、颜色等信息转化为数字信号。之后,成像系统对这些信号进行系统计算,提取目标特征,然后根据判别结果控制设备进行下一步操作。比如自动贴标生产线中产品的剔除、分瓶等。为什么要使用视觉检测?工业自动化生产线使用视觉检测系统的主要原因有几个:精度——于人眼的一些局限性,机器视觉在准确度上具有明显的优势。即使人眼可以通过放大镜或显微镜检._视觉抓捕用什么

pip安装、卸载依赖包的命令_用于卸载指定包依赖的命令-程序员宅基地

文章浏览阅读5.4k次。1.【下载】python -m pip install --upgrade pip2.【指定下载】python3 -m pip install pip==20.0.2_用于卸载指定包依赖的命令

推荐文章

热门文章

相关标签