ElasticSearch搜索引擎:常用的存储mapping配置项 与 doc_values详细介绍

ElasticSearch搜索引擎:常用的存储mapping配置项 与 doc_values详细介绍

一、ES的数据存储结构:

ES底层使用 Lucene 存储数据,Lucene 的索引包含以下部分:

A Lucene index is made of several components: an inverted index, a bkd tree, a column store (doc values), a document store (stored fields) and term vectors, and these components can communicate thanks to these doc ids.

 其中:

  • inverted index:倒排索引。
  • bkd tree: Block k-d tree,用于在高维空间内做索引,如地理坐标的索引。
  • column store:doc values,列式存储,批量读取连续的数据以提高排序和聚合的效率。
  • document store:Store Fileds,行式存储文档,用于控制 doc 原始数据的存储,其中占比最大的是 source 字段。
  • term vectors:用于存储各个词在文档中出现的位置等信息。

 

二、ES常见配置项说明:

在很多场合下,我们并不需要存储上述全部信息,因此可以通过设置 mappings 里面的属性来控制哪些字段是我们需要存储的、哪些是不需要存储的。而 ES 的 mapping 中有很多设置选项,这些选项如果设置不当,有的可能浪费存储空间,有的可能导致无法使用 Aggregation,有的可能导致不能检索。下面就简单介绍下 ES 中常见的存储与检索的 mapping 配置项:

配置项 作用 注意事项 默认值
_all 提供跨字段全文检索

(1)会占用额外空间,把 mapping 中的所有字段通过空格拼接起来做索引,在跨字段全文检索才需要打开;

(2)在 v6.0+已被弃用,v7.0会正式移除,可以使用 [copy_to] 来自定义组合字段

关闭
_source 存储 post 提交到ES的原始 json 内容

(1)会占用很多存储空间。数据压缩存储,读取会有额外解压开销。

(2)不需要读取原始字段内容可以考虑关闭,但关闭后无法 reindex

开启
store 是否单独存储该字段 (1)会占用额外存储空间,与 source 独立,同时开启 store 和 source 则会将该字段原始内容保存两份,不同字段单独存储,不同字段的数据在磁盘上不连续,若读取多个字段则需要查询多次,如需读取多个字段,需权衡比较 source 与 store 效率 关闭
doc_values 支持排序、聚合 会占用额外存储空间,与 source 独立,同时开启 doc_values 和 _source 则会将该字段原始内容保存两份。doc_values 数据在磁盘上采用列式存储,关闭后无法使用排序和聚合 开启
index 是否加入倒排索引 关闭后无法对其进行搜索,但字段仍会存储到 _source 和 doc_values,字段可以被排序和聚合 开启
enabled 是否对该字段进行处理 关闭后,只在 _source中存储,类似 index 与 doc_values 的总开关 开启

在ES的 mapping 设置里,all,source 是 mapping 的元数据字段(Meta-Fields),store、doc_values、enabled、index 是 mapping 参数。

1、_all:

all 字段的作用是提供跨字段查询的支持,把 mapping 中的所有字段通过空格拼接起来做索引。ES在查询的过程中,需要指定在哪一个field里面查询。

{
    “name”: “smith”,
    “email”: "John@example.com"
}

用户在查询时,想查询叫做 John 的人,但不知道 John 出现在 name 字段中还是在 email 字段中,由于ES是为每一个字段单独建立索引,所以用户需要以 John 为关键词发起两次查询,分别查询name字段和email字段。

如果开启了 all 字段,则ES会在索引过程中创建一个虚拟的字段 all,其值为文档中各个字段拼接起来所组成的一个很长的字符串(例如上面的例子,all 字段的内容为字符串 “smith John@example.com”)。随后,该字段将被分词打散,与其他字段一样被收入倒排索引中。由于 all 字段包含了所有字段的信息,因此可以实现跨字段的查询,用户不用关心要查询的关键词在哪个字段中。

由于该字段的内容都来自 source 字段,因此默认情况下,该字段的内容并不会被保存,可以通过设置 store 属性来强制保存 all 字段。开启 all 字段,会带来额外的CPU开销和存储,如果没有使用到,可以关闭 all 字段。

2、_source:

source 字段用于存储 post 到 ES 的原始 json 文档。为什么要存储原始文档呢?因为 ES 采用倒排索引对文本进行搜索,而倒排索引无法存储原始输入文本。一段文本交给ES后,首先会被分析器(analyzer)打散成单词,为了保证搜索的准确性,在打散的过程中,会去除文本中的标点符号,统一文本的大小写,甚至对于英文等主流语言,会把发生形式变化的单词恢复成原型或词根,然后再根据统一规整之后的单词建立倒排索引,经过如此一番处理,原文已经面目全非。因此需要有一个地方来存储原始的信息,以便在搜到这个文档时能够把原文返回给查询者。

