Elasticsearch基本概念和索引原理

我是啤酒就辣条。

但行好事,莫问前程。mysql

Elasticsearch是什么?

Elasticsearch是一个基于文档的NoSQL数据库,是一个分布式RESTful风格的搜索和数据分析引擎,同时也是Elastic Stack的核心,集中存储数据。Elasticsearch、Logstash、Kibana常常被用做日志分析系统,俗称ELK。redis

说白了,就是一个数据库,搜索贼快(可是插入更新较慢,要否则其余数据库别玩了)。速度快,还能够进行分词,很是适合作搜索,例如商城的商品搜索。为何快,后面讲原理的时候会说,不仅仅是缓存的问题,原理很是精彩。并且它是nosql的,数据格式能够随便造。Elasticsearch还为咱们提供了丰富的RESTful风格的API,写代码的成本极低。最后它支持分布式,高性能(搜索快),高可用(某些节点宕机能够接着用),可伸缩(能够方便的增长节点,解决物理内存上线问题),适合分布式系统开发。算法

Elasticsearch基本概念

为了快速了解Elasticsearch(后面可能会简称为ES),能够与mysql几个概念作个对比。sql

Elasticsearch Mysql
字段(Filed) 属性(列)
文档(Document) 记录(行)
类型(Type)
索引(Index) 数据库

是否是清楚多了?咱们说Elasticsearch是基于文档的,就是由于记录元素(被搜索的最小单位)是文档。例以下面就是一个文档,数据库

{
    "email":      "john@smith.com",
    "first_name": "John",
    "last_name":  "Smith",
    "info": {
        "bio":         "Eco-warrior and defender of the weak",
        "age":         25,
        "interests": [ "dolphins", "whales" ]
    },
    "join_date": "2014/05/01"
}

文档格式看起来很像Json吧。emailfirst_name等等就是Filed。因为结构是Json,因此value值就很方便听任意类型,这就是nosql的好处。json

文档(Document)

ES中的一个对象未来会和Java代码中的一个对象对应。文档的每个Filed能够是任意类型,可是一旦某索引(Index)(咱们描述的时候,略过Type,可是Type依然存在)中插入了一个文档,某Filed被第一次使用,ES就会设置好此Filed的类型。例如你插入user的name是字符串类型,之后再插入文档,name字段必须是字符串类型。因此,建议在插入文档以前,先设置好每一个Filed的类型。数组

若是插入文档的时候,不指定id,ES会帮助咱们自动生成一个id,建议id是数字类型,这样搜索会快速不少。商城系统中的商品id建议使用雪花算法生成,这样既避免了自增id的安全性问题,又解决了字符串id检索慢的问题。缓存

类型(Type)

关于Type,类型概念,在6.x版本中,一个索引(Index)能够拥有多个Type。在7.x版本(目前最新版本),一个索引只能拥有一个Type,默认的type就是_doc,在7.x版本中,已经建议删除了。在将来的8.x版本会完全删除。可是在7.x版本中,一个文档还必须归属于一个类型。安全

索引(Index)

都说ES中的索引相似于mysql中的数据库,我以为将来索引有成为mysql中概念的潜质。咱们把相同特征(Filed数量和类型基本相同)的文档放到同一个索引(index)里面。这样方便提早经过mapping来规定各个Filed的类型。另外,索引名称必须所有小写,因此不建议写成驼峰式。服务器

节点(Node)与分片(Shard)

在这里插入图片描述

因为生产环境下ES基本都是集群部署的,因此必定少不了节点的概念,一个节点就是一个ES实例,就是一个Java进程,这些Java进程部署在不一样的服务器上,增长ES可用性。

ES节点根据功能能够分为三种:

  1. 主节点:职责是和集群操做相关的内容,如建立或删除索引,跟踪哪些节点是群集的一部分,并决定哪些分片分配给相关的节点。每一个节点均可访问集群的状态,可是只有主节点能够修改集群的状态。
  2. 数据节点:数据节点主要是储存数据的节点,对文档进行增删改查,聚合操做等等,数据节点对cpu,内存,io要求较高,当资源不够的时候,能够增长新的节点,很方便的进行数据拓展。
  3. 客户端节点:本节点主要处理路由请求,分发索引的操做。实际上主节点和数据节点也有路由转发的功能,可是为了提升效率,仍是建议生产环境单首创建客户端节点。

