从ES7.3开始,引入了 Flattened 这种field类型。
Flattened 数据类型对于索引具有大量或未知数量的唯一键的对象很有用。仅为整个 JSON 对象创建一个字段映射,这可以帮助防止由于大量不同的字段映射而导致映射爆炸。
此外,Flattened 的对象字段在搜索功能方面存在折衷,例如不支持下面的3种查询:
在使用 flattened 数据类型时,必须注意的是:
flattened 的映射类型不应用于索引所有文档内容,因为它将所有值都视为关键字,并且不提供完整的搜索功能。 在大多数情况下,默认方法(每个子字段在映射中都有其自己相对应的项)有效。
下面内容来自官方文档的翻译。
默认情况下,对象中的每个子字段都是单独映射和索引的。如果事先不知道子字段的名称或类型,则会动态映射。
flattened
类型提供了一种替代方法,将整个对象映射为单个字段。给定一个对象, flattened
映射将解析其叶值并将它们作为关键词索引到一个字段中。然后可以通过简单查询和聚合搜索对象的内容。
这种数据类型对于索引具有大量或未知数量唯一键的对象很有用。整个 JSON 对象只创建一个字段映射,这有助于防止由于过多不同的字段映射而导致的映射爆炸。
另一方面,扁平化对象字段在搜索功能方面存在权衡。仅允许基本查询,不支持数值范围查询或高亮显示。有关限制的更多信息,请参阅“支持的操作”部分。
注意:
flattened
映射类型不应用于索引所有文档内容,因为它将所有值视为关键词,并且不提供全文搜索功能。默认方法,即每个子字段在映射中都有自己的条目,在大多数情况下效果良好。
PUT bug_reports
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"labels": {
"type": "flattened"
}
}
}
}
POST bug_reports/_doc/1
{
"title": "Results are not sorted correctly.",
"labels": {
"priority": "urgent",
"release": ["v1.2.5", "v1.3.0"],
"timestamp": {
"created": 1541458026,
"closed": 1541457010
}
}
}
GET bug_reports/_mapping
{
"bug_reports": {
"mappings": {
"properties": {
"labels": {
"type": "flattened"
},
"title": {
"type": "text"
}
}
}
}
}
在索引过程中,JSON 对象中的每个叶值都会创建标记。值被索引为字符串关键字,不进行分词或对数字或日期进行特殊处理。
查询顶层 flattened
字段会搜索对象中的所有叶值:
POST bug_reports/_search
{
"query": {
"term": {"labels": "urgent"}
}
}
要在扁平化对象中的特定键上查询,使用对象点表示法:
POST bug_reports/_search
{
"query": {
"term": {"labels.release": "v1.3.0"}
}
}
目前,扁平化对象字段可以与以下查询类型一起使用:
term, terms, and terms_set
prefix
range
match 和 multi_match
query_string 和 simple_query_string
exists
查询时无法使用通配符引用字段键,如 { "term": {"labels.time*": 1541457010}}
。请注意,所有查询(包括 range
)都将值视为字符串关键词。 flattened
字段不支持高亮显示。
可以在扁平化对象字段上排序,同时也可以执行简单的关键词式聚合,例如 terms
。与查询一样,没有对数值的特殊支持——JSON 对象中的所有值都按关键词处理。在排序时,这意味着值将按字典顺序进行比较。
TIPS: 扁平化对象字段目前无法存储。在映射中无法指定 store
参数。
字段值和具体子字段可以通过 fields 参数获取。由于 flattened
字段将整个对象(可能包含许多子字段)映射为单个字段,响应包含来自 _source
的未修改结构。
然而,单个子字段可以通过在请求中明确指定来获取。这仅适用于具体路径,但不能使用通配符:
PUT my-index-000001
{
"mappings": {
"properties": {
"flattened_field": {
"type": "flattened"
}
}
}
}
PUT my-index-000001/_doc/1?refresh=true
{
"flattened_field" : {
"subfield" : "value"
}
}
POST my-index-000001/_search
{
"fields": ["flattened_field.subfield"],
"_source": false
}
结果:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [{
"_index": "my-index-000001",
"_id": "1",
"_score": 1.0,
"fields": {
"flattened_field.subfield" : [ "value" ]
}
}]
}
}
你也可以使用 Painless 脚本从扁平化字段的子字段中检索值。在 Painless 脚本中,不要包含 doc['<field_name>'].value
,而是使用 doc['<field_name>.<sub-field_name>'].value
。例如,如果你有一个名为 label
的扁平化字段,其中包含一个 release
子字段,你的 Painless 脚本将是 doc['labels.release'].value
。
例如,假设你的映射包含两个字段,其中一个是 flattened
类型的:
PUT my-index-000001
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"labels": {
"type": "flattened"
}
}
}
}
索引包含你映射字段的几个文档。 labels
字段有三个子字段:
POST my-index-000001/_doc/1
{
"title": "Something really urgent",
"labels": {
"priority": "urgent",
"release": [
"v1.2.5",
"v1.3.0"
],
"timestamp": {
"created": 1541458026,
"closed": 1541457010
}
}
}
POST /my-index-000001/_doc/2
{
"title": "Somewhat less urgent",
"labels": {
"priority": "high",
"release": [
"v1.3.0"
],
"timestamp": {
"created": 1541458026,
"closed": 1541457010
}
}
}
POST /my-index-000001/_doc/3
{
"title": "Not urgent",
"labels": {
"priority": "low",
"release": [
"v1.2.0"
],
"timestamp": {
"created": 1541458026,
"closed": 1541457010
}
}
}
因为 labels
是一个 flattened
字段类型,整个对象被映射为单个字段。要在 Painless 脚本中从该子字段中检索值,请使用 doc['<field_name>.<sub-field_name>'].value
格式。
"script": {
"source": """
if (doc['labels.release'].value.equals('v1.3.0'))
{emit(doc['labels.release'].value)}
else{emit('Version mismatch')}
"""
官方文档: https://www.elastic.co/guide/en/elasticsearch/reference/8.18/flattened.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。