扁平化字段类型编辑

默认情况下,对象中的每个子字段都会被单独映射和索引。如果事先不知道子字段的名称或类型,则会动态映射它们。

flattened 类型提供了一种替代方法,将整个对象映射为单个字段。给定一个对象,flattened 映射将解析其叶子值并将它们索引到一个字段中作为关键字。然后可以通过简单的查询和聚合来搜索对象的內容。

此数据类型对于索引具有大量或未知数量的唯一键的对象很有用。只为整个 JSON 对象创建一个字段映射,这有助于防止映射爆炸,因为有太多不同的字段映射。

另一方面,扁平化对象字段在搜索功能方面存在权衡。只允许基本查询,不支持数值范围查询或高亮显示。有关限制的更多信息,请参阅支持的操作部分。

flattened 映射类型不应用于索引所有文档内容,因为它将所有值视为关键字,并且不提供完整的搜索功能。在大多数情况下,默认方法(每个子字段在映射中都有自己的条目)效果很好。

可以按如下方式创建扁平化对象字段

response = client.indices.create(
  index: 'bug_reports',
  body: {
    mappings: {
      properties: {
        title: {
          type: 'text'
        },
        labels: {
          type: 'flattened'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'bug_reports',
  id: 1,
  body: {
    title: 'Results are not sorted correctly.',
    labels: {
      priority: 'urgent',
      release: [
        'v1.2.5',
        'v1.3.0'
      ],
      timestamp: {
        created: 1_541_458_026,
        closed: 1_541_457_010
      }
    }
  }
)
puts response
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
    }
  }
}

在索引期间,将为 JSON 对象中的每个叶子值创建令牌。这些值将被索引为字符串关键字,不会进行分析,也不会对数字或日期进行特殊处理。

查询顶层 flattened 字段将搜索对象中的所有叶子值

response = client.search(
  index: 'bug_reports',
  body: {
    query: {
      term: {
        labels: 'urgent'
      }
    }
  }
)
puts response
POST bug_reports/_search
{
  "query": {
    "term": {"labels": "urgent"}
  }
}

要查询扁平化对象中的特定键,请使用对象点表示法

response = client.search(
  index: 'bug_reports',
  body: {
    query: {
      term: {
        'labels.release' => 'v1.3.0'
      }
    }
  }
)
puts response
POST bug_reports/_search
{
  "query": {
    "term": {"labels.release": "v1.3.0"}
  }
}

支持的操作编辑

由于值索引方式的相似性,flattened 字段与keyword 字段共享许多相同的映射和搜索功能。

目前,扁平化对象字段可与以下查询类型一起使用

  • termtermsterms_set
  • 前缀
  • 范围
  • matchmulti_match
  • query_stringsimple_query_string
  • 存在

在查询时,无法使用通配符引用字段键,例如 { "term": {"labels.time*": 1541457010}}。请注意,所有查询(包括 range)都将值视为字符串关键字。不支持在 flattened 字段上进行高亮显示。

可以对扁平化对象字段进行排序,还可以执行简单的关键字样式聚合,例如 terms。与查询一样,没有对数字的特殊支持——JSON 对象中的所有值都被视为关键字。在排序时,这意味着值按字典顺序进行比较。

扁平化对象字段目前无法存储。无法在映射中指定store 参数。

检索扁平化字段编辑

可以使用fields 参数检索字段值和具体子字段。内容。由于 flattened 字段将可能包含许多子字段的整个对象映射为单个字段,因此响应包含来自 _source 的未更改结构。

但是,可以通过在请求中明确指定子字段来获取单个子字段。这仅适用于具体路径,而不适用于通配符

response = client.indices.create(
  index: 'my-index-000001',
  body: {
    mappings: {
      properties: {
        flattened_field: {
          type: 'flattened'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'my-index-000001',
  id: 1,
  refresh: true,
  body: {
    flattened_field: {
      subfield: 'value'
    }
  }
)
puts response

response = client.search(
  index: 'my-index-000001',
  body: {
    fields: [
      'flattened_field.subfield'
    ],
    _source: false
  }
)
puts response
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 类型

response = client.indices.create(
  index: 'my-index-000001',
  body: {
    mappings: {
      properties: {
        title: {
          type: 'text'
        },
        labels: {
          type: 'flattened'
        }
      }
    }
  }
)
puts response
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "labels": {
        "type": "flattened"
      }
    }
  }
}

索引一些包含已映射字段的文档。 labels 字段有三个子字段

response = client.bulk(
  index: 'my-index-000001',
  refresh: true,
  body: [
    {
      index: {}
    },
    {
      title: 'Something really urgent',
      labels: {
        priority: 'urgent',
        release: [
          'v1.2.5',
          'v1.3.0'
        ],
        timestamp: {
          created: 1_541_458_026,
          closed: 1_541_457_010
        }
      }
    },
    {
      index: {}
    },
    {
      title: 'Somewhat less urgent',
      labels: {
        priority: 'high',
        release: [
          'v1.3.0'
        ],
        timestamp: {
          created: 1_541_458_026,
          closed: 1_541_457_010
        }
      }
    },
    {
      index: {}
    },
    {
      title: 'Not urgent',
      labels: {
        priority: 'low',
        release: [
          'v1.2.0'
        ],
        timestamp: {
          created: 1_541_458_026,
          closed: 1_541_457_010
        }
      }
    }
  ]
)
puts response
POST /my-index-000001/_bulk?refresh
{"index":{}}
{"title":"Something really urgent","labels":{"priority":"urgent","release":["v1.2.5","v1.3.0"],"timestamp":{"created":1541458026,"closed":1541457010}}}
{"index":{}}
{"title":"Somewhat less urgent","labels":{"priority":"high","release":["v1.3.0"],"timestamp":{"created":1541458026,"closed":1541457010}}}
{"index":{}}
{"title":"Not urgent","labels":{"priority":"low","release":["v1.2.0"],"timestamp":{"created":1541458026,"closed":1541457010}}}

因为 labelsflattened 字段类型,所以整个对象被映射为单个字段。要在 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')}
  """

扁平化对象字段的参数编辑

接受以下映射参数

depth_limit

扁平化对象字段允许的最大深度,以嵌套的内部对象数表示。如果扁平化对象字段超过此限制,则会抛出错误。默认为 20。请注意,可以通过更新映射 API 动态更新 depth_limit

doc_values

字段是否应以列跨度方式存储在磁盘上,以便以后用于排序、聚合或脚本?接受 true(默认值)或 false

eager_global_ordinals

是否应在刷新时急切地加载全局序数?接受 truefalse(默认值)。对于经常用于术语聚合的字段,启用此选项是一个好主意。

ignore_above

超过此限制的叶子值将不会被索引。默认情况下,没有限制,所有值都将被索引。请注意,此限制适用于扁平化对象字段内的叶子值,而不是整个字段的长度。

index

确定字段是否应可搜索。接受 true(默认值)或 false

index_options

应在索引中存储哪些信息以用于评分目的。默认为 docs,但也可以设置为 freqs 以在计算分数时考虑词频。

null_value

一个字符串值,用于替换扁平化对象字段内的任何显式 null 值。默认为 null,这意味着空字段将被视为缺失。

similarity

应使用哪种评分算法或相似度。默认为 BM25

split_queries_on_whitespace

是否应在为该字段构建查询时,在空格处拆分全文查询 的输入。接受 truefalse(默认值)。

time_series_dimensions

(可选,字符串数组) 扁平化对象内的字段列表,其中每个字段都是时间序列的维度。每个字段都使用从根字段开始的相对路径指定,不包括根字段名称。

合成 _source编辑

合成 _source 仅对 TSDB 索引(将 index.mode 设置为 time_series 的索引)普遍可用。对于其他索引,合成 _source 处于技术预览阶段。技术预览中的功能可能会在将来的版本中更改或删除。Elastic 将努力解决任何问题,但技术预览中的功能不受官方 GA 功能支持 SLA 的约束。

扁平化字段在默认配置中支持合成`_source`。合成 _source 不能与doc_values 禁用一起使用。

合成源始终按字母顺序排序并对扁平化字段进行重复数据删除。例如

response = client.indices.create(
  index: 'idx',
  body: {
    mappings: {
      _source: {
        mode: 'synthetic'
      },
      properties: {
        flattened: {
          type: 'flattened'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'idx',
  id: 1,
  body: {
    flattened: {
      field: [
        'apple',
        'apple',
        'banana',
        'avocado',
        '10',
        '200',
        'AVOCADO',
        'Banana',
        'Tangerine'
      ]
    }
  }
)
puts response
PUT idx
{
  "mappings": {
    "_source": { "mode": "synthetic" },
    "properties": {
      "flattened": { "type": "flattened" }
    }
  }
}
PUT idx/_doc/1
{
  "flattened": {
    "field": [ "apple", "apple", "banana", "avocado", "10", "200", "AVOCADO", "Banana", "Tangerine" ]
  }
}

将变为

{
  "flattened": {
    "field": [ "10", "200", "AVOCADO", "Banana", "Tangerine", "apple", "avocado", "banana" ]
  }
}

合成源始终使用嵌套对象而不是对象数组。例如

response = client.indices.create(
  index: 'idx',
  body: {
    mappings: {
      _source: {
        mode: 'synthetic'
      },
      properties: {
        flattened: {
          type: 'flattened'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'idx',
  id: 1,
  body: {
    flattened: {
      field: [
        {
          id: 1,
          name: 'foo'
        },
        {
          id: 2,
          name: 'bar'
        },
        {
          id: 3,
          name: 'baz'
        }
      ]
    }
  }
)
puts response
PUT idx
{
  "mappings": {
    "_source": { "mode": "synthetic" },
    "properties": {
      "flattened": { "type": "flattened" }
    }
  }
}
PUT idx/_doc/1
{
  "flattened": {
      "field": [
        { "id": 1, "name": "foo" },
        { "id": 2, "name": "bar" },
        { "id": 3, "name": "baz" }
      ]
  }
}

将变为(请注意嵌套对象而不是“扁平化”数组)

{
    "flattened": {
      "field": {
          "id": [ "1", "2", "3" ],
          "name": [ "bar", "baz", "foo" ]
      }
    }
}

合成源始终对单元素数组使用单值字段。例如

response = client.indices.create(
  index: 'idx',
  body: {
    mappings: {
      _source: {
        mode: 'synthetic'
      },
      properties: {
        flattened: {
          type: 'flattened'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'idx',
  id: 1,
  body: {
    flattened: {
      field: [
        'foo'
      ]
    }
  }
)
puts response
PUT idx
{
  "mappings": {
    "_source": { "mode": "synthetic" },
    "properties": {
      "flattened": { "type": "flattened" }
    }
  }
}
PUT idx/_doc/1
{
  "flattened": {
    "field": [ "foo" ]
  }
}

将变为(请注意嵌套对象而不是“扁平化”数组)

{
  "flattened": {
    "field": "foo"
  }
}