那么一定要存储原始文档吗?不一定!如果没有取出整个原始 json 结构体的需求,可以在 mapping 中关闭 source 字段或者只在 source 中存储部分字段(使用store)。 但是这样做有些负面影响:

  • (1)不能获取到原文
  • (2)无法reindex:如果存储了 source,当 index 发生损坏,或需要改变 mapping 结构时,由于存在原始数据,ES可以通过原始数据自动重建index,如果不存 source 则无法实现
  • (3)无法在查询中使用script:因为 script 需要访问 source 中的字段

3、store:

store 决定一个字段是否要被单独存储。大家可能会有疑问,source 里面不是已经存储了原始的文档嘛,为什么还需要一个额外的 store 属性呢?原因如下:

(1)如果禁用了 source 保存,可以通过指定 store 属性来单独保存某个或某几个字段,而不是将整个输入文档保存到 source 中。

(2)如果 source 中有长度很长的文本(如一篇文章)和较短的文本(如文章标题),当只需要取出标题时,如果使用 source 字段,ES需要读取整个 source 字段,然后返回其中的 title,由此会引来额外的IO开销,降低效率。此时可以选择将 title 的 store 设置为true,在 source 字段外单独存储一份。读取时不必在读取整 source 字段了。但是需要注意,应该避免使用 store 查询多个字段,因为 store 的存储在磁盘上不连续,ES在读取不同的 store 字段时,每个字段的读取均需要在磁盘上进行查询操作,而使用 source 字段可以一次性连续读取多个字段。

4、doc_values:

倒排索引可以提供全文检索能力,但是无法提供对排序和数据聚合的支持。doc_values 本质上是一个序列化的列式存储结构,适用于聚合(aggregations)、排序(Sorting)、脚本(scripts access to field)等操作。默认情况下,ES几乎会为所有类型的字段存储doc_value,但是 text 或 text_annotated 等可分词字段不支持 doc values 。如果不需要对某个字段进行排序或者聚合,则可以关闭该字段的doc_value存储。

5、index:

控制倒排索引,用于标识指定字段是否需要被索引。默认情况下是开启的,如果关闭了 index,则该字段的内容不会被 analyze 分词,也不会存入倒排索引,即意味着该字段无法被搜索。

6、enabled:

这是一个 index 和 doc_value 的总开关,如果 enabled 设置为false,则这个字段将会仅存在于 source 中,其对应的 index 和 doc_value 都不会被创建。这意味着,该字段将不可以被搜索、排序或者聚合,但可以通过 source 获取其原始值。

7、term_vector:

在对文本进行 analyze 的过程中,可以保留有关分词结果的相关信息,包括单词列表、单词之间的先后顺序、单词在原文中的位置等信息。查询结果返回的高亮信息就可以利用其中的数据来返回。默认情况下,term_vector是关闭的,如有需要(如加速highlight结果)可以开启该字段的存储。

 

三、doc_values 详细说明:

1、doc_values 的作用:

基于 lucene 的 solr 和 es 都是使用倒排索引实现快速检索的,也就是通过建立 “搜索关键词 ==>文档ID列表” 的关系映射实现快速检索,但是倒排索引也是有缺陷的,比如我们需要字段值做一些排序、分组、聚合操作,lucene 内部会遍历提取所有出现在文档集合的排序字段,然后再次构建一个最终的排好序的文档集合list,这个步骤的过程全部维持在内存中操作,而且如果排序数据量巨大的话,非常容易就造成solr内存溢出和性能缓慢。

doc values 就是在构建倒排索引时,会对开启 doc values 的字段额外构建一个有序的 “document文档 ==> field value“ 的列式存储映射,从而实现对指定字段进行排序和聚合时对内存的依赖,提升该过程的性能。默认情况下每个字段的 doc values 都是开启的,当然 doc values 也会耗费一定的磁盘空间。

另外 doc values 保存在操作系统的磁盘中,当 doc values 大于节点的可用内存,ES 可以从操作系统页缓存中加载或弹出,从而避免发生 JVM 内存溢出的异常,docValues 远小于节点的可用内存,操作系统自然将所有Doc Values存于内存中(堆外内存),有助于快速访问。

