🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# fielddata(字段数据) 原文链接 : [https://www.elastic.co/guide/en/elasticsearch/reference/5.3/fielddata.html#field-data-filtering](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/fielddata.html#field-data-filtering) 译文链接 : [fielddata(字段数据)](/pages/viewpage.action?pageId=10028596) 贡献者 : [程威](/display/~chengwei),[ApacheCN](/display/~apachecn),[Apache中文网](/display/~apachechina) 所有字段是默认被 [**indexed**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/mapping-index.html)(被索引的),这使得它们是可搜索的.可以在脚本中排序,聚合和获取字段值,但是需要不同的搜索模式. 搜索需要回答一个问题 “哪个 **document(文档)** 包含这个 **term**(词条)”,然而排序和聚合需要回答一个不同的问题 " 这个字段在这个 **document**(文档)中的值是多少?". 许多字段可以使用 **index-time**,在磁盘上的 **doc_values** 支持这种数据访问模式, 但是 **text** 字段不支持 **doc_values**。 相反,**text** 字段使用查询时存在于内存的数据结构 **fielddata**.这个数据结构是第一次将字段用于聚合,排序,或者脚本时基于需求构建的。它是通过读取磁盘上的每个 **segment**(片段)的整个反向索引来构建的,将 **term**(词条)和 **document**(文档)关系反转,并将结果存储在内存中,在**JVM**的堆中. ## text 字段默认关闭 Fielddata  **Fielddata** 会消耗很多堆空间,尤其是加载高基数的 **text** 字段的时候.一旦 **fielddata **加载到堆中,它在  **segment**(片段)中的生命周期还是存在的.此外,加载  **fielddata** 是一件非常昂贵的过程,会导致用户体验到延迟的感觉.这就是为什么 **fielddata **默认关闭. 如果你尝试对文本字段上的脚本进行排序,访问值,你会看到此异常: * **Field data **在 **text** 字段上默认是关闭的.在 **[your_field_name]**上设置 **fielddata = true**,以便通过反转反向索引来加载内存中的 **fielddata**。 请注意,这可能会使用显着的内存。 ## 在开启fielddata之前 在你开启 **fielddata ** 之前,考虑一下为什么你要在脚本中使用  **text **来聚合,排序.通常这么做是没有意义的. 在索引之前分析 **text** 字段,以至于像 **New York **这样的值可以通过 **new** 或者  **york** 来搜索.当你可能想要一个称作  **New York ** 的单一bucket(桶), **term**(词条)在这个字段上聚合会返回一个 **new** **bucket**和一个 **york** **bucket**(桶). 相反,你应该使用 **text** 字段进行全文搜索,以及一个开启 **doc_values** 的 **unanalyzed**(未分析) **[keyword](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/keyword.html)**  字段用于聚合,如下: ``` curl -XPUT 'localhost:9200/my_index?pretty' -H 'Content-Type: application/json' -d' { "mappings": { "my_type": { "properties": { "my_field": { # 1 "type": "text", "fields": { "keyword": { # 2 "type": "keyword" } } } } } } } ' ``` | 1 | 使用 **my_field** 用于搜索 | | 2 | 使用 **my_field.keyword** 用于聚合,排序,或者脚本. | ## 开启text 字段的fielddata 你可以使用以下的 [PUT mapping API](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/indices-put-mapping.html "Put Mapping")  给一个已经存在的 **text** 字段开启 **fielddata**. ``` curl -XPUT 'localhost:9200/my_index/_mapping/my_type?pretty' -H 'Content-Type: application/json' -d' { "properties": { "my_field": { # 1 "type": "text", "fielddata": true } } } ' ``` | 1 | 你为 **my_field** 指定的映射应包含该字段已有的映射,再加上 **fielddata** 参数. | 建议 **fielddata.* **参数必须在相同索引的相同名称的字段有相同的设置.可以使用 [PUT mapping API](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/indices-put-mapping.html "Put Mapping")  在现有字段上更新其值. Global ordinals **Global ordinals**(全局序数)是一个基于 **field data**和 **doc_values** 的数据结构,它以字典顺序每户每个唯一 **term**(词根)的增量编号.每个 **term**(词根)都有一个唯一的数,**term**(词根)A是低于 **term**(词根)B的.**Global ordinals** (全局序数)仅在 **[`text`](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/text.html "Text datatype")** 和 **[`keyword`](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/keyword.html "Keyword datatype")** 字段中支持. **Fielddata** 和 **doc_values** 也有 ordinals(序数),它是特定**segment**(段)和字段中所有**term**(词根)的唯一编号**.Global ordinals**(全局序数)只是建立在 **fielddata**和 **doc_values**之上,通过在 **segement ordinals** 和 **global ordinals** 之间提供映射,后者在整个**shard**(分片)中是唯一的. **Global ordinals** 是用于使用 **segement ordinals**(片段序数)的功能,例如排序和 **terms**(词根)聚合,以提高执行时间.**term**(词根)聚合完全依赖于 **Global ordinals**(全局序数)来执行 **shard** (分片)级别的聚合,然后将**global ordinals** (全局序数)转换为真正的 **term**(词根),**term**(词根)仅用于最终减少阶段,其结合不同 **shard**(分片)的结果. 指定字段的 **Global ordinals** (全局序数)与 **shard**(分片)所有的字段相关联,而 **field data** 和 **doc_values** 与单个 **segment**(片段)相关联.其与针对单个**segment**(段)相关联的特定字段的字段数据不同,一旦新的 **segment**(片段)变得可见, **Global ordinals**(全局序数)就需要完全重建.  **Global ordinals**(全局序数)取决于一个字段上的 **terms**(词根)数量,但通常它是比较低的.因为源字符安数据已经被加载.**Global ordinals**(全局序数)的内存开销很小,因为它被有效的压缩. ## fielddata_frequency_filter **Fielddata **过滤可以用于减少加载到内存中 **term**(词根)数量,从而减少内存使用.**term**(词根)可以按频率来过滤 : 频率过滤器允许你仅加载 **document**(文档)频率在最小和最大值之间的 **term**(词根),可以表示为绝对数字(当数字大于1.0时)或百分比(例如0.01为1%,1.0为100%).每个**segment**计算频率.百分比是基于 **docs**(文档)的数量,而不是该 **segment**(片段)的所有 **docs**(文档). 通过使用 **min_segment_size **指定 **segment**(片段)应包含的文档和最小数量,可以完全排除 ** small segment** (小的片段),如下: ``` curl -XPUT 'localhost:9200/my_index?pretty' -H 'Content-Type: application/json' -d' { "mappings": { "my_type": { "properties": { "tag": { "type": "text", "fielddata": true, "fielddata_frequency_filter": { "min": 0.001, "max": 0.1, "min_segment_size": 500 } } } } } } ' ```