Elasticsearch基本使用及其存储原理

基本概念

  1. 什么是ES?

    Elasticsearch 是一个分布式高扩展高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索分析探索的能力。充分利用Elasticsearch的水平伸缩性,能使数据在生产环境变得更有价值。Elasticsearch 的实现原理主要分为以下几个步骤,首先用户将数据提交到Elasticsearch 数据库中,再通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据,当用户搜索数据时候,再根据权重将结果排名打分,再将返回结果呈现给用户。

组成部分

  1. Document(文档)

    单条的记录称为 Document(文档),Document 使用 JSON 格式表示,最顶层结构或者根对象(root object)序列化的json数据,以唯一ID标识存储在elasticsearch中,文档包含元数据(metadata),而元数据中必须包含的节点为:

    1. _index:文档存储的地方
    2. _type:文档代表的对象的类(默认为doc)
    3. _id:文档的唯一标识,可手动生成,也可自动生成
      类似下面的数据:
{
"_index": "mas-",
       "_type": "doc",
       "_id": "platformshopskudt588jbw--b2b9a299e99449509ce9a8d8c77a1eae100459shiyidingding",
       "_score": 1,
       "_source": {
         "sku.categoryId": "12110218220700018908",
         "sku.title": "百龄坛巴西青柠威士忌风味配制酒",
         "sku.inputCodes": [
           "5000299603567"
         ],
         "sku.saleType": "标准",
         "sku.descriptions": [],
         "sku.name": "百龄坛巴西青柠威士忌风味配制酒",
         "goods.id": "1481557"
}
  1. Index

    许多条 Document 构成了一个 Index。 Elastic 会索引所有字段,经过处理后写入一个反向索引(Inverted Index)。查找数据的时候,直接查找该索引。所以,Elastic 数据管理的顶层单位就叫做 Index(索引)。它是单个数据库的同义词。每个 Index (即数据库)的名字必须是小写。命令( curl -X GET 'http://localhost:9200/_cat/indices)可以查看当前节点的所有 Index。

  2. Type

    Document 可以分组,比如一个 Index 里面,可以按城市分组(北京和上海),也可以按气候分组(晴天和雨天)。这种分组就叫做 Type,它是虚拟的逻辑分组,用来过滤 Document。不同的 Type 应该有相似的结构(schema),举例来说,id字段不能在这个组是字符串,在另一个组是数值。这是与关系型数据库的表的一个区别。性质完全不同的数据(比如products和logs)应该存成两个 Index,而不是一个 Index 里面的两个 Type(虽然可以做到)。下面的命令可以列出每个 Index 所包含的 Type。
    

$ curl ‘localhost:9200/_mapping?pretty=true’

  1. 映射(mapping)

    用于进行字段类型确认,将每个字段匹配为一种确定的数据类型,也称为确切值,若不设置确定的类型,Elasticsearch则按全文文本的类型进行存储且不具备分析能力,确切值(exact values)和全文文本(full text)的区别决定了搜索引擎与数据库的根本差异
    可通过命令(GET /index_name/_mapping/doc_type)查询映射
    Elasticsearch中确切值主要分为:

strings
numbers
booleans
dates
  • 确切值:是某一个确定的值,相当于每一份数据都是唯一的,不可能重复的,保证了查询的数据完全匹配全文文本
  • 全文文本:为非结构化数据,文本化的数据。全文文本会相应的查询相关的数据,根据文档与查询条件的匹配程度来返回搜索结果,保证结果文档与查询条件有较高的相关性
    Elasticsearch对全文文本查询时,首页对文本进行分析,再利用结果建立一个倒排索引
  1. 分析(analysis):用于进行全文文本分词,建立供搜索用的反向索引映射,默认以空格分隔

  2. Shards

    代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。

  3. Replicas

    代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡

  4. Node 与 ClusterElastic

    ClusterElastic代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。es的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部来看es集群,在逻辑上是个整体,你与任何一个节点的通信和与整个es集群通信是等价的。Node 与 ClusterElastic 本质上是一个分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个 Elastic 实例。单个 Elastic 实例称为一个节点(node)。一组节点构成一个集群(cluster)。
    集群和结点

存储原理

当我们进行数据新建的时候,Elasticsearch内部是怎么存储我们提交的数据呢? Elasticsearch 使用一种称为 倒排索引 的结构,它适用于快速的全文搜索。一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。
例如,假设我们有两个文档,每个文档的 source 域包含如下内容:

   1. The quick brown fox jumped over the lazy dog
   2. Quick brown foxes leap over lazy dogs in summer

为了创建倒排索引,我们首先将每个文档的 source 域拆分成单独的 词(我们称它为 词条 或 tokens ),创建一个包含所有不重复词条的排序列表,然后列出每个词条出现在哪个文档。结果如下所示:

TermDoc_1Doc_2
QuickX
TheX
brownXX
dogX
dogsX
foxX
foxesX
inX
jumpedX
lazyXX
leapX
overXX
quickX
summerX
theX

现在,如果我们想搜索 quick brown ,我们只需要查找包含每个词条的文档:

TermDoc_1Doc_2
brownXX
quickX
Total21

在Elasticsearch内部存储的时候,远比我们现在说的复杂,主要包含两个部分,一个是单词词典,一个是倒排列表:
倒排组成

  • 单词词典:
    单词词典的实现是哈希表加链表的形式,在哈希表的key是单词的hash值,值是单词的链表,因为hash算法会有冲突的情况发生,所以这里的值是一个集合,里面保存着相同hash值得单词以及改词指向倒排列表的指针,如图所示:
    单词词典
    记录出现过某个单词的文档列表,同时还记录单词在所有文档中的出现次数偏移位置,倒排列表元素数据结构如下:

    (DocI;TF;<POS>)
    

    其中:
    1. DocID:出现某单词的文档ID
    2. TF(Term Frequency):单词在该文档中出现的次数
    3. POS:单词在文档中的位置

那么上述的两个文档,假设Doc_1的ID为1,Doc_2的ID为2,那么我们实际存储的时候应该是这样的:

   Doc_1: The quick brown fox jumped over the lazy dog
   Doc_2: Quick brown foxes leap over lazy dogs in summer
单词ID单词逆向文档频率倒排列表(DocID;TF;)
1Quick1(<2;1;<1>)
2The1(<1;1;<1>)
3brown2(2;1;<2>),(1;1;<3>)
4dog1(1;1<7>)
5dogs1(1;1;<7>)
6fox1(1;1;<7>)
7foxes1(1;1;<3>)
8in1(<2:1;<8>)
9jumped1(1;1;<5>)
10lazy2(1;1;<8>),(2;1;<6>)
11leap1(2;1;<4>)
12over2(1;1;<6>),(2;1;<6>)
13quick1(1;1;<1>)
14summer1(2;1;<9>)
15the1(1;1;<1>)
比如单词“over”,单词ID为12,在两个文档中出现过,所以逆向文档频率为2,同时倒排索引中的元素也有两个:(1;1;<6>),(2;1;<6>)。拿第一个元素(1;1;<6>)进行说明,他表示“over”在文档ID为1的文档中出现过1次,出现的位置是第六个单词

知道了了倒排索引的内部结构之后,就能很好理解倒排索引的搜索过程了,其内部搜索过程如下图所示:
单词词典.

数据操作

  1. 新建和删除 Index
    新建 Index,可以直接向 Elastic 服务器发出 PUT 请求。下面的例子是新建一个名叫shopsku的 Index。
$ curl -X PUT 'localhost:9200/shopsku

服务器返回一个 JSON 对象,里面的acknowledged字段表示操作成功。
{
“acknowledged”:true,
“shards_acknowledged”:true
}
然后,我们发出 DELETE 请求,删除这个 Index。

$ curl -X DELETE 'localhost:9200/shopsku'
  1. 新增记录
    向指定的 /Index/Type 发送 PUT 请求,就可以在 Index 里面新增一条记录。比如,向/accounts/person发送请求,就可以新增一条人员记录。
$ curl -X PUT 'localhost:9200/accounts/person/1' -d '
{
  "user": "张三",
  "title": "工程师",
  "desc": "数据库管理"
}

服务器返回的 JSON 对象,会给出 Index、Type、Id、Version 等信息。

{
  "_index":"accounts",
  "_type":"person",
  "_id":"1",
  "_version":1,
  "result":"created",
  "_shards":{"total":2,"successful":1,"failed":0},
  "created":true
}

如果你仔细看,会发现请求路径是/accounts/person/1,最后的1是该条记录的 Id。它不一定是数字,任意字符串(比如abc)都可以。新增记录的时候,也可以不指定 Id,这时要改成 POST 请求。

$ curl -X POST 'localhost:9200/accounts/person' -d '
{
  "user": "李四",
  "title": "工程师",
  "desc": "系统管理"
}

上面代码中,向/accounts/person发出一个 POST 请求,添加一个记录。这时,服务器返回的 JSON 对象里面,_id字段就是一个随机字符串。

  {
  "_index":"accounts",
  "_type":"person",
  "_id":"AV3qGfrC6jMbsbXb6k1p",
  "_version":1,
  "result":"created",
  "_shards":{"total":2,"successful":1,"failed":0},
  "created":true
  }

注意,如果没有先创建 Index(这个例子是accounts),直接执行上面的命令,Elastic 也不会报错,而是直接生成指定的 Index。

  1. 查看记录
    向/Index/Type/Id发出 GET 请求,就可以查看这条记录。
$ curl 'localhost:9200/accounts/person/1?pretty=true'

上面代码请求查看/accounts/person/1这条记录,URL 的参数pretty=true表示以易读的格式返回。返回的数据中,found字段表示查询成功,_source字段返回原始记录。

{
  "_index" : "accounts",
  "_type" : "person",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "user" : "张三",
    "title" : "工程师",
    "desc" : "数据库管理"
    }
  }

如果 Id 不正确,就查不到数据,found字段就是false。

$ curl 'localhost:9200/weather/beijing/abc?pretty=true'

{
  "_index" : "accounts",
  "_type" : "person",
  "_id" : "abc",
  "found" : false
}
  1. 删除记录删除记录就是发出 DELETE 请求。
$ curl -X DELETE 'localhost:9200/accounts/person/1'
  1. 更新记录更新记录就是使用 PUT 请求,重新发送一次数据。
$ curl -X PUT 'localhost:9200/accounts/person/1' -d '
{
    "user" : "张三",
    "title" : "工程师",
    "desc" : "数据库管理,软件开发"
}

我们将原始数据从"数据库管理"改成"数据库管理,软件开发"。返回结果里面,有几个字段发生了变化。"_version" : 2,“result” : “updated”,“created” : false可以看到,记录的 Id 没变,但是版本(version)从1变成2,操作类型(result)从created变成updated,created字段变成false,因为这次不是新建记录。

{
  "_index":"accounts",
  "_type":"person",
  "_id":"1",
  "_version":2,
  "result":"updated",
  "_shards":{"total":2,"successful":1,"failed":0},
  "created":false
}
补充

除开我们上面介绍的特性外,底层还包括如下特性:

  1. recovery

      代表数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。
    
  2. river

     代表es的一个数据源,也是其它存储方式(如:数据库)同步数据到es的一个方法。它是以插件方式存在的一个es服务,通过读取river中的数据并把它索引到es中,官方的river有couchDB的,RabbitMQ的,Twitter的,Wikipedia的。
    
  3. gateway

     代表es索引快照的存储方式,es默认是先把索引存放到内存中,当内存满了时再持久化到本地硬盘。gateway对索引快照进行存储,当这个es集群关闭再重新启动时就会从gateway中读取索引备份数据。es支持多种类型的gateway,有本地文件系统(默认),分布式文件系统,Hadoop的HDFS和amazon的s3云存储服务。
    
  4. discovery.zen

     代表es的自动发现节点机制,es是一个基于p2p的系统,它先通过广播寻找存在的节点,再通过多播协议来进行节点之间的通信,同时也支持点对点的交互。
    
  5. Transport

     代表es内部节点或集群与客户端的交互方式,默认内部是使用tcp协议进行交互,同时它支持http协议(json格式)、thrift、servlet、memcached、zeroMQ等的传输协议(通过插件方式集成)。
    
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ExtraMile

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值