RemoveRecordField Processor
描述
通过删除选定字段来修改包含面向记录数据的 FlowFile 的内容。
标签
使用场景
从记录中删除一个或多个字段,其中要删除的字段名称已知。
根据传入数据格式配置 Record Reader。
根据期望的输出格式配置 Record Writer。
对于你想移除的每个字段,向处理器添加一个新属性。
该属性的名称可以是任意内容,但建议使用对该字段的简短描述。
该属性的值是一个匹配要移除字段的 RecordPath。
例如,要移除 `name` 和 `email` 字段,添加两个属性:
`name` = `/name`
`email` = `/email`
属性
| 名称 | 默认值 | 可选值 | 描述 |
|---|---|---|---|
| Record Reader | | 控制器服务 API:RecordReaderFactorycn.org.acal.lynxus-lynxus-standard-services-api-nar-2.11.8 | 指定用于读取传入数据的 Controller Service |
| Record Writer | | 控制器服务 API:RecordSetWriterFactorycn.org.acal.lynxus-lynxus-standard-services-api-nar-2.11.8 | 指定用于写出记录的 Controller Service |
动态属性
| 名称 | 值 | 描述 |
|---|---|---|
| 要移除的字段的描述 | 指向要移除的字段的 RecordPath。 | 将删除匹配设置为值的 RecordPath 的任何字段。 |
关系 (Relationships)
| 名称 | 描述 | 自动终止 |
|---|---|---|
failure | 如果 FlowFile 无法从配置的输入格式转换为配置的输出格式,未更改的 FlowFile 将被路由到此关系 | 否 |
success | 成功转换的FlowFiles将被路由到此关系 | 否 |
写入的 FlowFile 属性
| 名称 | 描述 |
|---|---|
record.error.message | 此属性在失败时提供读取器或写入器遇到的错误消息。 |
状态管理
该组件不存储状态。
受限 (Restricted)
该组件不受限。
输入要求
该组件要求有传入连接。
另请参阅
详细说明
RemoveRecordField
RemoveRecordField Processor 用法示例
RemoveRecordField Processor 可以从 Lynxus 记录中移除字段。要移除的字段通过 RecordPath 表达式指定。要了解 RecordPath,请阅读 RecordPath 指南。
RemoveRecordField 会根据配置的待移除 RecordPath 更新 FlowFile 中的所有记录。 配置用于读取 FlowFile 内容的 Record Reader 所关联的 Schema 也会基于相同的 RecordPath 更新,并考虑移除后记录字段中剩余的值。如果 Record Writer 的 Schema Access Strategy 为 Inherit Record Schema,该更新后的 schema 可用于 输出;否则对 schema 的更新会丢失,输出记录将使用 Writer 上配置的 Schema。
下面是一些旨在说明如何使用该 Processor 的示例。在这些示例中,输入数据、 记录 schema、输出数据和输出 schema 都使用 JSON 格式以便于理解。我们假设 Processor 配置了 JsonTreeReader 和 JsonRecordSetWriter Controller Service, 当然,该 Processor 也可以与其他 Reader 和 Writer Controller Service 配合。 示例中还假设记录 schema 以 FlowFile Attribute(avro.schema Attribute)的形式 显式提供,Reader 使用该 schema 处理 FlowFile。Writer 的 Schema Access Strategy 为 "Inherit Record Schema",这样 Processor 对 schema 的所有修改 都会被 Writer 采纳。Writer 的 Schema Write Strategy 设为 "Set 'avro.schema' Attribute",以便输出 FlowFile 以 Attribute 值的形式包含 schema。
示例 1:
从简单记录中移除字段
输入数据:
{
"id": 1,
"name": "John Doe",
"dateOfBirth": "1980-01-01"
}
输入 schema:
{
"type": "record",
"name": "PersonRecord",
"namespace": "cn.org.acal.lynxus",
"fields": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": "string"
},
{
"name": "dateOfBirth",
"type": "string"
}
]
}
要移除的字段:
/dateOfBirth
在这种情况下,dateOfBirth 字段会从记录和 schema 中一并移除。
输出数据:
{
"id": 1,
"name": "John Doe"
}
输出 schema:
{
"type": "record",
"name": "PersonRecord",
"namespace": "cn.org.acal.lynxus",
"fields": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": "string"
}
]
}
注意,从记录中移除字段与把字段值设为 null 不同。使用 RemoveRecordField 时, 无论字段是否可为 null,字段都会从记录及其 schema 中被完全移除。
示例 2:
从复杂记录中移除字段
假设有一个输入记录,包含 homeAddress 和 mailingAddress 两个字段, 两者都含有 zip 字段,我们希望把这两个 zip 字段都移除。
输入数据:
{
"id": 1,
"name": "John Doe",
"homeAddress": {
"zip": 1111,
"street": "Main",
"number": 24
},
"mailingAddress": {
"zip": 1121,
"street": "Airport",
"number": 12
}
}
输入 schema:
{
"name": "PersonRecord",
"type": "record",
"namespace": "cn.org.acal.lynxus",
"fields": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": "string"
},
{
"name": "homeAddress",
"type": {
"name": "address",
"type": "record",
"fields": [
{
"name": "zip",
"type": "int"
},
{
"name": "street",
"type": "string"
},
{
"name": "number",
"type": "int"
}
]
}
},
{
"name": "mailingAddress",
"type": "address"
}
]
}
要把两个地址中的 zip 字段移除,可以把 Processor 的 "Field to remove 1" 属性设为 "/homeAddress/zip",再添加一个值为 "/mailingAddress/zip" 的动态属性。 也可以在 "Field To Remove 1" 中使用带通配符的 RecordPath 表达式(此时不需要 指定动态属性)。
要移除的字段:
/*/zip
两个地址中的 zip 字段都会被移除。
输出数据:
{
"id": 1,
"name": "John Doe",
"homeAddress": {
"street": "Main",
"number": 24
},
"mailingAddress": {
"street": "Airport",
"number": 12
}
}
zip 字段会从 homeAddress 和 mailingAddress 两个字段的 schema 中移除。 不过,如果只指定移除 "/homeAddress/zip",那么即使这两个地址原本共享同一个 schema,mailingAddress 的 schema 也会保持原样。
示例 3:
数组
假设有一个包含地址数组的输入记录。
输入数据:
{
"id": 1,
"name": "John Doe",
"addresses": [
{
"zip": 1111,
"street": "Main",
"number": 24
},
{
"zip": 1121,
"street": "Airport",
"number": 12
}
]
}
输入 schema:
{
"name": "PersonRecord",
"type": "record",
"namespace": "cn.org.acal.lynxus",
"fields": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": "string"
},
{
"name": "addresses",
"type": {
"type": "array",
"items": {
"name": "address",
"type": "record",
"fields": [
{
"name": "zip",
"type": "int"
},
{
"name": "street",
"type": "string"
},
{
"name": "number",
"type": "int"
}
]
}
}
}
]
}
- 情形 1:移除数组中的一个元素
要移除的字段:
/addresses[0]
输出数据:
{
"id": 1,
"name": "John Doe",
"addresses": [
{
"zip": 1121,
"street": "Airport",
"number": 12
}
]
}
输出 schema:
{
"type": "record",
"name": "lynxusRecord",
"namespace": "cn.org.acal.lynxus",
"fields": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": "string"
},
{
"name": "addresses",
"type": {
"type": "array",
"items": {
"type": "record",
"name": "addressesType",
"fields": [
{
"name": "zip",
"type": "int"
},
{
"name": "street",
"type": "string"
},
{
"name": "number",
"type": "int"
}
]
}
}
}
]
}
数组的第一个元素被移除。输出数据的 schema 在结构上与输入 schema 相同。 注意,输入 schema 的名称 "PersonRecord" 变成了 "lynxusRecord", "address" 变成了 "addressesType"。这是正常现象,Lynxus 会为输出 schema 生成这些名称。无论 schema 实际是否被修改,这些名称变化都会发生。
- 情形 2:移除数组中的所有元素
要移除的字段:
/addresses[*]
输出数据:
{
"id": 1,
"name": "John Doe",
"addresses": []
}
数组的所有元素都被移除,结果是一个空数组。输出 schema 与情形 1 相同, 没有结构性变化。
- 情形 3:移除数组中某些元素的某个字段
要移除的字段:
/addresses[0]/zip
输出数据:
{
"id": 1,
"name": "John Doe",
"addresses": [
{
"zip": null,
"street": "Main",
"number": 24
},
{
"zip": 1121,
"street": "Airport",
"number": 12
}
]
}
输出 schema 与情形 1 相同,没有结构性变化。数组第一个元素的 zip 字段 被设为 null,因为需要删除该值,但删除没有应用于数组的所有元素, 所以无法修改 schema。在这种情况下,无论字段是否可为 null, 字段的值都会被设为 null。
- 情形 4:移除数组中所有元素的某个字段
要移除的字段:
/addresses[*]/zip
输出数据:
{
"id": 1,
"name": "John Doe",
"addresses": [
{
"street": "Main",
"number": 24
},
{
"street": "Airport",
"number": 12
}
]
}
输出 schema:
{
"type": "record",
"name": "lynxusRecord",
"namespace": "cn.org.acal.lynxus",
"fields": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": "string"
},
{
"name": "addresses",
"type": {
"type": "array",
"items": {
"type": "record",
"name": "addressesType",
"fields": [
{
"name": "street",
"type": "string"
},
{
"name": "number",
"type": "int"
}
]
}
}
}
]
}
zip 字段从数组的所有元素中移除,且 schema 被修改,zip 字段从 数组的元素类型中移除。
情形 1、2、3、4 所示的示例对数组和 map 两种集合都适用。数组或 map 的 schema 只有在字段删除应用于集合的所有元素时才会被修改。可以用 [*] 或 [0..-1] 操作符来选择数组的所有元素。
重要说明: 例如,如果 addresses 数组有 3 个元素,移除 "/addresses[*]/zip" 时,zip 字段会从 schema 中移除,因为它显式地应用于所有元素,与数组中 的实际元素数量无关。但如果路径是 "/addresses[0,1,2]/zip",那么即使 [0,1,2] 在这个特定数组中恰好意味着所有元素,schema 也不会被修改, 因为它选择的是第一个、第二个和第三个元素本身,并没有表达"无论元素数量 多少都要对数组所有元素应用删除"的意图。
- 情形 5:移除数组中的多个元素
要移除的字段:
/addresses[0] /addresses[0]
本例中我们想移除数组的前两个元素。为此需要指定两个独立的路径表达式, 每个指向一个数组元素。每次删除都在前一次删除的结果上执行,删除按照 包含 record path 的属性在 Processor 上指定的顺序执行。 首先移除 "/addresses[0]",即示例中 zip 码为 1111 的地址。这次删除后, addresses 数组有了新的第一个元素,即原数组的第二个元素(zip 码为 1121 的地址)。要移除这个元素,需要再次执行 "/addresses[0]"。 当删除目标是多个不同的数组元素时,尝试移除 "/addresses[0,1]" 或用谓词过滤数组元素可能会产生意外结果。
- 情形 6:数组中的数组
假设有一个复杂输入记录,其中数组里嵌套了数组。
输入数据:
{
"id": 1,
"people": [
{
"id": 11,
"addresses": [
{
"zip": 1111,
"street": "Main",
"number": 24
},
{
"zip": 1121,
"street": "Airport",
"number": 12
}
]
},
{
"id": 22,
"addresses": [
{
"zip": 2222,
"street": "Ocean",
"number": 24
},
{
"zip": 2232,
"street": "Sunset",
"number": 12
}
]
},
{
"id": 33,
"addresses": [
{
"zip": 3333,
"street": "Dawn",
"number": 24
},
{
"zip": 3323,
"street": "Spring",
"number": 12
}
]
}
]
}
下表总结了使用不同 RecordPath 时,记录和 schema 会发生什么:
| 要移除的字段 | schema 是否被修改? | 记录会发生什么? |
|---|---|---|
| /people[0]/addresses[1]/zip | 否 | 第一个人的第二个地址的 zip 字段被设为 null。 |
| /people[*]/addresses[1]/zip | 否 | 所有人的第二个地址的 zip 字段被设为 null。 |
| /people[0]/addresses[*]/zip | 否 | 第一个人的每个地址的 zip 字段被设为 null。 |
| /people[*]/addresses[*]/zip | 是 | 每个人的每个地址的 zip 字段被移除(同时从 schema 和数据中移除)。 |
上述针对数组展示的规则和示例同样适用于 map。
示例 4:
CHOICE 数据类型
假设有一个输入 schema,其中包含 CHOICE 类型的字段。
输入数据:
{
"id": 12,
"name": "John Doe"
}
输入 schema:
{
"type": "record",
"name": "nameRecord",
"namespace": "cn.org.acal.lynxus",
"fields": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": [
"string",
{
"type": "record",
"name": "nameType",
"fields": [
{
"name": "firstName",
"type": "string"
},
{
"name": "lastName",
"type": "string"
}
]
}
]
}
]
}
本例中,schema 把 name 字段指定为 CHOICE,但数据里它是一个简单的字符串。 如果移除 "/name/firstName",数据不会有任何修改,但 schema 会被修改, firstName 字段只会从 schema 中被移除。