Elasticsearch 中映射参数doc_values 和 fielddata分析比较

doc_values
默认状况下,大部分字段是索引的,这样让这些字段可被搜索。倒排索引(inverted index)容许查询请求在词项列表中查找搜索项(search term),并当即得到包含该词项的文档列表。
 
倒排索引(inverted index):
若是咱们想要得到全部包含 brown 的文档的词的完整列表,咱们会建立以下查询:
GET /my_index/_search
{
  "query" : {
    "match" : {
      "body" : "brown"
    }
  },
  "aggs" : {
    "popular_terms": {
      "terms" : {
        "field" : "body"
      }
    }
  }
}
 
倒排索引是根据词项来排序的,因此咱们首先在词项列表中找到 brown,而后扫描全部列,找到包含 brown 的文档。咱们能够快速看到 Doc_1 和 Doc_2 包含 brown 这个 token。
而后,对于聚合部分,咱们须要找到 Doc_1 和 Doc_2 里全部惟一的词项。用倒排索引作这件事情代价很高: 咱们会迭代索引里的每一个词项并收集 Doc_1 和 Doc_2 列里面 token。这很慢并且难以扩展:随着词项和文档的数量增长,执行时间也会增长。
Doc values 经过转置二者间的关系来解决这个问题。倒排索引将词项映射到包含它们的文档,doc values 将文档映射到它们包含的词项:
当数据被转置以后,想要收集到 Doc_1 和 Doc_2 的惟一 token 会很是容易。得到每一个文档行,获取全部的词项,而后求两个集合的并集。
 
Doc values 可使聚合更快、更高效而且内存友好。Doc values 的存在是由于倒排索引只对某些操做是高效的。
倒排索引的优点:在于查找包含某个项的文档,而对于从另一个方向的相反操做并不高效,即:肯定哪些项是否存在单个文档里,聚合须要这种访问模式。
 
在 Elasticsearch 中,Doc Values 就是一种列式存储结构,默认状况下每一个字段的 Doc Values 都是激活的,Doc Values 是在索引时建立的。当字段索引时,Elasticsearch 为了可以快速检索,会把字段的值加入倒排索引中,同时它也会存储该字段的 `Doc Values`。
 
Elasticsearch 中的 Doc Values 常被应用到如下场景:
  • 对一个字段进行排序
  • 对一个字段进行聚合
  • 某些过滤,好比地理位置过滤
  • 某些与字段相关的脚本计算
 
由于文档值(doc values)被序列化到磁盘,咱们能够依靠操做系统的帮助来快速访问。当 working set 远小于节点的可用内存,系统会自动将全部的文档值保存在内存中,使得其读写十分高速;当其远大于可用内存,操做系统会自动把 Doc Values 加载到系统的页缓存中,从而避免了 jvm 堆内存溢出异常。
 
所以,搜索和聚合是相互紧密缠绕的。搜索使用倒排索引查找文档,聚合操做收集和聚合 doc values 里的数据。
 
doc values 支持大部分字段类型,可是text 字段类型不支持(由于analyzed)。
(1) status_code 字段默认启动 doc_values 属性;
(2) session_id 显式设置 doc_values = false,可是仍然能够被查询;
 
若是确信某字段不须要排序或者聚合,或者从脚本中访问字段值,那么咱们能够设置 doc_values = false,这样能够节省磁盘空间。
 
fielddata
与 doc values 不一样,fielddata 构建和管理 100% 在内存中,常驻于 JVM 内存堆。这意味着它本质上是不可扩展的。
 
fielddata可能会消耗大量的堆空间,尤为是在加载高基数(high cardinality)text字段时。一旦fielddata已加载到堆中,它将在该段的生命周期内保留。此外,加载fielddata是一个昂贵的过程,可能会致使用户遇到延迟命中。这就是默认状况下禁用fielddata的缘由。
 
若是须要对 text 类型字段进行排序、聚合、或者从脚本中访问字段值,则会出现以下异常:
Fielddata is disabled on text fields by default. Set fielddata=true on [your_field_name] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.
 
可是,在启动fielddata 设置以前,须要考虑为何针对text 类型字段进行排序、聚合、或脚本呢?一般状况下,这是不太合理的。
text字段在索引时,例如New York,这样的词会被分词,会被拆成new、york 2个词项,这样当搜索new 或 york时,能够被搜索到。在此字段上面来一个terms的聚合会返回一个new的bucket和一个york的bucket,可是你可能想要的是一个单一new york的bucket。
 
怎么解决这一问题呢?
你可使用 text 字段来实现全文本查询,同时使用一个未分词的 keyword 字段,且启用doc_values,来处理聚合操做。
(1) 使用my_field 字段用于查询;
(2) 使用my_field.keyword 字段用于聚合、排序、或脚本;
 
可使用 PUT mapping API 在现有text 字段上启用 fielddata,以下所示:
 
 《Elasticsearch 7.x从入门到精通》专栏会经过理论与实践相结合的方式,带领你一步一步走进Elasticsearch的世界,使你轻松掌握Elasticsearch的基本概念,学习Elasticsearch的服务搭建,了解Elasticsearch的经常使用技巧,并经过案例项目让你拥有实际的应用能力。 同时,也会讲解Elastic Stack中其余相关组件,如Logstash、Beats和Kibana等等。
相关文章
相关标签/搜索