OpenSearch索引response字段兼容字符串与对象类型的可行性咨询
我有两个应用,一个返回的response字段值为字符串(如"somestring"),另一个返回的response字段值为对象(如{statusCode: 200})。我配置的索引映射如下:
response: dynamic: true properties: statusCode: type: integer
使用该映射时,出现如下错误:
#<Fluent::Plugin::OpenSearchErrorHandler::OpenSearchError: 400 - Rejected by OpenSearch [error type]: mapper_parsing_exception [reason]: 'object mapping for [response] tried to parse field [response] as object, but found a concrete value'>
请问是否可以实现让response字段接收任意值,且当值为包含statusCode的对象时正常索引?
解决方案
OpenSearch里字段类型一旦确定后就不能混合不同基础类型(比如对象和字符串),要实现兼容可以用以下几种方法:
方法1:用动态模板自动适配类型(推荐)
修改索引映射,通过dynamic_templates让response根据实际值的类型自动应用对应映射,既支持字符串也支持带statusCode的对象:
mappings: dynamic_templates: - response_string_handler: match: response match_mapping_type: string mapping: type: text fields: keyword: type: keyword ignore_above: 256 - response_object_handler: match: response match_mapping_type: object mapping: dynamic: true properties: statusCode: type: integer
当response是字符串时,会被映射为text+keyword类型;当是对象时,会使用你定义的statusCode整数映射,其他子字段动态生成。
方法2:用ignore_malformed临时兼容(不推荐)
如果只是临时需要兼容,不想调整结构,可以给response字段加上ignore_malformed: true,这样字符串类型的response不会触发报错,但代价是这些字符串不会被索引,只能存储,无法基于它们做查询:
response: dynamic: true ignore_malformed: true properties: statusCode: type: integer
方法3:拆分字段(长期最优)
如果业务允许,建议在数据写入OpenSearch前,用Fluentd过滤器把两种类型的response拆分到不同字段,这样映射更清晰,避免类型冲突:
# Fluentd过滤器配置示例 filter * { @type record_transformer enable_ruby true <record> response_str ${record['response'].is_a?(String) ? record['response'] : nil} response ${record['response'].is_a?(Hash) ? record['response'] : nil} </record> remove_keys response_str if response_str == nil remove_keys response if response == nil }
对应的OpenSearch映射可以分别定义:
response: dynamic: true properties: statusCode: type: integer response_str: type: text fields: keyword: type: keyword ignore_above: 256
内容的提问来源于stack exchange,提问作者Niyaz