2、doc_values 与 source 的区别?使用 docvalue_fields 检索指定的字段?

post 提交到 ES 的原始 Json 文档都存储在 source 字段中,默认情况下,每次搜索的命中结果都包含文档 source,即使仅请求少量字段,也必须加载并解析整个 source 对象,而 source 每次使用时都必须加载和解析,所以使用 source 非常慢。为避免该问题,当我们只需要返回相当少的支持 doc_values 的字段时,可以使用 docvalue_fields 参数获取选定字段的值。

doc values 存储与 _source 相同的值,但在磁盘上基于列的结构中进行了优化,以进行排序和汇总。由于每个字段都是单独存储的,因此 Elasticsearch 仅读取请求的字段值,并且可以避免加载整个文档 _source。通过 docvalue_fields 可以从建好的列式存储结果中直接返回字段值,毕竟 source 是从一大片物理磁盘去,理论上从 doc values 处拿这个字段值会比 source 要快一点,页面抖动少一点。

3、如何在 ES 中使用 doc values?

doc values 通过牺牲一定的磁盘空间带来的好处主要有两个:

  • 节省内存
  • 提升排序,分组等聚合操作的性能

那么我们如何使用 doc values 呢?

(1)我们首先关注如何激活 doc values,只要开启 doc values 后,排序,分组,聚合的时候会自动使用 doc values 提速。在 ElasticSearch 中,doc values 默认是开启的,比较简单暴力,我们也可以酌情关闭一些不需要使用 doc values 的字段,以节省磁盘空间,只需要设置 doc_values 为 false 就可以了,如下:

"session_id":{"type":"string","index":"not_analyzed","doc_values":false}

(2)使用 docvalue_fields 的检索指定的字段:

GET my-index-000001/_search
{
  "query": {
    "match": {
      "user.id": "kimchy"
    }
  },
  "docvalue_fields": [
    "user.id",
    "http.response.*", 
    {
      "field": "date",
      "format": "epoch_millis" 
    }
  ]
}

 

ES搜索指定字段的不同方式,详情请见官网:https://www.elastic.co/guide/en/elasticsearch/reference/7.x/search-fields.html#search-fields

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/114590.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • BCG网格控件单独设置颜色

    BCG网格控件单独设置颜色源码下载:http://download.csdn.net/detail/he_zhidan/8009531

  • autoconf 报错

    autoconf 报错报错现象:error:Autoconfversion2.64orhigherisrequired解决办法:查询当前版本:[python]viewplaincopy[root@wslu-cswslu]#rpm-qf/usr/bin/autoconfautoconf-2.63-5.1.el6.noarch卸载当前版本:[python]viewplainco…

  • zookeeper启动报错出现Starting zookeeper … FAILED TO START详细解决方案

    zookeeper启动报错出现Starting zookeeper … FAILED TO START详细解决方案zookeeper启动时出现/usr/local/apache-zookeeper-3.5.9-bin/bin/../没有权限等问题

    2022年10月19日
  • 无锁队列实现原理_优先队列 java

    无锁队列实现原理_优先队列 java首次接触无锁数据结构的设计,请各位大佬多多指教~~~CAS(Compare&&Swap)原子操作CAS是无锁(lockfree)的数据结构的基础。用伪代码描述:input:reg,old_val,new_val/*是old_val,reg替换为new_val,返回为true;否则返回为false*/if(*reg==old_val){*reg==new…

    2022年10月21日
  • mnist手写数字识别代码(knn手写数字识别)

    MNIST手写数字识别模型建立与优化本篇的主要内容有:TensorFlow处理MNIST数据集的基本操作建立一个基础的识别模型介绍SoftmaxSoftmaxSoftmax回归以及交叉熵等MNIST是一个很有名的手写数字识别数据集(基本可以算是“HelloWorld”级别的了吧),我们要了解的情况是,对于每张图片,存储的方式是一个28*28的矩阵,但是我们在导入数据进…

  • Elasticsearch:Painless 编程调试「建议收藏」

    Painless也就是无痛的意思。这是一个专为Elasticsearch而设计的。当初的设计人员取名为“Painless”,表达的意思的是在编程的时候没有疼痛感,很方便设计人员使用。由于这是一个脚本的语言,在实际的使用中,我们很难找到这些编程的方法及使用。在今天的教程中,我来讲述一下该如何来进行调试。Debug.ExplainPainless没有REPL,虽然很高兴有一天,但它不会告诉你调试Elasticsearch中嵌入的Painless脚本的全部过程,因为脚本可以访问或“上

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号