用了Elasticsearch,一口气上5T

elasticsearch 中的store 以及倒排索引的问题

Elasticsearch | 作者 code4j | 发布于2018年01月16日 | 阅读数:6641

近期看了下es的一些属性,平时基本没接触到,看到store的时候 官方的说法我有点困惑,说下自己的,看看是不是对的。
 es的store表示是否存储该字段。不存储的话无法展示。
 
但是其实默认的store属性就是no,然而我们依然能够检索出所有的字段,原因是还有一个_source字段,这个字段存储了我们index的时候的全部属性,所以我们可以通过解析source来获得里面的字段,如果我们不指定field的话,甚至不需要解析直接返回整个source。
 
store = yes会对这个字段做单独存储,我理解的是es除了构建倒排索引,还会构建一个存储域,倒排索引用来做查询命中文档id,存储域用来存放写入的具体文档,如果store=yes则是将这个field单独存储到一个存储域中,因此使用field获取字段的时候 不走source,会去额外的区域获取字段值,等于IO操作多了一次,field越多,IO次数越多。
 
关于使用场景,对于很长的字段建议store 放到额外地方,我理解是这样的:很长的字段通常不会用来搜索,但是可能用来展示,额外存储能够减小_source字段的压力,再指定field 字段不是store的时候要从source中获取,轻量的source解析更快。
 
上述理解若没有偏差,还有几个疑问:
1.如果某字段field 设置了store,索引没有禁用source,获取全部字段的时候,对于字段field是不是也要强制走额外的存储?我的理解按照优化的角度考虑es应该在这一步取消多余的IO。
 
2.store是否会影响倒排索引存储方式?字段放到额外的区域和放到source里面在构建倒排索引的时候有什么区别吗?我理解的不管是否存储,都是按照每个field 独立构建倒排索引的,构建方式的话就通过解析_source的字段建立字典和文档映射,不知道理解对不对。
已邀请:

rockybean - Elastic Certified Engineer, ElasticStack Fans,公众号:ElasticTalk

赞同来自: novia jianjianhe davidyan

好问题!如果了解过 lucene 的话,理解这个就会容易很多。
 
首先 field.store  这个属性其实是 lucene 创建字段时候的一个选项,表明是否要记录原始值。除了 field.store 属性外还有一个参数是 field.index 是配置该字段是否分词,也就是是否构建倒排索引。
 
这两个配置作用不同。如果配置了 field.index ,那么可以使用该字段进行全文检索,反之则不能用该字段检索。配置 field.store 为 yes,在查询后,会将字段原始值返回,如果 field.store 为 no,那么返回结果就没有该字段值。使用 lucene 的时候,一般是将 id 类的字段设置 field.store 为 yes,这样在搜索结果中拿到 id 后就可以进一步去获取详情数据了。
 
那么再来说说 _source,这个字段是 es 自己维护的一个元字段(其实和你的文档字段平级,没啥特殊的,也是个 lucene field),它的内容是你存储的原始文档,而且设置了 field.store 为 yes,也就意味着在 lucene 做查询返回结果时,该字段会返回。那么你也就能拿到文档的原始结果了。所谓的 source fitlering,其实就是拿到_source后做一些过滤。那么问题来了,如果我有一个字段,比如存储的是文档内容,很长,那么这个时候_source就会很大,你获取的结果的时候网络开销就会大,性能就有问题,但很明显你不需要从es 来获取原始内容。这是时候你就可以把 _source 功能关闭,然后自己去设定字段 store 的属性,比如只 store id 或者标题类的字段,内容类字段就忽略了,只做检索就可以了。
 
总结一句,field.store 是lucene 的一个控制项,_source是一个元字段,也是有 store 这个控制项的,默认是 yes。
 
至于 store 在底层是如何存的,这个就可以进一步去看 lucene 的文档了。最后附一个测试的例子,里面还有 fielddata 的设定,可以自己试试看。
 
PUT test_store
{
"mappings": {
"doc": {
"_source": {
"enabled":false
},
"properties": {
"name": {
"type": "keyword",
"store": true
},
"age": {
"type": "long",
"store": true
},
"desc": {
"type": "text",
"fielddata": true,
"store": true
}
}
}
}
}


PUT test_store/doc/2
{
"money":10.3,
"name":"asf",
"age":12,
"desc":"hello,world"
}

GET test_store/_search

GET test_store/_search?stored_fields=*


GET test_store/_search
{
"stored_fields": ["name","age","desc"],
"docvalue_fields": ["desc"]
}



 

kennywu76 - Wood

赞同来自: code4j cccthought

理解上没有偏差。 关于两个疑问:
1. 搜索的时候,获取的field value的方式是可以指定从source获取还是从stored fields获取。 例如下面的Query指定从stored fields获取字段的值:
GET my_index/_search
{
"stored_fields": [ "title", "date" ]
}

 也可以借助source_filtering,从_source拿值,达到同样的效果, 参考: https://www.elastic.co/guide/e ... .html
 2. 倒排索引是term到文档ID的映射,stored field或者source不参与这个映射过程。 也就是不管采用哪种保存字段值的方式,倒排索引还是一样的,查询的时候match的开销是一样的。 不同的只是在fetch结果的开销有差异。

要回复问题请先登录注册