Elasticsearch-6.x 倒排索引,doc_values,Fielddata, store研究

一.倒排索引

倒排索引的概念,感兴趣的可以点击查看<>

也可以查看elasticsearch简介和倒排序索引介绍这篇文章,写的很清晰。

1.1 字段和倒排索引的关系

首先,在es中,我们可以把一个doc(文档)理解为数据库中的一行数据,每个doc对应多个field(字段),例如:

PUT /employee/group/1
{
    "age" : 25,
    "about" :      "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}
PUT /employee/group/2
{
    "age" :         32,
    "about" :       "I like to collect rock albums",
    "interests":  [ "music" ]
}

es中,会在_source中将数据存一份,然后,写入数据的同时,自动生成mapping信息,根据mapping信息,生成字段对应的倒排索引文件。

自动生成的mapping如下:

{
  "employee": {
    "mappings": {
      "group": {
        "properties": {
          "about": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "age": {
            "type": "long"
          },
          "interests": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}

按照字段,分别生成倒排索引文件,然后检索字段的时候,搜索字段对应的倒排索引文件即可,如下:

age字段:

age字段因为是long类型,整个字段无需分词(term,token),直接按字段值做倒排索引。

age-1-倒排索引文件
term词条 docID
25 1
32 2

about字段本身为text类型,支持分词,about.keyword多域字段为keyword类型,按整词作为term词条,所以产生about,about.keyword两个字段的倒排索引文件。

about-1 倒排索引文件
term词条 docID
i 1,2
love 1
to 1,2
go 1
rock 1,2
climbing 1
like 2
collect  2
albums 2
about.keyword-1倒排索引文件
term词条 docID
I love to go rock climbing 1
I like to collect rock albums 2

ES检索过程:

1.根据检索字段,如果是text类型的,按照写入索引时的分词机制,进行查询关键字分词,

2.查询字段对应的倒排索引文件,查询term分词,得到对应的docID

3.根据docID,获得doc,显示查询结果。

 

提问:

1.about.keyword的作用,换而言之,keyword数据类型和text数据类型的区别?

"about":"I love to go rock climbing"

对上面的about字段,keyword数据类型只支持精确搜索,因为keyword建立的索引文件的term,是全词建立索引,没有分词,所以,对于检索 about:"i",如果格式为keyword将返回null,无搜索结果。如果格式为text,则分词后建立索引,搜索  about:"i",有结果,因为有I 的term,由此可见,分词机制对搜索影响很大,因为term只能完全匹配,才会得到term对应的文档。

 

倒排索引的不足

1.倒排索引,按分词建立,建立后不可修改。

ES针对修改倒排索引,使用的是再合并策略:对修改的数据建立新的,小的索引文件,记录时间,新的索引文件和旧的索引文件合并,修改的部分,按时间最新覆盖。

2.倒排索引可以很快的通过分词,得到包含分词的文档。但是,如果我们已知文档,想得到文档拥有哪些分词,需要遍历整个倒排索引文件,影响效率。

解决办法是引入doc_values,doc_values是文档对应的分词形成的索引文件。

3.倒排索引十分依赖分词机制,分词机制不好,则搜索结果不理想

ES提供很多分词机制,也支持自定义分词机制。当然,如果不需要分词,只需要精准匹配,直接建立keyword类型数据即可。

 

二.doc_values 文档值

2.1. doc_values是什么

doc_values是elasticsearch中,对于倒排索引的部分缺点进行部分补充的功能。查看dov_values官方解释

倒排索引很方便单项查看 分词对应的文档,但是不利于反向查看,文档所有的分词。doc_values可以理解为反向的倒排索引,

doc_values存放的是文档对应的分词

2.1 doc_values的应用场景

上面说doc_values 是为了满足反向查询倒排索引而建立的。那么,什么样的情况我们需要用到doc_values呢。大致说来,聚合,排序,都会用到doc_values,

首先,我们进行一次聚合。

//增加一条记录
PUT /employee/group/3
{
    "age" :         32,
    "about" :       "I like to read book",
    "interests":  [ "music","books" ]
}
//查询abount中有i的,按age聚合,统计文档数
GET /employee/_search
{
  "query" : {
    "match" : {
      "about" : "i"
    }
  },
  "aggs" : {
    "res": {
      "terms" : {
        "field" : "age"
      }
    }
  }
}

这条语句主要是为了分析,每个数据出现的次数,例如,music有多少人喜欢,sports有多少人喜欢。结果如下:

{
  "aggregations": {
    "res": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": 32,                   //age=32的有两个文档
          "doc_count": 2
        },
        {
          "key": 25,                   //age=25的有一个文档
          "doc_count": 1
        }
      ]
    }
  }
}

将上面的查询聚合过程分解:

1.执行query,查询about中包含i这个term的doc。得到文档1,2,3

2.得到文档1,2,3后,我们分析1,2,3的age字段,判断每个age的有多少人。

在第2步中,如果我们只有倒排索引文件,我们需要遍历整个倒排索引,去获取,1,2,3文档的age索引文件,按照age索引文件的term(age是数值类型,整词形成倒排索引,不进行分词),即age的值,然后合并统计文档数。

但是如果我们有doc_values之后,就很方便统计了。

doc_values是和倒排索引同时建立的。同样按索引/类型/字段区分索引文件,doc_value生成数据为:

age-1-doc_values索引文件
文档ID 包含的term(不分词的term,即字段对应的值)
1 25
2 32
3 32

 

有了doc_values的查询聚合过程如下:

1.执行query,查询about中包含i这个term的doc。得到文档1,2,3

2.得到文档1,2,3后,查询age对应的doc_values索引文件,将age合并,计数,得到25->1,32->2,返回结果。

搜索和聚合是相互紧密缠绕的。搜索使用倒排索引查找文档,聚合操作收集和聚合 doc values 里的数据。

注意:

doc_values对不分词的字段默认开启,包括about.keyword这类多域字段,对分词字段默认关闭,即about字段

#分词字段# 从数据类型来看,text默认进行分词,keyword,long,int,double,复杂数据类型等默认不进行分词

刚才的描述中,经常强调doc_values存放的是 文档对应的分词数,这句话是容易引起歧义的,但是又是正确的,如果,该字段不允许分词,则该字段的值,就是该文档在这个索引文件的唯一分词(即term),对于能分词的字段,doc_values是默认关闭,但是可以手动开启,这个时候,doc_values存放的是文档对应的分词数 ,这句话就是正确的。

所以,对于doc_values的用途,ES官网的说法是:

Doc values 不仅可以用于聚合。 任何需要查找某个文档包含的值的操作都必须使用它。 除了聚合,还包括排序,访问字段值的脚本,父子关系处理,参见 父-子关系文档 

#为什么对分词字段关闭#  没找到官方解释 、个人看法:对分词字段,开启doc_values,产生的索引文件占用磁盘过大,处理的时候,消耗cpu资源,

 

doc_values的优缺点

1.doc_values 提高了聚合,排序,所有针对字段值的操作的效率,

2.doc_values加大了磁盘空间,但是ES提供了doc_values的压缩算法,对doc_values进行了大量压缩。而且,用不到可以禁用,节省空间。
 

三.Fielddata 

3.1 fielddata是什么

因为doc_values不针对分词字段,那么,如果一定要对分词字段的term分词进行聚合,该怎么办呢?

在es中,对分词的field,直接执行聚合操作,会报错,

{
        "type": "illegal_argument_exception",
        "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [about] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."
      }

大概意思是说,你必须要打开fielddata,然后将正排索引数据加载到内存中,才可以对分词的field执行聚合操作,而且会消耗很大的内存

fielddata就是满足该需求的,但是,因为过于消耗资源,所以默认关闭。

fielddata结构和doc_values相同,区别是.fielddata运算时在内存中生成,纯内存计算,doc_values放在磁盘中即可

有需求时,在mapping中打开fielddata开关。默认false关闭。

doc_values和fielddata详细说明可以查看博客 elasticsearch的Doc Values 和 Fielddata

四.store存储

字段独立于_source,单独存储,

注:_source中依然会存储该字段

优点: ES中,所有数据统一存在_source中,如果只是查询一个小字段,却要把_source中的整条数据显示后,再从_source中取出对应的字段,浪费资源。

缺点: 加大磁盘使用。

应用场景: 如果_source很大,频繁使用的字段很小,则应该store该字段,这样不需要每次都将_source加载完后,在查找该字段。

你可能感兴趣的:(elasticsearch)