Fielddata
默认情况下,大多数字段都已被索引,这使得他们可以被搜索。排序、聚合、访问脚本中的字段值,需要有与搜索不同的访问方式。
查询需要回答”哪些文档包含了这些查询术语?“这样的问题,而排序、聚合需要回答不同的问题:“改字段对该文本的价值是什么?“。
大多数字段可以使用 index-time,存储在磁盘上的 doc_value
用于此数据的访问模式。但是 text 类型的字段不支持 doc_value
。
然而,text 类型的字段可以使用查询时基于内存的数据结构,称为fielddata
。一个 text 类型的字段第一次用来排序、聚合,或者用在 scrpit 中时,该数据结构会按需创建。通过从磁盘上读取每个段的倒排索引, 反转 term 来建造 <->文档关系,并将结果存储到 jvm 的堆内存中。
fielddata 在 text 类型的字段中默认是禁用的
fielddata 会占用大量的堆空间,尤其是加载高基数的 text 类型字段。一旦 fielddata 被加载进了内存,它将会在相应段的整个生命周期内都保留。当然,加载 fielddata 是一个昂贵的操作,会导致用户的查询延迟。这也是为什么 fielddata 默认情况下被禁止的缘故了。
如果你尝试在 text 类型的字段上进行排序、聚合、通过脚本访问其值,你将会看到这个异常:
Fielddata is disabled on text fields by default. Set
fielddata=true
on [your_field_name
] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.
在开启 fielddata 之前
在开始 fielddata 之前,想一想,为什么需要使用一个 text 类型的字段排序、聚合,或者在脚本中访问它,通常来说是没有意义的。
一个 text 类型的字段通常会在索引之前被分词解析,这样就可以使 new york
通过检索new
或者 york
找到。在该字段上进行 terms
聚合查询,就会得到一个 new
桶和一个 york
桶,然而,你需要的可能只是一个new york
桶。
相反,你应该用一个 text 类型的字段做全文索引,用另一个不分词且启动doc_values
的 keyword 类型字段做聚合操作:
curl -X PUT "localhost:9200/my_index?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"_doc": {
"properties": {
"my_field": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
}
'
使用 my_field 做全文搜索;
使用 my_field.keyword 做聚合、排序或在脚本中使用。
在 text 类型的字段上开启 fielddata
可以在已经存在的 text 类型字段上使用 put mapping API 开启 fielddata:
curl -X PUT "localhost:9200/my_index/_mapping/_doc?pretty" -H 'Content-Type: application/json' -d'
{
"properties": {
"my_field": {
"type": "text",
"fielddata": true
}
}
}
'
映射中你应该包含 my_field 已经存在的映射部分,再加上
fielddata
参数。Tip:
fielddata.*
参数的设置必须该字段在该索引的全部其他设置。它的值可以通过 maping API 在已存在的字段上更新。
fielddata_frequency_filter
fielddata 过滤可以用来减少加载到内存中的词条数量,因而可以减少内存使用,词条可以按频率过滤:
频率过滤器允许你只加载那些文档词条频率落在min
和 max
之间的词条,它可以表示为绝对值(值大于 1.0)或者是百分比(比如 0.01 是 1%,1 是 100%)。词频是按段计算的。百分比是基于字段中有一个值的文档数,与段中所有文档的比值。
可以使用 min_segment_size
指定段中包含文档的最小数量,来排除一些小段:
curl -X PUT "localhost:9200/my_index?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"_doc": {
"properties": {
"tag": {
"type": "text",
"fielddata": true,
"fielddata_frequency_filter": {
"min": 0.001,
"max": 0.1,
"min_segment_size": 500
}
}
}
}
}
}
'
翻译于:https://www.elastic.co/guide/en/elasticsearch/reference/6.3/fielddata.html