如何在FlowFile的内容中将FlowFile属性写入Avro元数据?

时间:2018-01-29 20:42:10

标签: avro apache-nifi

我创建的FlowFiles在被ExecuteSql处理器发出后被操纵并向下游拆分。我填写了FlowFiles'具有我想要放入每个FlowFile内容中包含的Avro元数据的数据的属性。

我该怎么做?

我尝试使用配置了UpdateRecordAvroReader的{​​{1}}处理器以及应该编写FlowFile属性的密钥为AvroRecordSetWriter的属性到Avro文档中的那个键 somewhere 。但是,它不会出现在输出中的任何位置。

将Avro数据中的记录移动到子项并将元数据部分作为记录数据的一部分是可以接受的。不过,我宁愿不这样做,因为它似乎不是正确的解决方案,因为它听起来比简单地修改Avro元数据要复杂得多。

1 个答案:

答案 0 :(得分:4)

记录感知处理器(以及读取器/写入器)不支持元数据,这意味着它们当前不能(从NiFi 1.5.0开始)以任何方式对元数据进行操作(检查,创建,删除等),所以UpdateRecord本身不支持元数据。使用/ canary属性键,它将尝试在顶级的Avro记录中插入一个名为canary的字段,并且应该具有您指定的值。但是我相信你的输出模式需要在顶层添加canary字段,否则它可能会被忽略(我不是肯定的,你可以检查输出模式以查看它是否自动添加)。 / p>

目前还没有可以明确更新Avro元数据的NiFi处理器(MergeContent在将各种Avro文件合并在一起时做了一些,但是你不能选择设置一个值,例如)。但是我有一个未经抛光的Groovy脚本,你可以在ExecuteScript中使用它来为NiFi 1.5.0+中的Avro文件添加元数据。在ExecuteScript中,您将语言设置为Groovy,将以下内容设置为Script Body,然后将用户定义的(又称"动态"属性)添加到ExecuteScript,其中键将是元数据键,并且评估值(属性支持表达式语言)将是值:

@Grab('org.apache.avro:avro:1.8.1')
import org.apache.avro.*
import org.apache.avro.file.*
import org.apache.avro.generic.*

def flowFile = session.get()
if(!flowFile) return

try {
// Save off dynamic property values for metadata key/values later
def metadata = [:]
context.properties.findAll {e -> e.key.dynamic}.each {k,v -> metadata.put(k.name, context.getProperty(k).evaluateAttributeExpressions(flowFile).value.bytes)}

flowFile = session.write(flowFile, {inStream, outStream ->
   DataFileStream<GenericRecord> reader = new DataFileStream<>(inStream, new GenericDatumReader<GenericRecord>())
   DataFileWriter<GenericRecord> writer = new DataFileWriter<>(new GenericDatumWriter<GenericRecord>())
   def schema = reader.schema
   def inputCodec = reader.getMetaString(DataFileConstants.CODEC) ?: DataFileConstants.NULL_CODEC
   // Forward the existing metadata to the output
   reader.metaKeys.each { key ->
      if (!DataFileWriter.isReservedMeta(key)) {
         byte[] metadatum = reader.getMeta(key)
         writer.setMeta(key, metadatum)
      }
   }
   // For each dynamic property, set the key/value pair as Avro metadata
   metadata.each {k,v -> writer.setMeta(k,v)}
   writer.setCodec(CodecFactory.fromString(inputCodec))
   writer.create(schema, outStream)
   writer.appendAllFrom(reader, false)
} as StreamCallback)

session.transfer(flowFile, REL_SUCCESS)
} catch(e) {
   log.error('Error adding Avro metadata, penalizing flow file and routing to failure', e)
   flowFile = session.penalize(flowFile)
   session.transfer(flowFile, REL_FAILURE)
} 

请注意,此脚本可以使用1.5.0之前的NiFi版本,但1.5.0之前不支持顶部的@Grab,因此您必须将Avro及其依赖项下载到平面中文件夹,并指向ExecuteScript的“模块目录”属性中的文件。