Elasticsearch 7.3.1同一字段是否支持存储字符串与对象两类数据
问题结论
Elasticsearch 7.3.1 中不支持同一个字段在映射固定类型后,直接混存字符串、对象两种不同类型的数据。
ES的映射规则要求同名字段必须对应唯一的字段类型,如果你第一次写入数据时value字段传了字符串,ES会自动将该字段类型识别为text(附带keyword子字段),后续再写入对象/对象数组类型的value时,会直接抛出类型映射不匹配的错误,写入失败。
可行实现方案
根据是否需要对value字段内的内容做检索、聚合操作,可选以下两种方案:
方案1:不需要索引value内容,仅需存储原始值
如果不需要针对value里的字符串、对象属性做搜索、聚合、排序,只要求写入后查询时能返回完整原始内容,可以将value字段设为关闭索引的object类型,此时该字段可以接收任意类型的合法JSON值。
注意示例中的Data字段是对象数组,建议设为nested类型,避免数组内对象被ES扁平化后出现跨对象匹配的问题。
对应映射示例:
PUT 你的索引名 { "mappings": { "properties": { "Data": { "type": "nested", "properties": { "key": { "type": "keyword" }, "value": { "type": "object", "enabled": false } } } } } }
该映射可以直接兼容给出的示例数据写入,不需要调整原有数据结构。
方案2:需要索引value内容,支持检索
如果需要同时支持搜索value里的字符串值、以及对象内的type/message/path属性,需要统一字段结构,不要让value直接承载不同类型的值,而是给value加固定子字段区分存储类型:
- 字符串值统一存在
value.str_value子字段 - 对象/对象数组统一存在
value.obj_value子字段(该子字段设为nested类型避免数组扁平化问题)
对应映射示例:
PUT 你的索引名 { "mappings": { "properties": { "Data": { "type": "nested", "properties": { "key": { "type": "keyword" }, "value": { "type": "object", "properties": { "str_value": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "obj_value": { "type": "nested", "properties": { "type": { "type": "keyword" }, "message": { "type": "text" }, "path": { "type": "keyword" } } } } } } } } } }
写入数据时需要把原数据结构做对应调整,调整后的示例数据:
{ "Data": [ { "key": "keyName", "value": {"str_value": "valueName"} }, { "key": "keyName", "value": {"str_value": "valueName"} }, { "key": "keyName", "value": { "obj_value": [ { "type": "FailedName", "message": "FailedMessage", "path": "FailedPath" } ] } } ] }
注意事项
不要依赖ES的动态映射自动识别类型,动态映射下第一次写入的数据类型会直接锁死字段类型,后续写入不同类型数据会直接报错,需要提前按照业务需求定义好映射再写入数据。
内容的提问来源于stack exchange,提问作者Elie Jamous
相关产品推荐
相关产品推荐

