精华内容
下载资源
问答
  • ES索引存储原理

    2020-05-14 15:57:07
    ES索引存储原理 不变性 写到磁盘的倒序索引是不变的:自从写到磁盘就再也不变。 这会有很多好处: 不需要添加锁。不存在写操作,因此不存在多线程更改数据。 提高读性能。一旦索引被内核的文件系统做了Cache,绝大...

    转载:
    https://blog.csdn.net/guoyuguang0/article/details/76769184
    https://www.jianshu.com/p/28fb017be7a7/
    https://www.infoq.cn/article/UotLIglvj6TcUE2vxC5X
    https://zhuanlan.zhihu.com/p/48429223?from_voters_page=true
    https://zhuanlan.zhihu.com/p/91816296

    ES索引存储原理

    不变性

    写到磁盘的倒序索引是不变的:自从写到磁盘就再也不变。
    这会有很多好处:

    • 不需要添加锁。不存在写操作,因此不存在多线程更改数据。
    • 提高读性能。一旦索引被内核的文件系统做了Cache,绝大多数的读操作会直接从内存而不需要经过磁盘。
    • 提升其他缓存(例如fiter cache)的性能。其他的缓存在该索引的生命周期内保持有效,减少磁盘I/O和计算消耗。

    当然,索引的不变性也有缺点。如果你想让新修改过的文档可以被搜索到,你必须重新构建整个索引。这在一个index可以容纳的数据量和一个索引可以更新的频率上都是一个限制。

    如何在不丢失不变形的好处下让倒序索引可以更改?答案是:使用不只一个的索引。 新添额外的索引来反映新的更改来替代重写所有倒序索引的方案。

    Lucene引进了per-segment搜索的概念。一个segment是一个完整的倒序索引的子集,所以现在index在Lucene中的含义就是一个segments的集合,每个segment都包含一些提交点(commit point)。

    segment工作流程

    1.新的文档在内存中组织。
    2.每隔一段时间,buffer将会被提交: 生成一个新的segment(一个额外的新的倒序索引)并被写到磁盘,同时一个
      新的提交点(commit point)被写入磁盘,包含新的segment的名称。 磁盘fsync,所有在内核文件系统中的数据等待被写入到磁盘,来保障它们被物理写入。
    3.新的segment被打开,使它包含的文档可以被索引。
    4.内存中的buffer将被清理,准备接收新的文档。
    

    当一个新的请求来时,会遍历所有的segments。词条分析程序会聚合所有的segments来保障每个文档和词条相关性的准确。通过这种方式,新的文档轻量的可以被添加到对应的索引中。

    删除和更新

    segments是不变的,所以文档不能从旧的segments中删除,也不能在旧的segments中更新来映射一个新的文档版本。取之的是,每一个提交点都会包含一个.del文件,列举了哪一个segmen的哪一个文档已经被删除了。 当一个文档被”删除”了,它仅仅是在.del文件里被标记了一下。被”删除”的文档依旧可以被索引到,但是它将会在最终结果返回时被移除掉。

    文档的更新同理:当文档更新时,旧版本的文档将会被标记为删除,新版本的文档在新的segment中建立索引。也许新旧版本的文档都会本检索到,但是旧版本的文档会在最终结果返回时被移除。

    实时索引

    在上述的per-segment搜索的机制下,新的文档会在分钟级内被索引,但是还不够快。 瓶颈在磁盘。将新的segment提交到磁盘需要fsync来保障物理写入。但是fsync是很耗时的。它不能在每次文档更新时就被调用,否则性能会很低。 现在需要一种轻便的方式能使新的文档可以被索引,这就意味着不能使用fsync来保障。 在ES和物理磁盘之间是内核的文件系统缓存。之前的描述中,在内存中索引的文档会被写入到一个新的segment。但是现在我们将segment首先写入到内核的文件系统缓存,这个过程很轻量,然后再flush到磁盘,这个过程很耗时。但是一旦一个segment文件在内核的缓存中,它可以被打开被读取。

    更新持久化

    不使用fsync将数据flush到磁盘,我们不能保障在断电后或者进程死掉后数据不丢失。ES是可靠的,它可以保障数据被持久化到磁盘。一个完全的提交会将segments写入到磁盘,并且写一个提交点,列出所有已知的segments。当ES启动或者重新打开一个index时,它会利用这个提交点来决定哪些segments属于当前的shard。 如果在提交点时,文档被修改会怎么样?

    translog日志提供了一个所有还未被flush到磁盘的操作的持久化记录。当ES启动的时候,它会使用最新的commit point从磁盘恢复所有已有的segments,然后将重现所有在translog里面的操作来添加更新,这些更新发生在最新的一次commit的记录之后还未被fsync。

    translog日志也可以用来提供实时的CRUD。当你试图通过文档ID来读取、更新、删除一个文档时,它会首先检查translog日志看看有没有最新的更新,然后再从响应的segment中获得文档。这意味着它每次都会对最新版本的文档做操作,并且是实时的。

    Segment合并

    通过每隔一秒的自动刷新机制会创建一个新的segment,用不了多久就会有很多的segment。segment会消耗系统的文件句柄,内存,CPU时钟。最重要的是,每一次请求都会依次检查所有的segment。segment越多,检索就会越慢。

    ES通过在后台merge这些segment的方式解决这个问题。小的segment merge到大的,大的merge到更大的。。。

    这个过程也是那些被“删除”的文档真正被清除出文件系统的过程,因为被标记为删除的文档不会被拷贝到大的segment中。

    Segment

    • Inverted Index

    Inverted Index主要包括两部分:
    一个有序的数据字典Dictionary。
    与单词Term对应的Postings(即存在这个单词的文件)。

    • Document Values

    即使这样,我们发现以上结构仍然无法解决诸如:排序、聚合、facet,因为我们可能会要读取大量不需要的信息。
    所以,另一种数据结构解决了此种问题:Document Values。这种结构本质上就是一个列式的存储,它高度优化了具有相同类型的数据的存储结构。

    在这里插入图片描述
    为了提高效率,ElasticSearch可以将索引下某一个Document Value全部读取到内存中进行操作,这大大提升访问速度,但是也同时会消耗掉大量的内存空间。

    • Stored Fields

    当我们想要查找包含某个特定标题内容的文件时,Inverted Index就不能很好的解决这个问题,所以Lucene提供了另外一种数据结构Stored Fields来解决这个问题。本质上,StoredFields是一个简单的键值对key-value。默认情况下,ElasticSearch会存储整个文件的JSON source。

    在这里插入图片描述
    总之,这些数据结构Inverted IndexStored FieldsDocument Values及其缓存,都在segment内部。

    • Cache
      当一个真实请求来的时候,如下所示:
      在这里插入图片描述

    存储索引的流程

    从数据到索引,数据的流向如下:
    在这里插入图片描述

    总结

    在这里插入图片描述
    索引过程:

    1. 有一系列被索引文件

    2. 被索引文件经过语法分析和语言处理形成一系列词(Term) 。

    3. 经过索引创建形成词典和反向索引表。

    4. 通过索引存储将索引写入硬盘。

    搜索过程:

    1. 用户输入查询语句。

    2. 对查询语句经过语法分析和语言分析得到一系列词(Term) 。

    3. 通过语法分析得到一个查询树。

    4. 通过索引存储将索引读入到内存。

    5. 利用查询树搜索索引,从而得到每个词(Term) 的文档链表,对文档链表进行交,差,并得到结果文档。

    6. 将搜索到的结果文档对查询的相关性进行排序。

    7. 返回查询结果给用户。

    展开全文
  • 分布式文档存储 ES分布式特性 ...一个集群拥有相同的cluster.name 配置的节点组成, 它们共同承担数据和负载的压力 主节点负责管理集群的变更例如增加、删除索引,或者增加、删除节点等。 而主节点并...

    分布式文档存储

    ES分布式特性

    • 屏蔽了分布式系统的复杂性
    • 集群内的原理
      • 垂直扩容和水平扩容
      • 真正的扩容能力是来自于水平扩容–为集群添加更多的节点,并且将负载压力和稳定性分散到这些节点中

     

    ES集群特点

    • 一个集群拥有相同的cluster.name 配置的节点组成, 它们共同承担数据和负载的压力
    • 主节点负责管理集群的变更例如增加、删除索引,或者增加、删除节点等。 而主节点并不需要涉及到文档级别的变更和搜索等操作
    • 集群健康
    GET /_cluster/health
    返回值中的status 是我们关注的
    • green 主副分片均正常
    • yellow 主都正常,不是所有的副都正常
    • red 所有主分片都不正常
    • 分片的特点
      • Elasticsearch 是利用分片将数据分发到集群内各处
      • 分片是数据的容器,文档保存在分片内
      • 分片又被分配到集群内的各个节点里
      • 当集群规模变动,ES会自动在各个节点中迁移分片。使得数据任然均匀分布在集群中
      • 副分片是主分片的一个拷贝,作为硬件故障时的备份。并提供返回文档读操作
      • 在创建索引时,确定主分片数,但是副分片可以在后面进行更改

     

    在更新一个文档时的ES内部操作

    • Elasticsearch 已将旧文档标记为已删除,并增加一个全新的文档。
    • 尽管你不能再对旧版本的文档进行访问,但它并不会立即消失。
    • 当继续索引更多的数据,Elasticsearch 会在后台清理这些已删除文档

     

    ES如何处理冲突

    • 使用乐观并发控制
    • 利用 _version 号来确保 应用中相互冲突的变更不会导致数据丢失
    • 通过外部系统使用版本控制

     

    文档的部分更新

    • 文档不能被修改,只能被替换

     

    如何路由一个文档到一个分片中

    • 当索引一个文档时,我们怎么知道这个文档在什么位置
    • 使用下面的这个路由选择公式
    shard = hash(routing) % number_of_primary_shards
    • 下面将对这个公式每个字段进行分析
      • shard 哪个分片, 也就是分片id
      • routing 一个可变值,默认是文档的id
      • hash 一个哈希函数,对rounting字段进行哈希计算生成一个数字
      • number_of_primary_shards 主分片的数量,routing字段经过hash函数计算之后的值,将对 主分片的数量也就是 number_of_primary_shards 进行取与,之后得到的shard就是我们文档所在的分片的位置

     

    主分片和副分片如何交互

    • 假设一个集群由三个节点组成。有一个索引,这个索引有两个主分片,每个主分片有两个副分片相同的分片的副本不会放在同一个节点上
    •  

    • 请求发送到集群任意节点,每个节点都有能力处理请求。每个节点都知道集群中任一文档的位置,所以可以将请求转发到需求节点上

     

    新建、索引和删除单个文档 时的流程

    •  

      1. 先向 node 1 来一个请求这个请求可能是发送新建,索引或者删除文档等。
      2. node 1 节点根据文档的_id 确定文档属于分片0, 请求被转发到node3 节点
      3. node 3 在主分片执行了请求,如果主分片执行成功了,它将请求转发给node1 和node 2 节点。当所有的副分片都执行成功,node 3 将协调节点报告成功,并向客户端报告完成
    • consistency 参数的值可以设为 one (只要主分片状态 ok 就允许执行操作),all(必须要主分片和所有副本分片的状态没问题才允许执行_写_操作), 或quorum 。默认值为 quorum , 即大多数的分片副本状态没问题就允许执行操作

    • 在执行一个写操作时,主分片都需要必须有一个规定数量的(quorum),也就是在大多数主副分片处于活跃状态。这样是防止在网络分区故障是执行写操作会导致数据不一致
    1.quorum = int( (primary + number_of_replicas) / 2 ) + 1

     

    取回一个文档

    • 可以从主分片或者任意副本分片检索文档
    •  

      1. 某个请求向node 1 发送获取请求 节点使用
      2. 节点使用节点文档_ID来确定文档属于分片0, 分片0 的副本分片存在于所有的三个节点上,在这种情况下,他将请求转发到node 2
      3. node 2 将文档返回给node 1 ,然后将文档返回给客户端
    • 在每次处理读取请求时,协调结点在每次请求的时候都会轮训所有的副本片来达到负载均衡

     

    局部更新文档

    •  

    • 部分更新一个文档的步骤
      1. 客户端向node1 发送一个请求
      2. 它将请求转发到主分片这个文档所在的Node 3
      3. node 3从主分片检索文档,修改_Source json ,并且尝试重新索引主分片的文档。如果文档被另一个进程修改,他会重复步骤3 知道超过retry_on_conflict 次后放弃
      4. node 3 成功更新文档,它将新版本的文档并行转发到node 1 和node 2 的副本分片,重新建立索引。所有副本分片都返回成功,node 3 向协调节点也返回成功,协调节点向客户端返回成功
      5. update 操作也支持 新建索引的时的那些参数 routing 、 replication 、 consistency 和 timeout

     

    多文档模式

    • mget 和 bulk API 的 模式类似于单文档模式。 协调节点知道每个文档的位置,将多个文档分解成每个文档的的多文档请求,并且将这些请求并行的转发到每个参与节点中 。
    • 使用 mget 取回多个文档
    •  

      1. 客户端向node 1 发送一个mget请求
      2. node 1 向每个分片构建多文档请求,并行的转发这些请求到托管在每个所需的主分盘或者副分片的节点上一旦收到所有的额回复,node 1 构建响应并将其返回给客户端
    • 使用 bulk 修改多个文档
    •  

      1. 一个bulk请求请求到node 1
      2. node 1 为每个节点创建一个批量请求,并将这些请求并行转发到每个包含主分片的节点
      3. 主分片一个接一个按顺序执行每个操作。当每个操作成功时,主分片并行转发新文档(或删除)到副本分片,然后执行下一个操作。 一旦所有的副本分片报告所有操作成功,该节点将向协调节点报告成功,协调节点将这些响应收集整理并返回给客户端

     

    搜索—–最基本的工具

    • ElastcSearch 的三个基本概念
      1. 映射 Mapping 描述数据在每个字段是如何存储的
      2. 分析 Analysis 全文如何处理使之可以被搜索到
      3. Query DSL ES中强大灵活的查询语言
    • 空搜索
      • GET /_search 没有指定任何查询的搜索包括没有指定索引

    1.**查询获取之后**

    {
    "took": 8, //请求耗费多少毫秒
    "timed_out": false,//是否超时
    "_shards": {//在查询中参与分片的总数,成功多少,失败多少
    "total": 42,//总分片数
    "successful": 42,//成功数
    "skipped": 0,//跳过数
     "failed": 0//失败数
     },
     "hits": {//hits指返回的结果集
     "total": 6184,//总文档数量
     "max_score": 1,
     "hits": [
     {
     "_index": ".kibana", //索引名称
     "_type": "config",//索引type
     "_id": "5.6.3",//文档在这个索引下的id
     "_score": 1,//索引得分,是查询后的计算得来的
     "_source": {
     "buildNum": 15554
     }
     },
     
    展开全文
  • ES索引存储原理 不变性 写到磁盘的倒序索引是不变的:自从写到磁盘就再也不变。 这会有很多好处: 不需要添加锁。不存在写操作,因此不存在多线程更改数据。 提高读性能。一旦索引被内核的文件系统做了Cache,...

    ES索引存储原理


    不变性


    写到磁盘的倒序索引是不变的:自从写到磁盘就再也不变。 这会有很多好处:

    不需要添加锁。不存在写操作,因此不存在多线程更改数据。
    提高读性能。一旦索引被内核的文件系统做了Cache,绝大多数的读操作会直接从内存而不需要经过磁盘。
    提升其他缓存(例如fiter cache)的性能。其他的缓存在该索引的生命周期内保持有效,减少磁盘I/O和计算消耗。


    当然,索引的不变性也有缺点。如果你想让新修改过的文档可以被搜索到,你必须重新构建整个索引。这在一个index可以容纳的数据量和一个索引可以更新的频率上都是一个限制。

    如何在不丢失不变形的好处下让倒序索引可以更改?答案是:使用不只一个的索引。 新添额外的索引来反映新的更改来替代重写所有倒序索引的方案。 Lucene引进了per-segment搜索的概念。一个segment是一个完整的倒序索引的子集,所以现在index在Lucene中的含义就是一个segments的集合,每个segment都包含一些提交点(commit point)。

    segment工作流程

    1.新的文档在内存中组织。
    2.每隔一段时间,buffer将会被提交: 生成一个新的segment(一个额外的新的倒序索引)并被写到磁盘,同时一个
      新的提交点(commit point)被写入磁盘,包含新的segment的名称。 磁盘fsync,所有在内核文件系统中的数据等待被写入到磁盘,来保障它们被物理写入。
    3.新的segment被打开,使它包含的文档可以被索引。
    4.内存中的buffer将被清理,准备接收新的文档。
    


    当一个新的请求来时,会遍历所有的segments。词条分析程序会聚合所有的segments来保障每个文档和词条相关性的准确。通过这种方式,新的文档轻量的可以被添加到对应的索引中。

    删除和更新


    segments是不变的,所以文档不能从旧的segments中删除,也不能在旧的segments中更新来映射一个新的文档版本。取之的是,每一个提交点都会包含一个.del文件,列举了哪一个segmen的哪一个文档已经被删除了。 当一个文档被”删除”了,它仅仅是在.del文件里被标记了一下。被”删除”的文档依旧可以被索引到,但是它将会在最终结果返回时被移除掉。

    文档的更新同理:当文档更新时,旧版本的文档将会被标记为删除,新版本的文档在新的segment中建立索引。也许新旧版本的文档都会本检索到,但是旧版本的文档会在最终结果返回时被移除。

    实时索引


    在上述的per-segment搜索的机制下,新的文档会在分钟级内被索引,但是还不够快。 瓶颈在磁盘。将新的segment提交到磁盘需要fsync来保障物理写入。但是fsync是很耗时的。它不能在每次文档更新时就被调用,否则性能会很低。 现在需要一种轻便的方式能使新的文档可以被索引,这就意味着不能使用fsync来保障。 在ES和物理磁盘之间是内核的文件系统缓存。之前的描述中,在内存中索引的文档会被写入到一个新的segment。但是现在我们将segment首先写入到内核的文件系统缓存,这个过程很轻量,然后再flush到磁盘,这个过程很耗时。但是一旦一个segment文件在内核的缓存中,它可以被打开被读取

    更新持久化


    不使用fsync将数据flush到磁盘,我们不能保障在断电后或者进程死掉后数据不丢失。ES是可靠的,它可以保障数据被持久化到磁盘。一个完全的提交会将segments写入到磁盘,并且写一个提交点,列出所有已知的segments。当ES启动或者重新打开一个index时,它会利用这个提交点来决定哪些segments属于当前的shard。 如果在提交点时,文档被修改会怎么样?

    translog日志提供了一个所有还未被flush到磁盘的操作的持久化记录。当ES启动的时候,它会使用最新的commit point从磁盘恢复所有已有的segments,然后将重现所有在translog里面的操作来添加更新,这些更新发生在最新的一次commit的记录之后还未被fsync。

    translog日志也可以用来提供实时的CRUD。当你试图通过文档ID来读取、更新、删除一个文档时,它会首先检查translog日志看看有没有最新的更新,然后再从响应的segment中获得文档。这意味着它每次都会对最新版本的文档做操作,并且是实时的。

    Segment合并


    通过每隔一秒的自动刷新机制会创建一个新的segment,用不了多久就会有很多的segment。segment会消耗系统的文件句柄,内存,CPU时钟。最重要的是,每一次请求都会依次检查所有的segment。segment越多,检索就会越慢。

    ES通过在后台merge这些segment的方式解决这个问题。小的segment merge到大的,大的merge到更大的。。。

    这个过程也是那些被”删除”的文档真正被清除出文件系统的过程,因为被标记为删除的文档不会被拷贝到大的segment中。

    Segment:

    Inverted Index

    Inverted Index主要包括两部分:

    1. 一个有序的数据字典Dictionary(包括单词Term和它出现的频率)。
    2. 与单词Term对应的Postings(即存在这个单词的文件)。        

    Stored Fields:

    当我们想要查找包含某个特定标题内容的文件时,Inverted Index就不能很好的解决这个问题,所以Lucene提供了另外一种数据结构Stored Fields来解决这个问题。本质上,Stored Fields是一个简单的键值对key-value。默认情况下,ElasticSearch会存储整个文件的JSON source。

    Document Values

    官网:https://www.elastic.co/guide/cn/elasticsearch/guide/current/docvalues.html#docvalues

    即使这样,我们发现以上结构仍然无法解决诸如:排序、聚合、facet,因为我们可能会要读取大量不需要的信息。
    所以,另一种数据结构解决了此种问题:Document Values。这种结构本质上就是一个列式的存储,它高度优化了具有相同类型的数据的存储结构。

    为了提高效率,ElasticSearch可以将索引下某一个Document Value全部读取到内存中进行操作,这大大提升访问速度,但是也同时会消耗掉大量的内存空间。

    总之,这些数据结构Inverted Index、Stored Fields、Document Values及其缓存,都在segment内部。

    Cache

    当一个真实请求来的时候,如下所示:


    存储索引的流程
    从数据到索引,数据的流向如下:

    数据生成索引存入内存Buffer,同时存入TranSlog
    内存中的数据每隔一秒以segment的形式写入系统文件缓存
    每隔一段时间,文件缓存中的数据存入硬盘,同时清除对应的translog


    Lucene 工作流程


    如何创建索引
    找出文档

    文件一:Students should be allowed to Go out with their friends, but not allowed to drink beer.

    文件二:My friend Jerry went to school to see his students but found them drunk which is not allowed.

    将原文档传给分次组件(Tokenizer)

    分词组件(Tokenizer)会做以下几件事情( 此过程称为Tokenize) :

    将文档分成一个一个单独的单词。
    去除标点符号。
    去除停词(Stop word) 。
    所谓停词(Stop word)就是一种语言中最普通的一些单词,由于没有特别的意义,因而大多数情况下不能成为搜索的关键词,因而创建索引时,这种词会被去掉而减少索引的大小。经过分词(Tokenizer) 后得到的结果称为词元(Token) 。
    在我们的例子中,便得到以下词元(Token):
    “Students”,“allowed”,“go”,“their”,“friends”,“allowed”,“drink”,“beer”,“My”,“friend”,“Jerry”,“went”,“school”,“see”,

    将得到的词元(Token)传给语言处理组件(Linguistic Processor)

    语言处理组件(linguistic processor)主要是对得到的词元(Token)做一些同语言相关的处理。
    对于英语,语言处理组件(Linguistic Processor) 一般做以下几点:

    变为小写(Lowercase) 。
    将单词缩减为词根形式,如“cars ”到“car ”等。这种操作称为:stemming 。
    将单词转变为词根形式,如“drove ”到“drive ”等。这种操作称为:lemmatization 。
    在我们的例子中,经过语言处理,得到的词(Term)如下:
    “student”,“allow”,“go”,“their”,“friend”,“allow”,“drink”,“beer”,“my”,“friend”,“jerry”,“go”,“school”,“see”,“his”,“student”,“find”,“them

    将得到的词(Term)传给索引组件(Indexer)

    索引 组件(Indexer)主要做以下几件事情:

    1. 利用得到的词(Term)创建一个字典。
    2. 对字典按字母顺序进行排序。
    3. 合并相同的词(Term) 成为文档倒排(Posting List) 链表。
    4. 到此为止索引已经建好。

    如何检索数据:

    1. 用户输入查询语句
    2. 对查询语句进行词法分析,语法分析,及语言处理
    3. 词法分析主要用来识别单词和关键字。
    4. 语法分析主要是根据查询语句的语法规则来形成一棵语法树。
    5. 语言处理同索引过程中的语言处理几乎相同。
    6. 如learned变成learn,tables 变成table等。
    7. 搜索索引,得到符合语法树的文档。

    此步骤有分几小步:

    1. 首先,在反向索引表中,分别找出包含lucene,learn,hadoop的文档链表。
    2. 其次,对包含lucene,learn的链表进行合并操作,得到既包含lucene又包含learn的文档链表。
    3. 然后,将此链表与hadoop的文档链表进行差操作,去除包含hadoop的文档,从而得到既包含lucene又包含learn而且不包含hadoop的文档链表。

    此文档链表就是我们要找的文档。

    根据得到的文档和查询语句的相关性,对结果进行排序

    1. 首先,一个文档有很多词(Term)组成
    2. 其次对于文档之间的关系,不同的Term重要性不同
    3. 找出词(Term) 对文档的重要性的过程称为计算词的权重(Term weight) 的过程。
    4. 判断词(Term) 之间的关系从而得到文档相关性的过程应用一种叫做向量空间模型的算法

    计算权重的过程:
    影响一个词(Term)在一篇文档中的重要性主要有两个因素:

    1. Term Frequency (tf):即此Term在此文档中出现了多少次。tf 越大说明越重要。
    2. Document Frequency (df):即有多少文档包含次Term。df 越大说明越不重要。
       


    这仅仅只term weight计算公式的简单典型实现。实现全文检索系统的人会有自己的实现,Lucene就与此稍有不同。

    判断Term之间的关系从而得到文档相关性的过程,也即向量空间模型的算法(VSM)
    我们把文档看作一系列词(Term),每一个词(Term)都有一个权重(Term weight),不同的词(Term)根据自己在文档中的权重来影响文档相关性的打分计算。

    于是我们把所有此文档中词(term)的权重(term weight) 看作一个向量。

    Document = {term1, term2, …… ,term N}

    Document Vector = {weight1, weight2, …… ,weight N}

    同样我们把查询语句看作一个简单的文档,也用向量来表示。

    Query = {term1, term 2, …… , term N}

    Query Vector = {weight1, weight2, …… , weight N}

    我们把所有搜索出的文档向量及查询向量放到一个N维空间中,每个词(term)是一维。


    我们认为两个向量之间的夹角越小,相关性越大。

    所以我们计算夹角的余弦值作为相关性的打分,夹角越小,余弦值越大,打分越高,相关性越大。

    有人可能会问,查询语句一般是很短的,包含的词(Term)是很少的,因而查询向量的维数很小,而文档很长,包含词(Term)很多,文档向量维数很大。你的图中两者维数怎么都是N呢?

    在这里,既然要放到相同的向量空间,自然维数是相同的,不同时,取二者的并集,如果不含某个词(Term)时,则权重(Term Weight)为0。


    举个例子,查询语句有11个Term,共有三篇文档搜索出来。其中各自的权重(Term weight),如下.

    于是文档二相关性最高,先返回,其次是文档一,最后是文档三。

    到此为止,我们可以找到我们最想要的文档了。

    总结


    索引过程:

    1) 有一系列被索引文件

    2) 被索引文件经过语法分析和语言处理形成一系列词(Term) 。

    3) 经过索引创建形成词典和反向索引表。

    4) 通过索引存储将索引写入硬盘。

    搜索过程:

    a) 用户输入查询语句。

    b) 对查询语句经过语法分析和语言分析得到一系列词(Term) 。

    c) 通过语法分析得到一个查询树。

    d) 通过索引存储将索引读入到内存。

    e) 利用查询树搜索索引,从而得到每个词(Term) 的文档链表,对文档链表进行交,差,并得到结果文档。

    f) 将搜索到的结果文档对查询的相关性进行排序

    g) 返回查询结果给用户。
    ————————————————
    版权声明:本文为CSDN博主「guoyuguang0」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/guoyuguang0/article/details/76769184

    展开全文
  • ES索引存储原理 不变性 写到磁盘的倒序索引是不变的:自从写到磁盘就再也不变。 这会有很多好处: 不需要添加锁。不存在写操作,因此不存在多线程更改数据。 提高读性能。一旦索引被内核的文件系统做了Cache,绝大...

    ES索引存储原理
    不变性
    写到磁盘的倒序索引是不变的:自从写到磁盘就再也不变。 这会有很多好处:

    不需要添加锁。不存在写操作,因此不存在多线程更改数据。
    提高读性能。一旦索引被内核的文件系统做了Cache,绝大多数的读操作会直接从内存而不需要经过磁盘。
    提升其他缓存(例如fiter cache)的性能。其他的缓存在该索引的生命周期内保持有效,减少磁盘I/O和计算消耗。
    当然,索引的不变性也有缺点。如果你想让新修改过的文档可以被搜索到,你必须重新构建整个索引。这在一个index可以容纳的数据量和一个索引可以更新的频率上都是一个限制。

    如何在不丢失不变形的好处下让倒序索引可以更改?答案是:使用不只一个的索引。 新添额外的索引来反映新的更改来替代重写所有倒序索引的方案。 Lucene引进了per-segment搜索的概念。一个segment是一个完整的倒序索引的子集,所以现在index在Lucene中的含义就是一个segments的集合,每个segment都包含一些提交点(commit point)。

    segment工作流程
    1.新的文档在内存中组织。
    2.每隔一段时间,buffer将会被提交: 生成一个新的segment(一个额外的新的倒序索引)并被写到磁盘,同时一个
    新的提交点(commit point)被写入磁盘,包含新的segment的名称。 磁盘fsync,所有在内核文件系统中的数据等待被写入到磁盘,来保障它们被物理写入。
    3.新的segment被打开,使它包含的文档可以被索引。
    4.内存中的buffer将被清理,准备接收新的文档。
    1
    2
    3
    4
    5
    当一个新的请求来时,会遍历所有的segments。词条分析程序会聚合所有的segments来保障每个文档和词条相关性的准确。通过这种方式,新的文档轻量的可以被添加到对应的索引中。

    删除和更新
    segments是不变的,所以文档不能从旧的segments中删除,也不能在旧的segments中更新来映射一个新的文档版本。取之的是,每一个提交点都会包含一个.del文件,列举了哪一个segmen的哪一个文档已经被删除了。 当一个文档被”删除”了,它仅仅是在.del文件里被标记了一下。被”删除”的文档依旧可以被索引到,但是它将会在最终结果返回时被移除掉。

    文档的更新同理:当文档更新时,旧版本的文档将会被标记为删除,新版本的文档在新的segment中建立索引。也许新旧版本的文档都会本检索到,但是旧版本的文档会在最终结果返回时被移除。

    实时索引
    在上述的per-segment搜索的机制下,新的文档会在分钟级内被索引,但是还不够快。 瓶颈在磁盘。将新的segment提交到磁盘需要fsync来保障物理写入。但是fsync是很耗时的。它不能在每次文档更新时就被调用,否则性能会很低。 现在需要一种轻便的方式能使新的文档可以被索引,这就意味着不能使用fsync来保障。 在ES和物理磁盘之间是内核的文件系统缓存。之前的描述中,在内存中索引的文档会被写入到一个新的segment。但是现在我们将segment首先写入到内核的文件系统缓存,这个过程很轻量,然后再flush到磁盘,这个过程很耗时。但是一旦一个segment文件在内核的缓存中,它可以被打开被读取。

    更新持久化
    不使用fsync将数据flush到磁盘,我们不能保障在断电后或者进程死掉后数据不丢失。ES是可靠的,它可以保障数据被持久化到磁盘。一个完全的提交会将segments写入到磁盘,并且写一个提交点,列出所有已知的segments。当ES启动或者重新打开一个index时,它会利用这个提交点来决定哪些segments属于当前的shard。 如果在提交点时,文档被修改会怎么样?

    translog日志提供了一个所有还未被flush到磁盘的操作的持久化记录。当ES启动的时候,它会使用最新的commit point从磁盘恢复所有已有的segments,然后将重现所有在translog里面的操作来添加更新,这些更新发生在最新的一次commit的记录之后还未被fsync。

    translog日志也可以用来提供实时的CRUD。当你试图通过文档ID来读取、更新、删除一个文档时,它会首先检查translog日志看看有没有最新的更新,然后再从响应的segment中获得文档。这意味着它每次都会对最新版本的文档做操作,并且是实时的。

    Segment合并
    通过每隔一秒的自动刷新机制会创建一个新的segment,用不了多久就会有很多的segment。segment会消耗系统的文件句柄,内存,CPU时钟。最重要的是,每一次请求都会依次检查所有的segment。segment越多,检索就会越慢。

    ES通过在后台merge这些segment的方式解决这个问题。小的segment merge到大的,大的merge到更大的。。。

    这个过程也是那些被”删除”的文档真正被清除出文件系统的过程,因为被标记为删除的文档不会被拷贝到大的segment中。

    Segment
    Inverted Index

    Inverted Index主要包括两部分:

    一个有序的数据字典Dictionary(包括单词Term和它出现的频率)。
    与单词Term对应的Postings(即存在这个单词的文件)。
    Stored Fields

    当我们想要查找包含某个特定标题内容的文件时,Inverted Index就不能很好的解决这个问题,所以Lucene提供了另外一种数据结构Stored Fields来解决这个问题。本质上,Stored Fields是一个简单的键值对key-value。默认情况下,ElasticSearch会存储整个文件的JSON source。

    这里写图片描述

    Document Values

    即使这样,我们发现以上结构仍然无法解决诸如:排序、聚合、facet,因为我们可能会要读取大量不需要的信息。
    所以,另一种数据结构解决了此种问题:Document Values。这种结构本质上就是一个列式的存储,它高度优化了具有相同类型的数据的存储结构。

    这里写图片描述

    为了提高效率,ElasticSearch可以将索引下某一个Document Value全部读取到内存中进行操作,这大大提升访问速度,但是也同时会消耗掉大量的内存空间。

    总之,这些数据结构Inverted Index、Stored Fields、Document Values及其缓存,都在segment内部。

    Cache

    当一个真实请求来的时候,如下所示:
    这里写图片描述

    存储索引的流程
    从数据到索引,数据的流向如下:

    这里写图片描述

    数据生成索引存入内存Buffer,同时存入TranSlog
    内存中的数据每隔一秒以segment的形式写入系统文件缓存
    每隔一段时间,文件缓存中的数据存入硬盘,同时清除对应的translog
    Lucene 工作流程
    如何创建索引
    找出文档

    文件一:Students should be allowed to Go out with their friends, but not allowed to drink beer.

    文件二:My friend Jerry went to school to see his students but found them drunk which is not allowed.

    将原文档传给分次组件(Tokenizer)

    分词组件(Tokenizer)会做以下几件事情( 此过程称为Tokenize) :

    将文档分成一个一个单独的单词。
    去除标点符号。
    去除停词(Stop word) 。
    所谓停词(Stop word)就是一种语言中最普通的一些单词,由于没有特别的意义,因而大多数情况下不能成为搜索的关键词,因而创建索引时,这种词会被去掉而减少索引的大小。经过分词(Tokenizer) 后得到的结果称为词元(Token) 。
    在我们的例子中,便得到以下词元(Token):
    “Students”,“allowed”,“go”,“their”,“friends”,“allowed”,“drink”,“beer”,“My”,“friend”,“Jerry”,“went”,“school”,“see”,

    将得到的词元(Token)传给语言处理组件(Linguistic Processor)

    语言处理组件(linguistic processor)主要是对得到的词元(Token)做一些同语言相关的处理。
    对于英语,语言处理组件(Linguistic Processor) 一般做以下几点:

    变为小写(Lowercase) 。
    将单词缩减为词根形式,如“cars ”到“car ”等。这种操作称为:stemming 。
    将单词转变为词根形式,如“drove ”到“drive ”等。这种操作称为:lemmatization 。
    在我们的例子中,经过语言处理,得到的词(Term)如下:
    “student”,“allow”,“go”,“their”,“friend”,“allow”,“drink”,“beer”,“my”,“friend”,“jerry”,“go”,“school”,“see”,“his”,“student”,“find”,“them

    将得到的词(Term)传给索引组件(Indexer)

    索引 组件(Indexer)主要做以下几件事情:

    利用得到的词(Term)创建一个字典。
    对字典按字母顺序进行排序。
    合并相同的词(Term) 成为文档倒排(Posting List) 链表。
    到此为止索引已经建好。

    如何检索数据

    用户输入查询语句
    对查询语句进行词法分析,语法分析,及语言处理

    词法分析主要用来识别单词和关键字。

    语法分析主要是根据查询语句的语法规则来形成一棵语法树。

    语言处理同索引过程中的语言处理几乎相同。
    如learned变成learn,tables 变成table等。

    搜索索引,得到符合语法树的文档。

    此步骤有分几小步:

    首先,在反向索引表中,分别找出包含lucene,learn,hadoop的文档链表。
    其次,对包含lucene,learn的链表进行合并操作,得到既包含lucene又包含learn的文档链表。
    然后,将此链表与hadoop的文档链表进行差操作,去除包含hadoop的文档,从而得到既包含lucene又包含learn而且不包含hadoop的文档链表。
    此文档链表就是我们要找的文档。

    根据得到的文档和查询语句的相关性,对结果进行排序
    首先,一个文档有很多词(Term)组成
    其次对于文档之间的关系,不同的Term重要性不同
    找出词(Term) 对文档的重要性的过程称为计算词的权重(Term weight) 的过程。
    判断词(Term) 之间的关系从而得到文档相关性的过程应用一种叫做向量空间模型的算法

    计算权重的过程
    影响一个词(Term)在一篇文档中的重要性主要有两个因素:

    Term Frequency (tf):即此Term在此文档中出现了多少次。tf 越大说明越重要。
    Document Frequency (df):即有多少文档包含次Term。df 越大说明越不重要。
    1
    2
    这里写图片描述

    这仅仅只term weight计算公式的简单典型实现。实现全文检索系统的人会有自己的实现,Lucene就与此稍有不同。

    判断Term之间的关系从而得到文档相关性的过程,也即向量空间模型的算法(VSM)
    我们把文档看作一系列词(Term),每一个词(Term)都有一个权重(Term weight),不同的词(Term)根据自己在文档中的权重来影响文档相关性的打分计算。

    于是我们把所有此文档中词(term)的权重(term weight) 看作一个向量。

    Document = {term1, term2, …… ,term N}

    Document Vector = {weight1, weight2, …… ,weight N}

    同样我们把查询语句看作一个简单的文档,也用向量来表示。

    Query = {term1, term 2, …… , term N}

    Query Vector = {weight1, weight2, …… , weight N}

    我们把所有搜索出的文档向量及查询向量放到一个N维空间中,每个词(term)是一维。
    这里写图片描述

    我们认为两个向量之间的夹角越小,相关性越大。

    所以我们计算夹角的余弦值作为相关性的打分,夹角越小,余弦值越大,打分越高,相关性越大。

    有人可能会问,查询语句一般是很短的,包含的词(Term)是很少的,因而查询向量的维数很小,而文档很长,包含词(Term)很多,文档向量维数很大。你的图中两者维数怎么都是N呢?

    在这里,既然要放到相同的向量空间,自然维数是相同的,不同时,取二者的并集,如果不含某个词(Term)时,则权重(Term Weight)为0。
    这里写图片描述

    举个例子,查询语句有11个Term,共有三篇文档搜索出来。其中各自的权重(Term weight),如下.

    这里写图片描述

    于是文档二相关性最高,先返回,其次是文档一,最后是文档三。

    到此为止,我们可以找到我们最想要的文档了。

    总结
    这里写图片描述

    索引过程:

    1. 有一系列被索引文件

    2. 被索引文件经过语法分析和语言处理形成一系列词(Term) 。

    3. 经过索引创建形成词典和反向索引表。

    4. 通过索引存储将索引写入硬盘。

    搜索过程:

    a) 用户输入查询语句。

    b) 对查询语句经过语法分析和语言分析得到一系列词(Term) 。

    c) 通过语法分析得到一个查询树。

    d) 通过索引存储将索引读入到内存。

    e) 利用查询树搜索索引,从而得到每个词(Term) 的文档链表,对文档链表进行交,差,并得到结果文档。

    f) 将搜索到的结果文档对查询的相关性进行排序。

    g) 返回查询结果给用户。

    展开全文
  • 分布式文档存储 ...一个集群拥有相同的cluster.name 配置的节点组成, 它们共同承担数据和负载的压力 主节点负责管理集群的变更例如增加、删除索引,或者增加、删除节点等。 而主节点并不需要...
  • 存储原理及读写过程1、ES节点架构2、插入、更新或者删除流程3、查询4、写实现5、删除更新实现 1、ES节点架构 分布式主从架构 Master Node:主节点 负责所有管理类的操作 所有索引库的创建、删除、修改、分片的...
  • ES索引存储原理 不变性 写到磁盘的倒序索引是不变的:自从写到磁盘就再也不变。 这会有很多好处: 不需要添加锁。不存在写操作,因此不存在多线程更改数据。 提高读性能。一旦索引被内核的文件系统做了Cache,绝大...
  • ES索引结构及存储原理 ES(ElasticSearch)是一款分布式全文检索框架,底层基于基于Lucene实现。 Elasticsearch中的字段类型可以分为两类:精确值全文。精确值 如它们听起来那样精确。例如日期或者用户 ID,但字符串...
  • 上面介绍了在 ES 内部索引的写处理流程,这个流程是在 ES 的内存中执行的,数据被分配到特定的分片副本上之后,最终是存储到磁盘上的,这样在断电的时候就不会丢失数据。 具体的存储路径可在配置文件 …/config/...
  • 目录 一、ES使用场景 1.1 存储数据(基础) ...2.2 ES读写数据原理 2.2.1 写入相关的几个问题 2.2.2 写入过程 2.2.3 写入shard 2.2.4 merge策略 2.2.5 存储目录结构 2.2.5 ES读取数据的过程 2.3 E...
  • es--3es原理及架构

    2021-03-31 21:50:36
    倒排索引是什么 ElasticSearch Solr 底层都是基于Lucene,而Lucene的底层原理是 倒排索引 倒排索引适用于快速的全文检索,一个...es存储数据的基本单位是索引,比如说你现在要在es存储一些订单数据,你就应该在
  • ES 基本原理

    2021-04-03 15:54:56
    ElasticSearch原理 ...MySQL作为开源关系型数据库,应用范围非常广泛,非常适合于结构化数据存储和查询。在数据查询场景下,默认返回所有满足匹配条件的记录;如果业务数据为结构化数据,同时不需要特别关注排名和
  • 做软件开发的话,或者对IT、计算机有一定的了解的话,都知道,数据都是存储在数据库里面的,比如说电商网站的商品信息,招聘网站的职位信息,新闻网站的新闻信息,等等吧。所以说,很自然的一点,如果说从技术的角
  • 1 前言 由于Elasticsearch使用Lucene来处理shard级别的索引查询,因此数据目录中的文件由ElasticsearchLucene编写。 Lucene负责编写维护Lucene索引文件,而Elasticsearch在Lucene之上...2 ES数据 2.1 Nod...
  • ES快速索引原理

    2020-07-15 15:27:54
    来兼顾存储和查询效率 不建议自己生成 doc id ,ES索引文档的时候会有一个路由算法去平衡每个分片的数据。如果自己指定ID的话,需要多做一步处理,可以搜一下ES源码的教程看下,性能会差数倍 ...
  • ES是一个分布式,可扩展,近实时的高性能都多与数据分析引擎,提供了收集,分析,存储数据三大功能,主要特性 分布式,零配置,亦庄亦用,自动发现,索引自动分片,索引副本机制,RestFul风格接口,多数据自动...
  • 关于Vmware EXSI的数据存储

    千次阅读 2014-09-02 16:31:25
    关于vmware EXSI的存储技术和数据存储我也是刚刚接触,当然,这里描述的Vmware EXSI的存储主要是从原理上解析,其中也有我对EXSi的存储的个人理解。主要从vSphere的VmFS存储类型ISCSI的存储技术来讲,还有一些运维...
  • 搜索数据时,首先在OS Cache中进行搜索,如果找不到数据,则在磁盘中找到对应的index segment文件并打开,读取数据至堆内存中(ES由java开发,因此一定是读取到堆内存,而不是OS Cache),接着,在堆内存中对数据进行...
  • 同时ES还是一个分布式文档数据库,其中每个字段均可被索引,而且每个字段的数据均可被搜索,能够横向扩展至数以百计的服务器存储以及处理PB级的数据。 可以在极短的时间内存储、搜索分析大量的数据。通常作为具有...
  • Elasticsearch 的实现原理主要分为以下几个步骤,首先用户将数据提交到Elasticsearch 数据库中,再通过分词控制器去将对应的语句分词,将其权重分词结果一并存入数据,当用户搜索数据时候,再根据权重将结果排名,...
  • @ inrupt / solid-client是一个JavaScript库,用于访问数据和管理对存储在Solid Pods中的数据的权限。 它在实体资源描述框架(RDF)原理的基础上提供了一个抽象层,并且与RDF / JS规范兼容。 您可以在使用CommonJS...
  • canal实现mysql数据实时同步es

    千次阅读 2020-03-29 13:35:25
    canal是阿里开源的一款用于同步mysql数据到其他数据存储的中间件,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅消费 在搭建mysql服务器主从同步的时候,我们知道,备份服务器如果需要同步master的...
  • canal主要用途是对MySQL数据库增量日志进行解析,提供增量数据的订阅消费,简单说就是可以对MySQL的增量数据进行实时同步,支持同步到MySQL、Elasticsearch、HBase等数据存储中去。 canal工作原理 canal会模拟M
  • canal主要用途是对MySQL数据库增量日志进行解析,提供增量数据的订阅消费,简单说就是可以对MySQL的增量数据进行实时同步,支持同步到MySQL、Elasticsearch、HBase等数据存储中去。 二、canal工作原理 canal会...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 157
精华内容 62
关键字:

es数据存储和原理