精华内容
下载资源
问答
  • Elasticsearch 倒排索引

    2021-01-16 14:21:20
    Elasticsearch倒排索引,其实就是 Lucene 的倒排索引。 二、为什么叫倒排索引 在没有搜索引擎时,我们是直接输入一个网址,然后获取网站内容,这时我们的行为是: document -> to -> words 通过文章,...

    目录

    一、简介

    二、为什么叫倒排索引

    三、倒排索引内部结构

    倒排列表(Postings List)

    增量编码压缩(Frame Of Reference)

    位图压缩算法(Roaring Bitmap)


    一、简介

    Elasticsearch 是建立在全文搜索引擎库 Lucene 基础上的搜索引擎,它隐藏了 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTful API,不过掩盖不了它底层也是 Lucene 的事实。Elasticsearch 的倒排索引,其实就是 Lucene 的倒排索引。 

    二、为什么叫倒排索引

    在没有搜索引擎时,我们是直接输入一个网址,然后获取网站内容,这时我们的行为是:

    document -> to -> words

    通过文章,获取里面的单词,这便是正向索引,即 forward index

    后来,我们希望能够输入一个单词,找到含有这个单词,或者和这个单词有关系的文章:

    word -> to -> documents

    于是我们把这种索引,称为倒排索引,即 inverted index

    三、倒排索引内部结构

    Lucene 的倒排索引主要是由以下三部分组成:

    先来看一个实际例子来大概认识下倒排索引的这三个概念,假设在 es 里有如下的数据:

                                                                         preview

    es 中每一行就是一个document,每个document es都会生成一个docid,建立倒排索引后的样子就是:

                                                                         preview

    文档中的每个字段都会建立自己的倒排索引,18,20这些叫做 term,而 [1,3] 就是 posting list,posting list 是一个 int 数组,存储了所有符合某个 term 的文档 id,那么什么是 term dictionary 和 term index 呢?

    我们回到需要倒排索引的场景上来,首先,我们肯定需要先生成数据,比如爬虫爬到一篇文章,这时我们需要对这篇文章进行分析,将文本拆分成一个个单词。这个过程很复杂,比如“四月是你的谎言”,好一点的中文分词器应该能自动将它分解为“四月”、“是”、“你的”、“谎言”,然后还把 “是”、“你的” 这两个无意义的词语去掉,这应该是个神奇的步骤,逻辑应该都在分析器中,之后有兴趣再看吧...

    好了,将单词分解完之后,这时把这两个词语及它对应的文档id存下来:

    worddocumentId
    四月[1]
    谎言[1]

    接着爬虫继续爬,又爬到一个含有“谎言”的文档,于是索引变成:

    worddocumentId
    四月[1,2]
    谎言[1]

    下次搜索“谎言”,就会返回文档id是1和2的两份文档。然而这种实现需要进行全局遍历才能找到对应的 term,但是这世界上有那么多单词,全局遍历肯定不现实。于是有了排序,这样我们就可以用二分查找的方式,比全局遍历更快地找出目标 term,这就是  term dictionary (term dictionary 在磁盘上是以分 block 的方式保存的,一个block内部利用公共前缀压缩,比如都是Ab开头的单词就可以把Ab省去,这样term dictionary可以比b+tree更节约磁盘空间)。

    光排序还不行,单词都是在磁盘的,而磁盘的随机读操作仍然是非常昂贵的(一次random access大概需要10ms的时间),所以尽量少的读磁盘,就有必要把一些数据缓存到内存(就像 mysql 的B+树),要是 es 也学 mysql,那么多单词放进去内存立马就炸了,于是就有了 term index(字典树),term index 有点像一本字典的大的章节表,比如:

    A开头的term ……………. Xxx页
    
    C开头的term ……………. Xxx页
    
    S开头的term ……………. Xxx页

    当然 term 未必都是英文字符,可以是任意的byte数组,因此实际的 term index 是一颗 trie 树,也叫字典树或前缀树,即这颗树不会包含所有的 term,它包含的是term的一些前缀。通过 term index 可以快速地定位到term dictionary 的某个 offset,然后从这个位置再往后顺序查找。再加上一些压缩技术(term index在内存中是以FST<Finite State Transducers>形式保存的,其特点是非常节省内存) term index 的尺寸可以只有所有 term 的尺寸的几十分之一,使得用内存缓存整个term index变成可能。下图例子是一颗包含 "A", "to", "tea", "ted", "ten", "i", "in", 和 "inn" 的 trie 树:

     

    三者整体效果图大概如下:

     preview

    现在我们可以回答“为什么Elasticsearch/Lucene检索可以比mysql快了",mysql只有term dictionary这一层,是以b+tree排序的方式存储在磁盘上的,检索一个term需要若干次的random access的磁盘操作,而Lucene在term dictionary的基础上添加了term index来加速检索,term index以树的形式缓存在内存中,从term index查到对应的term dictionary的block位置之后,再去磁盘上找term,大大减少了磁盘的random access次数。

    倒排列表(Postings List)

    搜索引擎一项很重要的工作就是高效的压缩和快速的解压缩一系列有序的整数列表。我们都知道,Elasticsearch 基于 Lucene,一个 Lucene 索引 我们在 Elasticsearch 称作 分片,并且引入了 按段搜索 的概念。

    新的文档首先被添加到内存索引缓存中,然后写入到一个基于磁盘的段。在每个 segment 内文档都会有一个 0 到文档个数之间的标识符(最高值 2^31 -1),称之为 doc ID。这在概念上类似于数组中的索引:它本身不做存储,但足以识别每个 item 数据。

    Segments 按顺序存储有关文档的数据,在一个 Segments 中 doc ID 是 文档的索引。因此,segment 中的第一个文档的 doc ID 为 0,第二个为 1,等等。直到最后一个文档,其 doc ID 等于 segment 中文档的总数减 1。

    倒排索引需要将 terms 映射到包含该单词 (term) 的doc ID列表,这样的映射列表就称之为 倒排列表 (Postings List),一般很多文档都会包含该单词,每个文档都会记录文档编码(doc ID),单词在这个文档中出现的次数(TF)及单词在文档中哪些位置出现过等信息,这样一个与文档相关的信息被称作 倒排索引项(Posting)

    虽然倒排列表只是一个用来存文档id的数组,但是在设计时遇到的问题可不少:

    • 如何压缩以节省磁盘空间
    • 如何快速求交并集

    增量编码压缩(Frame Of Reference)

    针对倒排列表,Lucene 采用一种增量编码的方式将一系列 ID 进行压缩存储,自 Lucene 4.1 以来一直在使用。

    假设有这样一个数组:

    [73, 300, 302, 332, 343, 372]

    如何尽可能的压缩?

    在 Lucene 中,由于数据是按segment存储的,且最大值为 2^31 -1 ,所以如果不进行任何处理,每个元素占用四个字节(byte),对应上面数组即占用24 byte。

    压缩,就是尽可能降低每个数据占用的空间,同时又能让信息不失真,能够还原回来。在实际的搜索引擎系统中,并不存储倒排索引项中的实际文档编号(Doc ID),而是代之以文档编号差值(D-Gap)。文档编号差值是倒排列表中相邻的两个倒排索引项文档编号的差值,一般在索引构建过程中,可以保证倒排列表中后面出现的文档编号大于之前出现的文档编号,所以文档编号差值总是大于 0 的整数。

    Step 1:Delta-encode —— 增量编码

    增量编码就是从第二个数开始每个数存储与前一个 id 的差值,即只记录元素与元素之间的增量,于是数组变成了:

    [73, 227, 2, 30, 11, 29]

    之所以要对文档编号进行差值计算,主要原因是为了更好地对数据进行压缩,原始文档编号一般都是大数值,通过差值计算,就有效地将大数值转换为了小数值,而这有助于增加数据的压缩率。

    Step 2:Split into blocks —— 分割成块

    Lucene里每个块是 256 个文档 ID,这样可以保证每个块,增量编码后,每个元素都不会超过 256(1 byte),为了方便演示,我们假设每个块是 3 个文档 ID:

    [73, 227, 2], [30, 11, 29]

    Step 3:Bit packing —— 位压缩

    计算每组 3 个数中最大的那个数需要占用 bit 位数,比如  [30, 11, 29]  中最大数 30 最小需要 5 个 bit 位存储,这样 11、29 也用 5 个 bit 位存储,这样才占用 15 个 bit,不到 2 个字节,压缩效果很好。

    以上三个步骤,共同组成了一项编码技术,Frame Of Reference(FOR),如下面原理图所示,这是一个区块大小为 3 的示例(实际上是 256):

     

    位图压缩算法(Roaring Bitmap

    在实际查询时,如果给定查询过滤条件 age=18 ,其过程就是先从term index找到18在term dictionary的大概位置,然后再从term dictionary里精确地找到18这个term,然后得到一个posting list或者一个指向posting list位置的指针,然后再查询 gender=女 的过程也是类似的,最后得出 age=18 AND gender=女 就是把两个 posting list 在内存中做一个交集(由于posting list在磁盘中是压缩过的,因此需要先解压回原始 id 数组)。

    而这个求交集的过程可不容易,也就是 Posting List 的第二个痛点 —— 如何快速求交并集

    我们把 Lucene 遇到的问题,简化成一道算法题。假设有下面三个数组:

    [64, 300, 303, 343]
    
    [73, 300, 302, 303, 343, 372]
    
    [303, 311, 333, 343]

    求他们的交集。

    这里有四种方式可以进行计算:

    • Integer 数组
    • Skip List 
    • Bitmap
    • Roaring Bitmaps

    而 Lucene 就是采用了第四种方式,但是我们需要先了解 Bitmap 的方式,假设有这样的一个 Posting list:

    [3,1,4,7,8]

    如果使用 Integer 数组遍历求交集的方式,大概需要 20 byte存储,在文档id一多的时候,要把这么多数据从磁盘解压后丢到内存,内存肯定撑不住。

    因此旧版本(5.0 之前)的 Lucene 采用 Bitmap 方式来解决,对应上面 Posting list ,对应的 Bitmap 就是:

    [0,1,0,1,1,0,0,1,1]

    非常直观,用 0/1 表示某个值是否存在,比如 8 这个值就对应第 8 位,对应的 bit 值是 1,这样用一个字节就可以代表 8 个文档 id。但这样的压缩方式仍然不够高效,Bitmap 自身就有压缩的特点,其用一个 byte 就可以代表 8 个文档,所以 100 万个文档只需要 12.5 万个 byte。而 Bitmap 的缺点是存储空间随着文档个数线性增长,例如下面数组:

    [0, 65535]

    如果用 Bitmap 表示:

    [1,0,0,0,….(超级多个0),…,0,0,1]

    你需要 65536 个 bit,也就是 65536/8 = 8192 bytes,而用 Integer 数组,你只需要 2 * 4 bytes = 8 bytes,可以看出在文档个数少的时候使用 Integer 数组是更加节省内存的。

    而 Lucene 使用的这个数据结构叫做 Roaring Bitmap ,简称 RBM

    RBM 的主要思想并不复杂,简单来讲,有如下三条:

    1. 我们将 32-bit 的范围 ([0, n)) 划分为 2^16 个桶,每一个桶有一个 Container 来存放一个数值的低16位;
    2. 在存储和查询数值的时候,我们将一个数值 k 划分为高 16 位(k % 2^16)和低 16 位(k mod 2^16),取高 16 位找到对应的桶,然后在低 16 位存放在相应的 Container 中;
    3. 容器的话, RBM 使用两种容器结构: Array Container 和 Bitmap Container。Array Container 存放稀疏的数据,Bitmap Container 存放稠密的数据。即,若一个 Container 里面的 Integer 数量小于 4096,就用 Short 类型的有序数组来存储值。若大于 4096,就用 Bitmap 来存储值。

    为什么这里用的 4096 这个阈值?因为一个 Integer 的低 16 位是 2Byte,因此对应到 Arrary Container 中的话就是 2Byte * 4096 = 8KB;同样,对于 Bitmap Container 来讲,2^16 个 bit 也相当于是 8KB。

    然后,基于前面提到的两种 Container,在两个 Container 之间的 Union (bitwise OR) 或者 Intersection (bitwise AND) 操作又会出现下面三种场景:

    • Bitmap vs Bitmap
    • Bitmap vs Array
    • Array vs Array

    RBM 提供了相应的算法来高效地实现这些操作。

    展开全文
  • Elasticsearch倒排索引

    2021-01-20 12:12:43
    Elasticsearch通过倒排索引的数据结构来实现全文搜索 在关系数据库系统里,索引是检索数据最有效率的方式。但对于搜索引擎,它并不能满足其特殊要求,比如海量数据下比如百度或者谷歌要搜索百亿级的网页,如果使用...
  • 倒排索引1.1 倒排索引的结构1.2 倒排索引不可变的好处二. 重建索引 一. 倒排索引 1.1 倒排索引的结构 (1)包含这个关键词的document list (2)包含这个关键词的所有document的数量:IDF(inverse document ...

    序号内容链接地址
    1SpringBoot整合Elasticsearch7.6.1https://blog.csdn.net/miaomiao19971215/article/details/105106783
    2Elasticsearch Filter执行原理https://blog.csdn.net/miaomiao19971215/article/details/105487446
    3Elasticsearch 倒排索引与重建索引https://blog.csdn.net/miaomiao19971215/article/details/105487532
    4Elasticsearch Document写入原理https://blog.csdn.net/miaomiao19971215/article/details/105487574
    5Elasticsearch 相关度评分算法https://blog.csdn.net/miaomiao19971215/article/details/105487656
    6Elasticsearch Doc valueshttps://blog.csdn.net/miaomiao19971215/article/details/105487676
    7Elasticsearch 搜索技术深入https://blog.csdn.net/miaomiao19971215/article/details/105487711
    8Elasticsearch 聚合搜索技术深入https://blog.csdn.net/miaomiao19971215/article/details/105487885
    9Elasticsearch 内存使用https://blog.csdn.net/miaomiao19971215/article/details/105605379
    10Elasticsearch ES-Document数据建模详解https://blog.csdn.net/miaomiao19971215/article/details/105720737

    一. 倒排索引

    1.1 倒排索引的结构

    (1)包含这个关键词的document list
    (2)包含这个关键词的所有document的数量:IDF(inverse document frequency)
    (3)这个关键词在每个document中出现的次数:TF(term frequency)
    (4)这个关键词在这个document中的次序
    (5)每个document的长度:length norm
    (6)包含这个关键词的所有document的平均长度

    1.2 倒排索引不可变的好处

    (1)不需要锁,提升并发能力,避免锁的问题
    (2)数据不变,一直保存在os cache中,只要cache内存足够
    (3)filter cache一直驻留在内存,因为数据不变,同一个过滤条件下得到的bitset一定不会变。
    (4)可以压缩,节省cpu和io开销

    二. 重建索引

    没有哪一个架构师敢说自己设计的index完美无缺,经过一段时间的使用后,往往会根据实际的业务场景,对原有结构进行调整。但遗憾的是,ES不允许对已存在的字段进行修改和删除,比如不能修改字段的类型,字段的分词器,增加新的子字段等操作,原因是这样会倒排索引的结构发生变化。
    重建索引的方法如下: 新建一个index,为其设置定制化的mapping,接着将旧数据从旧索引中迁移到新索引中。迁移数据的方法非常多,比如通过scroll滚动读取数据,接着通过bulk POST create操作,将数据批量新增至新索引。
    但重建索引不可避免的带来一个问题: 需要重新创建一个新索引。如果程序中操作ES的代码在书写index时使用了硬编码,那么重建索引就会导致整个系统不可用,必须修改代码再重启系统才能恢复功能。为了避免重启系统,实现零停机,我们需要在程序中使用index的别名

    展开全文
  • 业务上,最早启用Elasticsearch(下称ES)是为了解决模糊查询的问题。具体业务场景为大量抓取回来的短视频内容、热门微博、公众号文章、小红书笔记、信息流新闻文章等,需要支持用户模糊查找,而随着每日新增的内容...

    Elasticsearch在生产中充当的角色

    业务上,最早启用Elasticsearch(下称ES)是为了解决模糊查询的问题。具体业务场景为大量抓取回来的短视频内容、热门微博、公众号文章、小红书笔记、信息流新闻文章等,需要支持用户模糊查找,而随着每日新增的内容越来越多,这些信息已经积累到单个媒体数千万近亿的数量,因此依靠MySQL的模糊查询是无法满足性能上的要求,考虑引入对应的搜索引擎来解决,于是就将数据的特定字段迁移至ES以支持快速高效的模糊查询,并将查询得到的ID取回MySQL匹配再将详细内容返回。

    Elasticsearch为什么能够支持高效的模糊查询

    倒排索引原理

    为了支持模糊查询,用户输入关键词之后,需要快速定位到这些词对应的词条,思路与MySQL的LIKE一样,但是MySQL没有实现对应的方案以支持快速定位。ES在这块上略有不同,利用倒排索引(Inverted Index)可以直接获取到文档的ID。下面来简单介绍一下倒排索引的结构。

    为了便于理解,介绍的实现与具体实现会有不一致。
    现在有以下的数据行:

    id书名出版社
    1高性能MySQL电子工业出版社
    2Elasticsearch服务器开发人民邮电出版社
    3深入理解Elasticsearch机械工业出版社

    在写入数据,也就是索引(动词)的过程中:
    (1)ES首先会将数据进行分析,如"高性能MySQL"拆分成“高性能”和“MySQL”等词条(tokens),同理,“电子工业出版社”可以被拆分成“电子”、“工业”、“出版社”;
    (2) 拆分完毕后添加至对应的倒排索引中:

    词条对应id
    高性能1
    MySQL1
    电子1
    工业1
    出版社1

    (3)这样当Client查询“工业”一词的时候,就可以快速定位到id为1的数据行;
    (4)同理对id为2和3的数据分析和索引之后,倒排索引变成:

    词条对应id
    高性能1
    MySQL1
    电子1
    工业1, 3
    出版社1, 2, 3
    Elasticsearch2, 3
    服务器2
    开发2
    人民2
    邮电2
    深入3
    理解3

    (5)举例搜索“工业”一词的时候,就应该定位到id为1和2的行

    附上官方文档中的倒排索引势力,格式略有不同但是原理是相近的

    Term      Doc_1  Doc_2
    -------------------------
    Quick   |       |  X
    The     |   X   |
    brown   |   X   |  X
    dog     |   X   |
    dogs    |       |  X
    fox     |   X   |
    foxes   |       |  X
    in      |       |  X
    jumped  |   X   |
    lazy    |   X   |  X
    leap    |       |  X
    over    |   X   |  X
    quick   |   X   |
    summer  |       |  X
    the     |   X   |
    ------------------------
    

    倒排索引和分析的具体实现

    倒排索引具体实现在官网文档中粗略查询了一下没有具体介绍,估计被埋在了厚厚的文档堆中。根据其他资料显示,倒排索引实现方法多种,主要如BSBI和SPIMI等,参考博客《倒排索引构建算法BSBI和SPIMI》

    在具体的分析过程中,Elasticsearch会使用多种分析器将文本拆分成用于搜索的词条,然后将这些词条统一化以提高“可搜索性”。具体来讲,分析器应该包含如下功能:
    (1)字符过滤器:如去除HTML,字符转换如&转为and
    (2)分词器:如遇到空格和标点将文本拆分成词条
    (3)Token过滤器:如将大小写统一,增加词条(如jump、leap等同义词)
    ES内置有多种可选择的分析器,在业务中我们负责写入数据的同事使用的是针对中文分词的分词器以正确处理中文文本。

    经过这些处理之后倒排索引生成,就能实现用于模糊查询的功能了。

    Elasticsearch数据写入的过程

    预备知识

    在ES中,数据结构和MySQL相似但也略有不同,类比来看,ES的存储从上至下可以类比成:
    索引(Index):相当于MySQL中的DB
    文档类型(Doc Type):相当于MySQL的Table
    文档(Doc):相当于MySQL中的一行数据

    ES的索引并非可以理解为一整块数据块,由不同的doc构成doc type然后聚集在一起就是index。实际上ES的索引是由一个或多个分片组成的,每个分片包含了文档集的一部分。每个分片又可以又对应的副本。
    因此,按照默认配置,ES的每个索引会切分出5个分片,而每个分片又有各自对应的副本,所以一共是10个分片。

    分片,具体来说就是Lucene索引,因此可以看作ES的索引是由多个Lucene索引(分片)组成的,这些Lucene索引上包含了部分的doc。

    继续细分Lucene索引,ES引入了按段搜索的概念,每个Lucene索引都是由多个段组成的,这些段具体而言就是,自身就是一个倒排索引。每个Lucene索引均包含了一个提交点(Commit Point)和多个段。

    一下引入多种概念可能有点让人搞不懂,不要紧,下面借助一些官方的图例来理解一下。

    数据如何写入

    Lucene索引和段
    记住官方这张图,图中一个Lucene索引包含了3个段和一个提交点,当新增数据的时候:
    (1)新的doc存放至内存缓冲区(In-memory indexing buffer)中,准备被提交(New documents are collected in an in-memory indexing buffer);
    (2)缓冲区的内容提交(Every so often, the buffer is commited):

    • 一个新的段被写至磁盘中
    • 一个新的、包含新段名称的提交点被写至磁盘中
    • 所有在文件系统缓存中的待写入的数据被写入(flush)至磁盘,磁盘同步完成
    • A new segment—a supplementary inverted index—is written to disk.
    • A new commit point is written to disk, which includes the name of the new segment.
    • The disk is fsync’ed—all writes waiting in the filesystem cache are flushed to disk, to ensure that they have been physically written.
      新的doc存放至内存缓冲区
      内存缓冲区的内容写入磁盘,生成新的commit point
      由于有按段写入缓冲区、写入磁盘的过程存在,ES的新增数据的搜索并不是实时的——近实时搜索。

    近实时搜索

    因为需要把对应的段写入之后才能够查询,因此新数据进来的瞬间是无法搜索到的,即使已经按段(意味着倒排索引已经建立好)存在内存中。
    提交一个新的段至磁盘需要进行fsync的操作,这是个代价大的操作因此需要在内存缓冲区和磁盘之间增加新的缓冲区,使得在fsync操作之前文档就能够被搜索到。
    在Elasticsearch和磁盘之间是文件系统缓存。下图表示段已经从内存缓冲区中同步至文件系统缓存(灰色段),借助缓存,此时文档已经可以被检索到,但是还没有被提交。这个从内存缓冲区至文件系统缓存的过程称为refresh,这是一个写入和打开新段的轻量过程。
    在这里插入图片描述
    我们可以在设置中设置refresh的间隔时间,也可以通过refresh api进行手动refresh使得新增的doc“实时”可见。

    # 修改my_logs索引的refresh时间间隔
    PUT /my_logs
    {
      "settings": {
        "refresh_interval": "30s" 
      }
    }
    
    # 请求接口对blogs进行refresh操作
    POST /blogs/_refresh 
    

    数据持久化

    既然使用到了内存及文件系统缓存,那么必然有数据丢失的风险。尽管通过refresh实现了近实时搜索,但是还是要时常进行完整commit来确保能从失败中恢复出来。

    ES中使用了一个translog,在文档被索引(动词)后,就会被添加到内存缓冲区并且追加到translog:
    在这里插入图片描述
    在refresh操作过后,In-memory buffer区域的段转移到文件缓冲区,也就是灰色段:
    在这里插入图片描述
    随着进程的继续,doc会逐渐积累:
    在这里插入图片描述
    经过一定时间或者translog变大之后,这些translog就会通过fsync提交,现在看到所有的段都是绿色,意味着可搜索、持久化完成。文件缓存系统上的段(灰色)在fsync时会被清空(flush),旧的translog会被删除,创建新的空translog:
    在这里插入图片描述
    同样,flush操作也和refresh类似,有对应API可调用:

    POST /blogs/_flush 
    

    这里引用官方文档对translog的安全性的描述:


    Translog 有多安全?

    translog 的目的是保证操作不会丢失。这引出了这个问题: Translog 有多安全 ?

    在文件被 fsync 到磁盘前,被写入的文件在重启之后就会丢失。默认 translog 是每 5 秒被 fsync 刷新到硬盘, 或者在每次写请求完成之后执行(e.g. index, delete, update, bulk)。这个过程在主分片和复制分片都会发生。最终, 基本上,这意味着在整个请求被 fsync 到主分片和复制分片的translog之前,你的客户端不会得到一个 200 OK 响应。

    在每次请求后都执行一个 fsync 会带来一些性能损失,尽管实践表明这种损失相对较小(特别是bulk导入,它在一次请求中平摊了大量文档的开销)。

    但是对于一些大容量的偶尔丢失几秒数据问题也并不严重的集群,使用异步的 fsync 还是比较有益的。比如,写入的数据被缓存到内存中,再每5秒执行一次 fsync 。

    这个行为可以通过设置 durability 参数为 async 来启用:

    PUT /my_index/_settings
    {
        "index.translog.durability": "async",
        "index.translog.sync_interval": "5s"
    }
    

    这个选项可以针对索引单独设置,并且可以动态进行修改。如果你决定使用异步 translog 的话,你需要 保证 在发生crash时,丢失掉 sync_interval 时间段的数据也无所谓。请在决定前知晓这个特性。

    如果你不确定这个行为的后果,最好是使用默认的参数( “index.translog.durability”: “request” )来避免数据丢失。


    段合并

    随着refresh的不断调用,ES中的段会越来越多,太多的段会消耗更多的资源,因为查询是要在各个段中进行检查的,会拖慢查询效率。
    ES通过将小段合并至大段来解决这个积累的问题,这个动作是自动的:
    (1) 当索引的时候,刷新(refresh)操作会创建新的段并将段打开以供搜索使用。
    (2)合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中。这并不会中断索引和搜索。
    在这里插入图片描述
    合并之后老的段会被删除,fsync将新的段提交至磁盘
    在这里插入图片描述

    Elasticsearch数据查询的过程

    上文已经提过,ES将索引分成不同的分片(Luence索引),再由不同分片中的段(倒排索引)存储具体的数据。为了获取对应的doc,ES需要查询所有分片并且对结果进行合并。

    默认的索引过程

    ES根据文档的标识符,选择文档应该进入的分片(当然这一步也支持手动指定分片)。默认情况下,通过计算文档的Hash值将文档分配到对应分片上。

    取出过程

    大多数情况下,为了得到想要的结果,需要查询所有的分片。
    我们把请求发送到ES的一个节点,根据请求的搜索类型:
    (1)ES首先查询所有节点获得对应符合的文档的标识符+得分(用于排序)
    (2)节点根据这些所有的标识符和得分,判断需要取出的对应文档范围(如得分top5的文档),重新构建一个内部请求,再到对应分片上获取这些文档的具体内容。

    展开全文
  • ElasticSearch引擎把文档数据写入到倒排索引(Inverted Index)的数据结构中,倒排索引建立的是分词(Term)和文档(Document)之间的映射关系,在倒排索引中,数据是面向词(Term)而不是面向文档的。 一个倒排...

    一、倒排索引(Inverted Index)


    ElasticSearch引擎把文档数据写入到倒排索引(Inverted Index)的数据结构中,倒排索引建立的是分词(Term)和文档(Document)之间的映射关系,在倒排索引中,数据是面向词(Term)而不是面向文档的。

    一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。


    举个例子:
    对以下三个文档去除停用词后构造倒排索引

    倒排索引-查询过程

    对上面图片中查询包含“搜索引擎”的文档,通过倒排索引获得“搜索引擎”对应的文档id列表,有1、3。

    通过正排索引查询1和3的完整内容,返回最终结果。


    倒排索引-组成

    • 单词词典(Term Dictionary)
    • 倒排列表(Posting List)

    单词词典(Term Dictionary)


    单词词典的实现一般用B+树,B+树构造的可视化过程网址:B+ Tree Visualization


    倒排列表(Posting List)

    倒排列表记录了单词对应的文档集合,由倒排索引项(Posting)组成,倒排索引项主要包含如下信息:

    1. 文档id用于获取原始信息。
    2. 单词频率(TF,Term Frequency),记录该单词在该文档中出现的次数,用于后续相关性算分。
    3. 位置(Posting),记录单词在文档中的分词的位置(可能有多个的位置),用于做短语搜索(Phrase Query)。
    4. 偏移(Offset),记录单词在文档的开始和结束位置下标,用于高亮显示。

    B+树内部结点存索引,叶子结点存数据,这里的 单词词典就是B+树索引,倒排列表就是数据,整合在一起后如下所示:

    ES存储的是一个JSON格式的文档,其中包含多个字段,每个字段会有自己的倒排索引。

    倒排索引的结构

    1. 包含这个关键词的document list
    2. 包含这个关键词的所有document的数量:IDF(inverse document frequency)
    3. 这个关键词在每个document中出现的次数:TF(term frequency)
    4. 这个关键词在这个document中的次序
    5. 每个document的长度:length norm
    6. 包含这个关键词的所有document的平均长度

    倒排索引的好处

    1. 不需要锁,提升并发能力,避免锁的问题
    2. 数据不变,一直保存在 cache中,只要cache内存足够
    3. filter cache一直留在内存,因为数据不变
    4. 可以压缩,节省cpu和io开销

    二、分词


    分词是将文本转换成一系列单词(Term or Token)的过程,也可以叫文本分析,在ES里面称为Analysis

    分词器


    分词器是ES中专门处理分词的组件,英文为Analyzer,它的组成如下:

    • Character Filters:针对原始文本进行处理,比如去除html标签
    • Tokenizer:将原始文本按照一定规则切分为单词
    • Token Filters:针对Tokenizer处理的单词进行再加工,比如转小写、删除或增新等处理

    分词器的组成

    Character Filters

    • 在Tokenizer之前对原始文本进行处理,比如增加、删除或替换字符等
    • 自带的如下:

                    HTML Strip Character Filter:去除HTML标签和转换HTML实体

                    Mapping Character Filter:进行字符替换操作

                    Pattern Replace Character Filter:进行正则匹配替换

    • 会影响后续tokenizer解析的position和offset信息

    Tokenizers

    • 将原始文本按照一定规则切分为单词(term or token)
    • 自带的如下:

                  1.standard 按照单词进行分割
                  2.letter 按照非字符类进行分割
                  3.whitespace 按照空格进行分割
                  4.UAX URL Email 按照standard进行分割,但不会分割邮箱和URL
                  5.Ngram 和 Edge NGram 连词分割
                  6.Path Hierarchy 按照文件路径进行分割

    Token Filters

    • 对于tokenizer输出的单词(term)进行增加、删除、修改等操作
    • 自带的如下:

                  1.lowercase 将所有term转为小写
                  2.stop 删除停用词
                  3.Ngram 和 Edge NGram 连词分割
                  4.Synonym 添加近义词的term

    分词器调用顺序


    在Kibana上分词的案例

    ES中预定义的分词器

    1.Standard Analyzer
         默认分词器
         按词切分,支持多语言
         小写处理
    2.Simple Analyzer
         按照非字母切分
         小写处理
    3.Whitespace Analyzer
         空白字符作为分隔符
    4.Stop Analyzer
         相比Simple Analyzer多了去除请用词处理
         停用词指语气助词等修饰性词语,如the, an, 的, 这等
    5.Keyword Analyzer
         不分词,直接将输入作为一个单词输出
    6.Pattern Analyzer
         通过正则表达式自定义分隔符
         默认是\W+,即非字词的符号作为分隔符
    7.Language Analyzer
         提供了30+种常见语言的分词器


    三、自定义分词


    自定义分词需要在索引配置中设定 char_filter、tokenizer、filter、analyzer等。

    四、分词使用说明


    分词会在如下两个时机使用:

    • 创建或更新文档时(Index Time),会对相应的文档进行分词处理
    • 查询时(Search Time),会对查询语句进行分词,详细如下:

                   1.查询时通过analyzer指定分词器
                   2.通过index mapping设置search_analyzer实现
                   3.一般不需要特别指定查询时分词器,直接使用索引分词器即可,否则会出现无法匹配的情况

    五、ElasticSearch的使用建议

       1.在java实体类中定义往ES存入数据的格式

                            >定义实体类对应ES中的索引和类型 @Document(indexName = "contractcenter-cargoitem", type = "plcCargoItemESVO")、 

                            >定义非日期类型数据是否分词 @Field(index = FieldIndex.analyzed)、

                            >定义日期类型数据时间格式 @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT+8")

              

        2.存入ES日期类型数据常见问题

          2.1.实体类日期类型数据时间格式 要与 手工录入 或 接口调用存入ES的日期类型数据时间格式一致,

            例如:实体类是yyyy-MM-dd'T'HH:mm:ss.SSSZ+0800,ES也必须是yyyy-MM-dd'T'HH:mm:ss.SSSZ+0800

          2.2.ES存入数据时,会规定数据的类型,日期类型最好是简约形式,不要用其他的属性,例如:

            "shipmentDate": {

                "type": "date"

              }

          2.3.在往ES存入数据的时候,如果要存入的数据 ES里没有,ES会自动为那些没有的数据创建索引。

          2.4.在第一次java或手工往ES存数据时,会生成数据的索引和数据的类型, 如果后面改变数据的类型,会由于与第一次存数据的类型不一致而报数据解析异常。

      3. 明确字段是否需要分词,需要分词的字段就将type设置为keyword,可以提高查询效率。

      4.在使用analyze API时,需要十分注意,并且要查看文档的分词结果是否正确。
     

    展开全文
  • 一切设计都是为了提高搜索的性能倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引。通俗地来讲,正向索引是通过key找value,反向索引则是通过value找key。先来回忆一下我们是怎么插入一条索引记录的:...
  • Elasticsearch 之所以可以实现近乎实时的检索,依靠的技术手段是非常多的,本文将从 反向索引、Term Index 两块知识点入手,分析 Elasticsearch 之所以那么快的原因。 1. 反向索引 1.1. 正向索引 什么是正向索引 ...
  • 面试必问Elasticsearch倒排索引原理

    千次阅读 2019-03-17 20:46:00
    倒排索引是目前搜索引擎公司对搜索引擎最常用的存储方式,也是搜索引擎的核心内容,在搜索引擎的实际应用中,有时需要按照关键字的某些值查找记录,所以是按照关键字建立索引,这个索引就被称为倒排索引。...
  • 来源:博客园链接:https://www.cnblogs.com/dreamroute/p/8484457.html介绍Elasticsearch 是一个分布式可扩展的实时搜索和分析引...
  • 为什么需要倒排索引倒排索引,也是索引。索引,初衷都是为了快速检索到你要的数据。...对 Mysql 来说,是 B+ 树,对 Elasticsearch/Lucene 来说,是倒排索引Elasticsearch 是建立在全文搜索引擎库 Lucene 基...
  • ElasticSearch倒排索引

    万次阅读 2019-03-12 09:22:53
    ElasticSearch倒排索引 Elasticsearch使用一种叫做倒排索引(inverted index)的结构来做快速的全文搜索。倒排索引由在文档中出现的唯一的单词列表,以及对于每个单词在文档中的位置组成。 例如,我们有两个文档,每...
  • Elasticsearch倒排索引

    2021-10-28 22:21:02
    Elasticsearch倒排索引 倒排索引的概念是相对于MySQL这样的正向索引而言的。 1.正向索引 那么什么是正向索引呢?例如给商品表(tb_goods)中的id创建索引: 如果是根据字段id查询,那么直接走索引,查询速度非常快...
  • 正排索引与倒排索引 首先,我们需要这两种索引方式是要干啥?其实任何一种索引模式,都对应的是不同的信息存储方式。这样不同的存储方式,主要是为了不同的查询要求而定的。正排索引和倒排索引就是如此,正排易维护...
  • elasticsearch 倒排索引原理

    千次阅读 2019-01-24 19:23:50
    Elasticsearch是通过Lucene的倒排索引技术实现比关系型数据库更快的过滤。特别是它对多条件的过滤支持非常好,比如年龄在18和30之间,性别为女性这样的组合查询。倒排索引很多地方都有介绍,但是其比关系型数据库的b...
  • Elasticsearch倒排索引与B+Tree对比

    千次阅读 2020-04-17 12:02:30
    Elasticsearch 是通过 Lucene 的倒排索引技术实现比关系型数据库更快的过滤。特别是它对多条件的过滤支持非常好,比如年龄在 18 和 30 之间,性别为女性这样的组合查询。倒排索引很多地方都有介绍,但是其比关系型...
  • ES倒排索引原理

    2021-03-18 14:57:32
    ES倒排索引原理 先简单了解一下什么是倒排索引,假设我们向某个索引里写入了下面两条document: document 某字段内容 doc1 I really liked my small dogs, and I think my mom also liked them. doc2 He ...
  • 倒排索引ElasticSearch

    2021-02-01 03:07:32
    1 Mysql中的索引在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式。1.1 MyISAM索引实现MyISAM表的索引和数据是分离的,索引...
  • es倒排索引 选择索引策略很困难。 Elasticsearch 文档的确有一些一般性建议,并且有 其他公司的一些技巧,但这也取决于特定的用例。 在典型情况下,您有一个数据库作为事实来源,并且有一个使事物可搜索的索引。 您...
  • Elasticsearch系列——(1.1)倒排索引原理

    万次阅读 多人点赞 2018-08-13 16:04:41
    关于es为什么搜索快,大家应该有所了解,但是到底什么是倒排索引?网上找到一篇介绍通俗易懂,转载如下:   见其名知其意,有倒排索引,对应肯定,有正向索引。  正向索引(forward index),反向索引...
  • 搜索的时候,要依靠倒排索引;排序的时候,需要依靠正排索引,看到每个document的每个field,然后进行排序,所谓的正排索引,其实就是doc values。在建立索引的时候,一方面会建立倒排索引,以供搜索用;一方面会...
  • 本篇文章主要介绍ES中的索引——倒排索引 分词 在创建索引之前,会对文档中的字符串进行分词。ES中字符串有两种类型,keyword和text。 keyword类型的字符串不会被分词,搜索时全匹配查询 text类型的字符串会被分词...
  • 一、什么是倒排索引倒排索引包含三个内容: 1、倒排表(posting list) 存储搜索数据的id列表 2、词项字典(term dictionary) 存储数据仓库中的词汇 3、词项索引(term index) 标识当前词项是不是被搜索...
  • Elasticsearch中的倒排索引详解

    千次阅读 2020-04-17 11:58:29
    Elasticsearch创建索引流程一文中,介绍了ES创建索引的流程。再流程中是调用Lucene的...在讲解倒排索引前,我们先了解索引创建,下图是 Elasticsearch 中数据索引过程的流程。 从上图可以看到,文档未在 ES 中...
  • ElasticSearch——倒排索引和正向索引 1、正向索引 正向索引 (forward index) 以文档的ID为关键字,表中记录文档中每个字的位置信息,查找时扫描表中每个文档中字的信息直到找出所有包含查询关键字的文档 这种组织...
  • elasticsearch中的倒排索引是分词和文档之间的对应关系 举个例子,文档和词条之间的关系如下图: 字段值被分析之后,存储在倒排索引中,倒排索引存储的是分词(Term)和文档(Doc)之间的关系,简化版的倒排索引...
  • 去掉没有实际意义的词, 如is、a、in、as等 大小写转换, 使用关键字elasticsearch 能把Elasticsearchelasticsearch都查询出来, 因此所有的单词统一大小写。 单、复数,过去式、进行时等进行转换, 如希望使用...
  • 见其名知其意,有倒排索引,对应肯定,有正向索引。 正向索引(forward index),反向索引(inverted index)更熟悉的名字是倒排索引。 在搜索引擎中每个文件都对应一个文件ID,文件内容被表示为一系列关键词的集合...
  • 正排索引:文档 Id 到文档内容、单词的关联关系 文档 ID ...倒排索引:单词到文档 Id 的关联关系 单词 文档 ID 列表 elasticsearch 1 流行 1 搜索引擎 1、3 php 2 世界 2 最好 2...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,367
精华内容 5,746
关键字:

es倒排索引