来源:8rr.co/GsAa面试题ES写数据的工作原理是什么?ES查询数据的工作原理是什么?能介绍下底层的Lucene吗?你了解倒排索引吗?面试官的心理分析是这么问的。其实面试官只是想看看你是否了解es的一些基本原理,因为使用es无非就是写数据和查数据。如果你在发起写入和搜索请求的时候不明白es在做什么,那你就真的是……es基本上就是个黑盒子,你还能做什么?你唯一能做的就是用esapi读写数据。如果出现问题而您对此一无所知,您能指望什么?面试题分析es数据写入过程客户端选择一个节点向其发送请求,这个节点就是协调节点(coordinatingnode)。协调节点路由文档并将请求转发到相应的节点(具有主分片)。实际节点上的主分片处理请求,然后将数据同步到副本节点。如果协调节点发现主节点和所有副本节点都已完成,则将响应结果返回给客户端。es-writees读取数据的过程可以通过docid查询,会根据docid进行hash,确定当时docid分配到哪个shard,从那个shard查询。客户端向任意节点发送请求,成为坐标节点。坐标节点对docid进行哈希路由,将请求转发给对应的节点。此时采用round-robin随机轮询算法,随机选择其中一个primaryshard及其所有replicas来均衡读请求负载。收到请求的节点将文档返回给坐标节点。坐标节点将文档返回给客户端。es搜索数据过程es最厉害的地方就是可以做全文搜索,也就是比如你有三段数据:java真好玩,java真难学,j2ee特别,复制到clipboardError已复制,如果根据java关键字搜索,包含java的文档会被搜索出来。es会回给你:java真好玩,java真难学。客户端向坐标节点发送请求。协调节点将搜索请求转发给所有分片对应的主分片或副本分片。查询阶段:每个分片将自己的搜索结果(实际上是一些docid)返回给协调节点,协调节点对数据进行合并、排序、分页等操作,产生最终结果。fetch阶段:然后协调节点根据docid从各个节点拉取实际的文档数据,最后返回给客户端。写请求写入主分片,然后同步到所有副本分片;可以使用随机轮询算法从主分片或副本分片读取读取请求。写数据的底层原理es-write-detail先写入内存缓冲区,不能在缓冲区中查找数据;同时将数据写入translog日志文件。如果buffer快满了,或者过了一定时间,内存buffer数据会被刷新到新的segment文件中,但是此时数据并没有直接进入segment文件磁盘文件,而是先进入os缓存.这个过程就是刷新。es每隔1秒将buffer中的数据写入一个新的segmentfile,每秒生成一个新的磁盘文件segmentfile,里面存放着最近1秒写入buffer的数据。但是,如果此时缓冲区中没有数据,那么当然不会进行刷新操作。如果缓冲区中有数据,则默认每秒执行一次刷新操作,以闪入新的段文件。在操作系统中,磁盘文件其实有一个叫做oscache的东西,也就是操作系统的缓存。也就是说,数据在写入磁盘文件之前,会先进入os缓存,在操作系统层面先进入一个内存缓存。只要通过refresh操作将buffer中的数据刷入os缓存中,就可以查找到数据了。为什么叫es准实时呢?NRT代表近实时。默认是1秒刷新一次,所以es是准实时的,因为写入的数据1秒后才能看到。可以通过es的restfulapi或者javaapi手动进行刷新操作,即手动将buffer中的数据刷新到os缓存中,这样就可以立即搜索到数据。只要有数据进入os缓存,buffer就会被清空,因为不需要再保留buffer,数据在translog中已经持久化到磁盘了。重复以上步骤,新的数据不断进入buffer和translog,不断将buffer数据一个接一个写入新的segment文件。每次刷新后,清除缓冲区并保留translog。随着这个过程的进行,translog会变得越来越大。当translog达到一定长度时,触发commit操作。commit操作的第一步是将buffer中已有的数据刷新到os缓存中,并清空buffer。然后,向磁盘文件写入一个commitpoint,它标识了commitpoint对应的所有segment文件,同时强制将oscache中的当前数据全部fsync到磁盘文件中。最后清除已有的translog日志文件,重启一个translog,此时commit操作完成。此提交操作称为flush。默认情况下,每30分钟自动执行一次flush,但如果translog过大,也会触发flush。flush操作对应commit的整个过程。我们可以通过esapi手动执行flush操作,将os缓存中的数据手动fsync到磁盘。translog日志文件的用途是什么?在执行提交操作之前,数据要么保留在缓冲区中,要么保留在操作系统缓存中。buffer和oscache都是内存。一旦机器死机,内存中的所有数据都会丢失。所以需要将数据对应的操作写到一个专门的日志文件translog中。一旦此时机器宕机,再次重启,es会自动读取translog日志文件中的数据,恢复到内存缓冲区和os缓存中。.translog其实是先写入os缓存的。默认情况下每5秒刷新一次到磁盘,所以默认情况下可能会有5秒的数据只会留在buffer或translog文件的oscache中。如果此时机器挂机,将丢失5秒的数据。但是这样性能更好,最多丢失5秒的数据。也可以设置translog,让每次写操作都必须直接fsynced到磁盘,但是性能会差很多。事实上,你在这里。如果面试官没有问你es丢失数据的问题,你可以在这里向面试官炫耀一下。你说,其实es是准实时第一的,1秒后就可以查到数据了。;数据可能会丢失。有5秒的数据,留在buffer、translogoscache、segmentfileoscache中,不在磁盘上。如果此时出现宕机,将会丢失5秒的数据。综上所述,数据先写入内存缓冲区,然后每隔1s,??将数据刷新到os缓存中,就可以在os缓存中查找数据(所以我们说es可以从写入查找,Delay中间有1s)。每隔5s,将数据写入translog文件(所以如果机器死机,内存数据没了,最多5s的数据丢失),translog大到一定程度,还是默认30mins一次,commit操作会被触发,buffer会被zone中的数据刷新到segmentfile磁盘文件中。数据写入段文件后,同时建立倒排索引。删除/更新数据的底层原理如果是删除操作,commit时会生成一个.del文件,将某个doc标记为已删除。然后在查找的时候,根据.del文件就可以知道这个doc是否被删除了。如果是update操作,将原来的doc标记为deleted,然后写入一条新的数据。每次刷新buffer,都会生成一个segment文件,所以默认是每秒一个segment文件,这样segment文件就会越来越多,此时会定时执行merge。每次合并时,多个段文件将合并为一个。同时,标记为已删除的doc会被物理删除,然后将新的segment文件写入磁盘。这里会写一个commitpoint来标识所有新的segment文件,然后打开segment文件进行搜索,同时删除旧的segment文件。底层lucene简单来说,lucene就是一个jar包,里面包含了各种打包的构建倒排索引的算法代码。我们在Java开发的时候,需要引入lucenejar,然后基于luceneapi进行开发。通过lucene,我们可以对已有的数据进行索引,lucene会在本地磁盘上为我们整理好索引数据结构。倒排索引在搜索引擎中,每个文档都有一个对应的文档ID,文档的内容表示为一组关键字。例如对文档1进行了切分,提取了20个关键词,每个关键词都会记录它在文档中出现的次数和出现的位置。那么倒排索引就是关键词到文档ID的映射,每个关键词对应一系列出现关键词的文件。举个栗子。有以下文档:另外,实用的倒排索引还可以记录更多的信息,比如文档频率信息,表示文档集合中有多少文档包含某个词。然后,借助倒排索引,搜索引擎可以轻松响应用户查询。例如,当用户输入对Facebook的查询时,搜索系统会查找倒排索引并从中读取包含该词的文档。这些文档是提供给用户的搜索结果。注意关于倒排索引的两个重要细节:倒排索引中的所有术语对应一个或多个文档;倒排索引中的词条按照字典升序排列。
