Spark小白学习之路

「扫盲」Elasticsearch

2020-01-21  本文已影响0人  Java3y

前言

只有光头才能变强。

文本已收录至我的GitHub精选文章,欢迎Starhttps://github.com/ZhongFuCheng3y/3y

不知道大家的公司用Elasticsearch多不多,反正我公司的是有在用的。平时听同事们聊天肯定避免不了不认识的技术栈,例如说:把数据放在引擎,从引擎取出数据等等。

如果对引擎不了解的同学,就压根听不懂他们在说什么(我就是听不懂的一位,扎心了)。引擎一般指的是搜索引擎,现在用得比较多的就是Elasticsearch。

这篇文章主要是对Elasticsearch一个简单的入门,没有高深的知识和使用。至少我想做到的是:以后同事们聊引擎了,至少知道他们在讲什么。

image

什么是Elasticsearch?

Elasticsearch is a real-time, distributed storage, search, and analytics engine

Elasticsearch 是一个实时分布式存储、搜索、分析的引擎。

介绍那儿有几个关键字:

于是我们就得知道Elasticsearch是怎么做到实时的,Elasticsearch的架构是怎么样的(分布式)。存储、搜索和分析(得知道Elasticsearch是怎么存储、搜索和分析的)

这些问题在这篇文章中都会有提及。

我已经写了200多篇原创技术文章了,后续会写大数据相关的文章,如果想看我其他文章的同学,不妨关注我吧。公众号:Java3y

如果觉得我这篇文章还不错,对你有帮助,不要吝啬自己的赞

为什么要用Elasticsearch

在学习一项技术之前,必须先要了解为什么要使用这项技术。所以,为什么要使用Elasticsearch呢?我们在日常开发中,数据库也能做到(实时、存储、搜索、分析)。

相对于数据库,Elasticsearch的强大之处就是可以模糊查询

有的同学可能就会说:我数据库怎么就不能模糊查询了??我反手就给你写一个SQL:

select * from user where name like '%公众号Java3y%'

这不就可以把公众号Java3y相关的内容搜索出来了吗?

的确,这样做的确可以。但是要明白的是:name like %Java3y%这类的查询是不走索引的,不走索引意味着:只要你的数据库的量很大(1亿条),你的查询肯定会是级别的

如果对数据库索引还不是很了解的同学,建议复看一下我以前的文章。我觉得我当时写得还不赖(哈哈哈)

GitHub搜关键字:”索引“

而且,即便给你从数据库根据模糊匹配查出相应的记录了,那往往会返回大量的数据给你,往往你需要的数据量并没有这么多,可能50条记录就足够了。

还有一个就是:用户输入的内容往往并没有这么的精确,比如我从Google输入ElastcSeach(打错字),但是Google还是能估算我想输入的是Elasticsearch

image

而Elasticsearch是专门做搜索的,就是为了解决上面所讲的问题而生的,换句话说:

下面我们就来学学为什么Elasticsearch可以做到上面的几点。

Elasticsearch的数据结构

众所周知,你要在查询的时候花得更少的时间,你就需要知道他的底层数据结构是怎么样的;举个例子:

从上面说Elasticsearch的模糊查询速度很快,那Elasticsearch的底层数据结构是什么呢?我们来看看。

我们根据“完整的条件”查找一条记录叫做正向索引;我们一本书的章节目录就是正向索引,通过章节名称就找到对应的页码。

image

首先我们得知道为什么Elasticsearch为什么可以实现快速的“模糊匹配”/“相关性查询”,实际上是你写入数据到Elasticsearch的时候会进行分词

还是以上图为例,上图出现了4次“算法”这个词,我们能不能根据这次词为它找他对应的目录?Elasticsearch正是这样干的,如果我们根据上图来做这个事,会得到类似这样的结果:

这代表着“算法”这个词肯定是在第二页、第十三页、第四十二页、第五十六页出现过。这种根据某个词(不完整的条件)再查找对应记录,叫做倒排索引

再看下面的图,好好体会一下:

image

众所周知,世界上有这么多的语言,那Elasticsearch怎么切分这些词呢?,Elasticsearch内置了一些分词器

Elasticsearch分词器主要由三部分组成:

显然,Elasticsearch是老外写的,内置的分词器都是英文类的,而我们用户搜索的时候往往搜的是中文,现在中文分词器用得最多的就是IK

扯了一大堆,那Elasticsearch的数据结构是怎么样的呢?看下面的图:

image

我们输入一段文字,Elasticsearch会根据分词器对我们的那段文字进行分词(也就是图上所看到的Ada/Allen/Sara..),这些分词汇总起来我们叫做Term Dictionary,而我们需要通过分词找到对应的记录,这些文档ID保存在PostingList

Term Dictionary中的词由于是非常非常多的,所以我们会为其进行排序,等要查找的时候就可以通过二分来查,不需要遍历整个Term Dictionary

由于Term Dictionary的词实在太多了,不可能把Term Dictionary所有的词都放在内存中,于是Elasticsearch还抽了一层叫做Term Index,这层只存储 部分 词的前缀Term Index会存在内存中(检索会特别快)

Term Index在内存中是以FST(Finite State Transducers)的形式保存的,其特点是非常节省内存。FST有两个优点:

前面讲到了Term Index是存储在内存中的,且Elasticsearch用FST(Finite State Transducers)的形式保存(节省内存空间)。Term Dictionary在Elasticsearch也是为他进行排序(查找的时候方便),其实PostingList也有对应的优化。

PostingList会使用Frame Of Reference(FOR)编码技术对里边的数据进行压缩,节约磁盘空间

image

PostingList里边存的是文档ID,我们查的时候往往需要对这些文档ID做交集和并集的操作(比如在多条件查询时),PostingList使用Roaring Bitmaps来对文档ID进行交并集操作。