分片相似于mysql中的分表,在一个索引拆分红几个小索引,分布在不一样的节点(不一样服务器)上,每一个小索引都具备完备的功能,当客户端发来请求的时候,客户端节点找到合适的分片上的小索引,进行数据查询,这一过程对于用户来讲都是透明的,用户表面上看只是在操做一个索引。利用分片,能够避免单个节点的物理限制,还能够增长吞吐量。建议最开始一个索引要用多少分片设计好,由于修改分片数量是个至关麻烦的过程。

做为分布式的数据库,ES必须为我们提供数据冗余功能,这就是分片副本,就是将某个分片copy一份放到其余节点上。注意,这里分片和分片副本必须在不一样的节点上!分片副本也能够提升吞吐量。分片副本不一样于分片,能够很方便的进行修改。

说完了全部概念,再去看本节最开始那张图,有一个索引,分了3分片在三个节点上,而且每一个分片在不一样的节点上有分片副本。

Elasticsearch索引原理

看完上面的内容,你对Elasticsearch有了基本的认识,再去看基本操做(我后面要写一篇基操博客),就能够在项目中使用Elasticsearch了。此刻你能够喘口气,以放松的心态看后面的内容。下面咱们就讲讲索引为何快?

首先,咱们知道mysql底层数据结构使用的是B+Tree,这种BTree,将搜索时间复杂度变成了logN,已经很快了,咱们Elasticsearch要比它还快。Elasticsearch是怎么作的呢?首先储存结构要优化,而后再提升下和磁盘的交互效率。

先说Elasticsearch索引结构,叫作倒排索引,啥是倒排索引呢?它的大概逻辑以下:

在这里插入图片描述

为了讲清楚这个概念,咱们先看个例子,以下为咱们user的数据:

ID Name Age
1 Kate 24
2 John 24
3 Bill 29
4 Kate 26
5 Brand 29

Elasticsearch会为以上数据创建两个索引树:

Term Posting List
Kate 1,4
Brand 5
John 2
Bill 3
Term Posting List
24 1,2
26 4
29 3,5

以上的索引树就叫作倒排索引,每一个Filed字段对应着一组Term,每一个Term后面跟着的id(还记着吗,这个主键用户不指定就会自动生成,因此必定存在)就是Posting List,它是一组id,有了id再去磁盘中对应的文档就so fast了。

你有没有发现,Term若是按序找会快点,将Term按序排,在进行二分查找,是否是速度就跟BTree同样了,时间复杂度为LogN。这个有序的Term组就是Term Dictionary

那么问题又来了,好比说数据库中有name前缀为A的同窗1000万个,前缀为Z的同窗有3个,我要查前缀为Z的同窗,那二分查找不也不少次吗,因此,Elasticsearch把每一个开头的地方标记一下,拿出来,再放到一颗树里,速度不是就快了嘛。这棵树就是Term IndexTerm Index前缀不必定是第一个字符,好比A、Ab、Abz,这种均可以在Term Index树里。而且Term Dictionary可能会太大,会被放到磁盘中,避免内存占用太多。

再看下面这张结构图是否是清楚多了。

在这里插入图片描述

因为Term Index被放到内存中,因此最好压缩一下,减小内存使用,压缩使用的是FST,这个东西讲起来比较复杂,反正就是能压缩,内存变小就行了。

Term压缩完了,那么Posting List是否是也能够压缩一下,省省空间啊?既然都是id,使用过redis的同窗瞬间会想到bitMap,就是有个巨大的数组,储存着0或1,有就是1,没有就是0。例如上面的三、5放在BitMap中就是 1,0,1,0,0,0。虽然说空间已经明显小多了,可是若是一个Posting List只储存着1,10000001这两个id,最后产生的数字是否是过大呢。因而乎,Roaring bitmaps就出来了,进行了一次指数降级,简单点说就是取商和余数储存,被除数是65535。例如 1000,62101,131385,196658, 这几个id,首先分组,分组规则就是商同样,例如上面id可分组为[(0,1000),(0,62101)],[],[(2,6915)],[(3,53)]。注意,没有商为1的值,我用空数组表示。此时,将某个组中的数字放到一个bitmap中。

相关文章
相关标签/搜索