# fielddata（字段数据）

所有字段是默认被 [**indexed**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/mapping-index.html)（被索引的），这使得它们是可搜索的.可以在脚本中排序,聚合和获取字段值,但是需要不同的搜索模式.

搜索需要回答一个问题 “哪个 **document（文档）**&#x5305;含这个 **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**字段上默认是关闭的.&#x5728;**\[your\_field\_name]** 上设置**fielddata = true**，以便通过反转反向索引来加载内存中的**fielddata**。 请注意，这可能会使用显着的内存。

## 在开启fielddata之前

在你开启**fielddata** 之前,考虑一下为什么你要在脚本中使用 **text** 来聚合,排序.通常这么做是没有意义的.

在索引之前分析**text**字段,以至于像**New York** 这样的值可以通过**new**或者 **york** 来搜索.当你可能想要一个称作 **New York** 的单一bucket（桶）,**term**（词条）在这个字段上聚合会返回一个**newbucket**和一个**yorkbucket**（桶）.

相反,你应该使用**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) 给一个已经存在的**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)在现有字段上更新其值.
>
> 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)和[`keyword`](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/keyword.html)字段中支持.
>
> **Fielddata**和**doc\_values**也有 ordinals（序数）,它是特定**segment**（段）和字段中所有**term**（词根）的唯一编&#x53F7;**.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
          }
        }
      }
    }
  }
}
'
```
