# fielddata

字段数据(fielddata)，在 Lucene 中又叫 uninverted index。我们都知道，搜索引擎会使用倒排索引(inverted index)来映射单词到文档的 ID 号。而同时，为了提供对文档内容的聚合，Lucene 还可以在运行时将每个字段的单词以字典序排成另一个 uninverted index，可以大大加速计算性能。

作为一个加速性能的方式，fielddata 当然是被全部加载在内存的时候最为有效。这也是 ES 默认的运行设置。但是，内存是有限的，所以 ES 同时也需要提供对 fielddata 内存的限额方式：

* indices.fielddata.cache.size

  节点用于 fielddata 的最大内存，如果 fielddata 达到该阈值，就会把旧数据交换出去。该参数可以设置百分比或者绝对值。默认设置是不限制，所以强烈建议设置该值，比如 `10%`。
* indices.fielddata.cache.expire

  进入 fielddata 内存中的数据多久自动过期。注意，因为 ES 的 fielddata 本身是一种数据结构，而不是简单的缓存，所以过期删除 fielddata 是一个非常消耗资源的操作。ES 官方在文档中特意说明，这个参数绝对绝对**不要**设置！

### Circuit Breaker

Elasticsearch 在 total，fielddata，request 三个层面上都设计有 circuit breaker 以保护进程不至于发生 OOM 事件。在 fielddata 层面，其设置为：

* indices.breaker.fielddata.limit

  默认是 JVM 堆内存大小的 60%。注意，为了让设置正常发挥作用，如果之前设置过 `indices.fielddata.cache.size` 的，一定要确保 `indices.breaker.fielddata.limit` 的值大于 `indices.fielddata.cache.size` 的值。否则的话，fielddata 大小一到 limit 阈值就报错，就永远道不了 size 阈值，无法触发对旧数据的交换任务了。

## doc values

但是相比较集群庞大的数据量，内存本身是远远不够的。为了解决这个问题，ES 引入了另一个特性，可以对精确索引的字段，指定 fielddata 的存储方式。这个配置项叫：`doc_values`。

所谓 `doc_values`，其实就是在 ES 将数据写入索引的时候，提前生成好 fielddata 内容，并记录到磁盘上。因为 fielddata 数据是顺序读写的，所以即使在磁盘上，通过文件系统层的缓存，也可以获得相当不错的性能。

注意：因为 `doc_values` 是在数据写入时即生成内容，所以，它只能应用在精准索引的字段上，因为索引进程没法知道后续会有什么分词器生成的结果。

由于在 Elastic Stack 场景中，`doc_values` 的使用极其频繁，到 Elasticsearch 5.0 以后，这两者的区别被彻底强化成两个不同字段类型：`text` 和 `keyword`。

```
"myfieldname": {
    "type": "text"
}
```

等同于过去的：

```
    "myfieldname": {
        "type": "string",
        "fielddata": false
    }
```

而

```
"myfieldname": {
    "type": "keyword"
}
```

等同于过去的：

```
    "myfieldname": {
        "type": "string",
        "index": "not_analyzed",
        "doc_values": true
    }
```

也就是说，以后的用户，已经不太需要在意 fielddata 的问题了。不过依然有少数情况，你会需要对分词字段做聚合统计的话，你可以在自己接受范围内，开启这个特性：

```
{
    "mappings": {
        "my_type": {
            "properties": {
                "message": {
                    "type": "text",
                    "fielddata": true,
                    "fielddata_frequency_filter": {
                        "min": 0.1,
                        "max": 1.0,
                        "min_segment_size": 500
                    }
                }
            }
        }
    }
}
```

你可以看到在上面加了一段 `fielddata_frequency_filter` 配置，这个配置是 segment 级别的。上面示例的意思是：只有这个 segment 里的文档数量超过 500 个，而且含有该字段的文档数量占该 segment 里的文档数量比例超过 10% 时，才加载这个 segment 的 fielddata。

下面是一个可能有用的对分词字段做聚合的示例：

```
curl -XPOST 'http://localhost:9200/logstash-2016.07.18/logs/_search?pretty&terminate_after=10000&size=0' -d '
{
    "aggs": {
        "group": {
            "terms": {
                "field": "punct"
            },
            "aggs": {
                "keyword": {
                    "significant_terms": {
                        "size": 2,
                        "field": "message"
                    },
                    "aggs": {
                        "hit": {
                            "top_hits": {
                                "_source": {
                                    "include": [ "message" ]
                                },
                                "size":1
                            }
                        }
                    }
                }
            }
        }
    }
}'
```

这个示例可以对经过了 `logstash-filter-punct` 插件处理的数据，获取每种 punct 类型日志的关键词和对应的代表性日志原文。其效果类似 Splunk 的事件模式功能：

![](http://chenlinux.com/images/uploads/splunk-event-pattern.png)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hezhiqiang.gitbook.io/elkstack/elasticsearch/xing-neng-you-hua/fielddata.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