使用Roaring Bitmaps的好处就是可以节省空间和快速得出交并集的结果。

image

所以到这里我们总结一下Elasticsearch的数据结构有什么特点:

image

Elasticsearch的术语和架构

从官网的介绍我们已经知道Elasticsearch是分布式存储的,如果看过我的文章的同学,对分布式这个概念应该不陌生了。

如果对分布式还不是很了解的同学,建议复看一下我以前的文章。我觉得我当时写得还不赖(哈哈哈)

GitHub搜关键字:”SpringCloud“,"Zookeeper","Kafka","单点登录"

在讲解Elasticsearch的架构之前,首先我们得了解一下Elasticsearch的一些常见术语。

image

相信大家看完上面的对比图,对Elasticsearch的一些术语就不难理解了。那Elasticsearch的架构是怎么样的呢?下面我们来看看:

一个Elasticsearch集群会有多个Elasticsearch节点,所谓节点实际上就是运行着Elasticsearch进程的机器。

image

在众多的节点中,其中会有一个Master Node,它主要负责维护索引元数据、负责切换主分片和副本分片身份等工作(后面会讲到分片的概念),如果主节点挂了,会选举出一个新的主节点。

image

从上面我们也已经得知,Elasticsearch最外层的是Index(相当于数据库 表的概念);一个Index的数据我们可以分发到不同的Node上进行存储,这个操作就叫做分片

比如现在我集群里边有4个节点,我现在有一个Index,想将这个Index在4个节点上存储,那我们可以设置为4个分片。这4个分片的数据合起来就是Index的数据

image

为什么要分片?原因也很简单:

现在问题来了,如果某个节点挂了,那部分数据就丢了吗?显然Elasticsearch也会想到这个问题,所以分片会有主分片和副本分片之分(为了实现高可用

数据写入的时候是写到主分片,副本分片会复制主分片的数据,读取的时候主分片和副本分片都可以读

Index需要分为多少个分片和副本分片都是可以通过配置设置的

image

如果某个节点挂了,前面所提高的Master Node就会把对应的副本分片提拔为主分片,这样即便节点挂了,数据就不会丢。

到这里我们可以简单总结一下Elasticsearch的架构了:

image

Elasticsearch 写入的流程

上面我们已经知道当我们向Elasticsearch写入数据的时候,是写到主分片上的,我们可以了解更多的细节。

客户端写入一条数据,到Elasticsearch集群里边就是由节点来处理这次请求:

image

集群上的每个节点都是coordinating node协调节点),协调节点表明这个节点可以做路由。比如节点1接收到了请求,但发现这个请求的数据应该是由节点2处理(因为主分片在节点2上),所以会把请求转发到节点2上。

路由到对应的节点以及对应的主分片时,会做以下的事:

  1. 将数据写到内存缓存区
  2. 然后将数据写到translog缓存区
  3. 每隔1s数据从buffer中refresh到FileSystemCache中,生成segment文件,一旦生成segment文件,就能通过索引查询到了
  4. refresh完,memory buffer就清空了。
  5. 每隔5s中,translog 从buffer flush到磁盘中
  6. 定期/定量从FileSystemCache中,结合translog内容flush index到磁盘中。
image

解释一下:

说白了就是:写内存缓冲区(定时去生成segement,生成translog),能够让数据能被索引、被持久化。最后通过commit完成一次的持久化。

image

等主分片写完了以后,会将数据并行发送到副本集节点上,等到所有的节点写入成功就返回ack给协调节点,协调节点返回ack给客户端,完成一次的写入。

Elasticsearch更新和删除

Elasticsearch的更新和删除操作流程:

前面提到了,每隔1s会生成一个segement 文件,那segement文件会越来越多越来越多。Elasticsearch会有一个merge任务,会将多个segement文件合并成一个segement文件。

在合并的过程中,会把带有delete状态的doc物理删除掉。

image

Elasticsearch查询

查询我们最简单的方式可以分为两种:

public TopDocs search(Query query, int n);
public Document doc(int docID);

根据ID去查询具体的doc的流程是:

根据query去匹配doc的流程是:

image

从上面所讲的写入流程,我们就可以知道:Get(通过ID去查Doc是实时的),Query(通过query去匹配Doc是近实时的)

Elasticsearch查询又分可以为三个阶段:

image

一般我们用得最多的就是QUERY_THEN_FETCH,第一种查询完就返回整个Doc内容(QUERY_AND_FETCH)只适合于只需要查一个分片的请求。

QUERY_THEN_FETCH总体的流程流程大概是:

Query Phase阶段时节点做的事:

Fetch Phase阶段时节点做的是:

主流程我相信大家也不会太难理解,说白了就是:由于Elasticsearch是分布式的,所以需要从各个节点都拉取对应的数据,然后最终统一合成给客户端

只是Elasticsearch把这些活都干了,我们在使用的时候无感知而已。

image

最后

这篇文章主要对Elasticsearch简单入了个门,实际使用肯定还会遇到很多坑,但我目前就到这里就结束了。

image

如果文章写得有错误的地方,欢迎友善指正交流。等年后还会继续更新大数据相关的入门文章,有兴趣的欢迎关注我的公众号。觉得这篇文章还行,可以给我一个赞👍

参考资料:

如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号「Java3y」。

在公众号下回复「888」即可获取!!

<img src='https://user-gold-cdn.xitu.io/2020/1/20/16fc310538aa04b5?w=600&h=600&f=gif&s=759369' width=400px height=400px />

本已收录至我的GitHub精选文章,欢迎Starhttps://github.com/ZhongFuCheng3y/3y

求点赞 求关注️ 求分享👥 求留言💬 对我来说真的 非常有用!!!

上一篇下一篇

猜你喜欢

热点阅读