Nifi组件脚本开发—ExecuteScript 使用指南(二)
Part 2 - FlowFile I/O 和 Error Handling
flow File的IO
NiFi 的 Flow files 由两个主要部件组成:attributes 和 content. Attributes 是关于 content / flow file的元数据, 我们在Nifi组件脚本开发—ExecuteScript 使用指南(一)看到了如何使用 ExecuteScript 来操纵这个属性. flow file 的内容, 核心是一个 bytes集合,没有继承的 structure, schema, format, 等等. 不同的 NiFi processors 假定输入的 flow files 具有特定的 schema/format (或者从 attributes确定如 "mime.type" 或者通过其他的方法). 这些 processors 然后按照假定的格式对内容进行处理 (将返回 "failure" 到relationship,如果不是的话). 经常 processors 将输出 flow files 以特定的格式, 这在 processors' 描述中有相应的说明.
flow files 的 Input 和 Output (I/O) 通过 ProcessSession API 提供,通过 ExecuteScript 的"session" 变量来访问。一个机制是传递一个 callback 对象到session.read() 或 session.write()的调用。对于FlowFile将创建一个 InputStream 和/或 OutputStream, 这个callback 对象将被激活,使用相应的 callback 接口, 然后这个InputStream 和/或 OutputStream 的引用被传递到 callback函数使用. 这里有三个 callback 接口, 每一个有自己的应用环境:
InputStreamCallback
这个 interface 用在 session.read( flowFile, inputStreamCallback) 方法中,提供一个 InputStream,用于读取 flow file的内容. 该 interface 有一个单一方法:
void process(InputStream in) throws IOException
该 interface 提供一个被管理的 input stream. 这个input stream自动打开和关闭,也可以手动关闭. 这是从 flow file读取的方法, 并且不能被写回去。
OutputStreamCallback
该 interface 被用于session.write( flowFile, outputStreamCallback) 方法,提供 OutputStream写入内容到 flow file. 该 interface 具有单一的方法:
void process(OutputStream out) throws IOException
该 interface 提供被管理的 output stream. 这个output stream 被自动打开和关闭,也可以手动关闭。 - 重要的一点是,如果任何 streams 包装了这个 streams,所有打开的资源应该被清理.
例如, 在ExecuteScript中被创建数据 , 来自于外部文件, 而不是一个 flow file. 然后你可以使用 session.create() 去创建一个新的FlowFile, 然后 session.write( flowFile, outputStreamCallback) 用于添加内容.
StreamCallback
该 interface 用于 session.write( flowFile, streamCallback) 方法,提供 InputStream 和 OutputStream,为 flow file提供内容的读取和写入. 该 interface 有一个单一的方法:
void process(InputStream in, OutputStream out) throws IOException
该 interface 提供被管理的 output stream. 这个output stream 被自动打开和关闭,也可以手动关闭。 - 重要的一点是,如果任何 streams 包装了这个 streams,所有打开的资源应该被清理.
因为这些 callbacks 是 Java objects, 脚本将创建一个并且传入 session 方法, 下面的方法将使用不同的脚本语言进行演示. 并且,这里还有其他的读写 flow files方法, 包括:
- 使用 session.read(flowFile) 返回 InputStream. 取代 InputStreamCallback, 将返回 InputStream 用于读取. 你必须 (close, e.g.) 手动管理 InputStream.
- 使用 session.importFrom(inputStream, flowFile) 从 InputStream 写入到 FlowFile. 这将替代 借助OutputStreamCallback的session.write() 的使用.
从 flow file 中读取数据
需求:传入连接执行 ExecuteScript ,并且从队列中得到 flow file 的内容进行处理.
方法:使用session的read(flowFile, inputStreamCallback) 方法。一个 InputStreamCallback 对象需要被传入 read() 方法. 注意到,因为InputStreamCallback 是一个对象, 内容只在该对象中可见。 如果你需要在 read() 方法之外访问, 需要使用更为全局化的变量. 这里的例子讲来自flow file的全部内容存储到 String (使用 Apache Commons' IOUtils class)。
注意: 对于大的 flow files, 这并不是最好的技术方法; 应该只读取需要的数据,并按照适应的方法处理。比如 SplitText, 你应该一次读一行并且在 InputStreamCallback中处理, 或者 session.read(flowFile) 方法 得到 InputStream 的引用,从而在 callback之外处理.
例子:
Groovy:
import org.apache.commons.io.IOUtils
import java.nio.charset.StandardCharsets flowFile = session.get() if(!flowFile)return def text = ''
// Cast a closure with an inputStream parameter to InputStreamCallback
session.read(flowFile, {inputStream ->
text = IOUtils.toString(inputStream, StandardCharsets.UTF_8) // Do something with text here
} as InputStreamCallback)
Jython:
from org.apache.commons.io import IOUtils
from java.nio.charset import StandardCharsets
from org.apache.nifi.processor.io import InputStreamCallback # Define a subclass of InputStreamCallback for use in session.read()
class PyInputStreamCallback(InputStreamCallback):
def __init__(self):
pass
def process(self, inputStream):
text = IOUtils.toString(inputStream, StandardCharsets.UTF_8) # Do something with text here
# end class flowFile = session.get()
if(flowFile != None):
session.read(flowFile, PyInputStreamCallback())
# implicit return at the end
Javascript:
var InputStreamCallback = Java.type("org.apache.nifi.processor.io.InputStreamCallback")
var IOUtils = Java.type("org.apache.commons.io.IOUtils")
var StandardCharsets = Java.type("java.nio.charset.StandardCharsets") var flowFile = session.get(); if(flowFile != null) {
// Create a new InputStreamCallback, passing in a function to define the interface method
session.read(flowFile,new InputStreamCallback(function(inputStream) {
var text = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
// Do something with text here
}));
}
JRuby:
java_import org.apache.commons.io.IOUtils
java_import org.apache.nifi.processor.io.InputStreamCallback # Define a subclass of InputStreamCallback for use in session.read()
class JRubyInputStreamCallback
include InputStreamCallback def process(inputStream)
text = IOUtils.toString(inputStream)
# Do something with text here
end
end jrubyInputStreamCallback = JRubyInputStreamCallback.new
flowFile = session.get()
if flowFile != nil
session.read(flowFile, jrubyInputStreamCallback)
end
写入数据至 flow file
需求:为输出的 flow file创建内容.
方法:使用session的write(flowFile, outputStreamCallback) 方法。一个OutputStreamCallback 对象需要传递给 write() 方法. 注意,因为 OutputStreamCallback 是一个对象, 因此内容之灾对象内部可见. 如果你需要在 write() 方法之外访问, 使用更为全局化变量. 西面的例子写入 String 到 flowFile。
例子:
Groovy:
import org.apache.commons.io.IOUtils
import java.nio.charset.StandardCharsets flowFile = session.get()
if(!flowFile) return def text = 'Hello world!'
// Cast a closure with an outputStream parameter to OutputStreamCallback
flowFile = session.write(flowFile, {outputStream ->
outputStream.write(text.getBytes(StandardCharsets.UTF_8))
} as OutputStreamCallback)
Jython:
from org.apache.commons.io import IOUtils
from java.nio.charset import StandardCharsets
from org.apache.nifi.processor.io import OutputStreamCallback # Define a subclass of OutputStreamCallback for use in session.write()
class PyOutputStreamCallback(OutputStreamCallback):
def __init__(self):
pass def process(self, outputStream):
outputStream.write(bytearray('Hello World!'.encode('utf-8')))
# end class flowFile = session.get() if(flowFile != None):
flowFile = session.write(flowFile, PyOutputStreamCallback())
# implicit return at the end
Javascript:
var OutputStreamCallback = Java.type("org.apache.nifi.processor.io.OutputStreamCallback");
var IOUtils = Java.type("org.apache.commons.io.IOUtils");
var StandardCharsets = Java.type("java.nio.charset.StandardCharsets");
var flowFile = session.get(); if(flowFile != null) {
// Create a new OutputStreamCallback, passing in a function to define the interface method
flowFile = session.write(flowFile,new OutputStreamCallback(function(outputStream) {
outputStream.write("Hello World!".getBytes(StandardCharsets.UTF_8))
}));
}
JRuby:
java_import org.apache.commons.io.IOUtils
java_import java.nio.charset.StandardCharsets
java_import org.apache.nifi.processor.io.OutputStreamCallback # Define a subclass of OutputStreamCallback for use in session.write()
class JRubyOutputStreamCallback
include OutputStreamCallback def process(outputStream)
outputStream.write("Hello World!".to_java.getBytes(StandardCharsets::UTF_8))
end
end jrubyOutputStreamCallback = JRubyOutputStreamCallback.new
flowFile = session.get()
if flowFile != nil
flowFile = session.write(flowFile, jrubyOutputStreamCallback)
end
覆盖 flow file内容
需求:重用输入 flow file但是希望修改内容并传递到输出的 flow file.
方法:使用session的write(flowFile, streamCallback) 方法。一个StreamCallback 对象需要传递给 write() 方法. StreamCallback 同时提供了InputStream (从输入的 flow file) 和 outputStream (下一版本的 flow file), 因此你可以使用InputStream去取得 flow file的当前内容, 然后修改他们并且写会到 flow file. 这将覆盖 flow file 的内容, 因此对于追加内容要采用读入内容添加的方式, 或者使用不同的方法 (使用 session.append() 而不是session.write() )。
注意,因为 StreamCallback 是一个对象, 因此内容之灾对象内部可见. 如果你需要在 write() 方法之外访问, 使用更为全局化变量.
以下这个例子将反转输入flowFile (假定为 String) 的内容,并将反转后的字符串写入到新版的 flowFile.
例子:
Groovy:
import org.apache.commons.io.IOUtils
import java.nio.charset.StandardCharsets flowFile = session.get()
if(!flowFile) return def text = 'Hello world!'
// Cast a closure with an inputStream and outputStream parameter to StreamCallback flowFile = session.write(flowFile, {inputStream, outputStream ->
text = IOUtils.toString(inputStream, StandardCharsets.UTF_8)
outputStream.write(text.reverse().getBytes(StandardCharsets.UTF_8))
} as StreamCallback) session.transfer(flowFile, REL_SUCCESS)
Jython:
from org.apache.commons.io import IOUtils
from java.nio.charset import StandardCharsets
from org.apache.nifi.processor.io import StreamCallback # Define a subclass of StreamCallback for use in session.write()
class PyStreamCallback(StreamCallback):
def __init__(self):
pass def process(self, inputStream, outputStream):
text = IOUtils.toString(inputStream, StandardCharsets.UTF_8)
outputStream.write(bytearray('Hello World!'[::-1].encode('utf-8')))
# end class flowFile = session.get() if(flowFile != None):
flowFile = session.write(flowFile, PyStreamCallback()) # implicit return at the end
Javascript:
var StreamCallback = Java.type("org.apache.nifi.processor.io.StreamCallback");
var IOUtils = Java.type("org.apache.commons.io.IOUtils");
var StandardCharsets = Java.type("java.nio.charset.StandardCharsets");
var flowFile = session.get(); if(flowFile != null) {
// Create a new StreamCallback, passing in a function to define the interface method
flowFile = session.write(flowFile,new StreamCallback(function(inputStream, outputStream) {
var text = IOUtils.toString(inputStream, StandardCharsets.UTF_8)
outputStream.write(text.split("").reverse().join("").getBytes(StandardCharsets.UTF_8))
}));
}
JRuby:
java_import org.apache.commons.io.IOUtils
java_import java.nio.charset.StandardCharsets
java_import org.apache.nifi.processor.io.StreamCallback # Define a subclass of StreamCallback for use in session.write() class JRubyStreamCallback
include StreamCallback
def process(inputStream, outputStream)
text = IOUtils.toString(inputStream)
outputStream.write((text.reverse!).to_java.getBytes(StandardCharsets::UTF_8))
end
end jrubyStreamCallback = JRubyStreamCallback.new
flowFile = session.get()
if flowFile != nil
flowFile = session.write(flowFile, jrubyStreamCallback)
end
处理错误
需求:在 script ( data validation 或者出现一个 exception)运行时出现错误, 处理和抛出错误。
方法:对于exceptions, 使用脚本语言的exception-handling 机制 (一般是try/catch 代码块). 对于 data validation, 可以使用类似的方法, 但是定义一个boolean 变量,如 "valid" 以及 if/else 语句,而不是try/catch 语句. ExecuteScript 定义了 "success" and "failure" relationships; 一般情况下,你的处理将转移 "good" flow files 到 success,而 "bad" flow files 到 failure (记录错误在后续的操作中)。
例子:
Groovy:
flowFile = session.get() if(!flowFile) return
try {
// Something that might throw an exception here
// Last operation is transfer to success (failures handled in the catch block)
session.transfer(flowFile, REL_SUCCESS)
} catch(e) {
log.error('Something went wrong', e)
session.transfer(flowFile, REL_FAILURE)
}
Jython:
flowFile = session.get() if(flowFile != None):
try:
# Something that might throw an exception here
# Last operation is transfer to success (failures handled in the catch block)
session.transfer(flowFile, REL_SUCCESS)
except:
log.error('Something went wrong', e)
session.transfer(flowFile, REL_FAILURE) # implicit return at the end
Javascript:
var flowFile = session.get();
if(flowFile != null) {
try {
// Something that might throw an exception here
// Last operation is transfer to success (failures handled in the catch block)
session.transfer(flowFile, REL_SUCCESS)
} catch(e) {
log.error('Something went wrong', e)
session.transfer(flowFile, REL_FAILURE)
}
}
JRuby:
flowFile = session.get() if flowFile != nil
begin
# Something that might raise an exception here
# Last operation is transfer to success (failures handled in the rescue block)
session.transfer(flowFile, REL_SUCCESS)
rescue Exception => e
log.error('Something went wrong', e)
session.transfer(flowFile, REL_FAILURE)
end
end
上一篇:Nifi组件脚本开发—ExecuteScript 使用指南(一)
源:https://www.shangmayuan.com/a/0ba9c44310b04d1dad461790.html
Nifi组件脚本开发—ExecuteScript 使用指南(二)的更多相关文章
- Nifi组件脚本开发—ExecuteScript 使用指南(三)
上一篇:Nifi组件脚本开发-ExecuteScript 使用指南(二) Part 3 - 高级特征 本系列的前两篇文章涵盖了 flow file 的基本操作, 如读写属性和内容, 以及使用" ...
- Nifi组件脚本开发—ExecuteScript 使用指南(一)
Part 1 - 介绍 NiFi API 和 FlowFiles ExecuteScript 是一个万能的处理器,允许用户使用编程语言定义自己的数据处理功能, 在每一次 ExecuteScript p ...
- Delphi 组件渐进开发浅谈(二)——双简合璧
2.双简合璧2.1.带有T[x]Label的T[x]Edit组件 请允许我用[x]的书写方式来表示不同的对象.因为随后将大量提及TLabeledEdit与TTntLabeledEdit.TCustom ...
- 【NIFI】 Apache NiFI 之 ExecuteScript处理(二)
本例介绍NiFI ExecuteScript处理器的使用,使用的脚本引擎ECMScript 接上一篇[NIFI] Apache NiFI 之 ExecuteScript处理(一) ExecuteScr ...
- JAVA+PHP+阿里云组件纯手工实现POP、SMTP、IMAP开发邮件服务器(二)
java开发邮件服务器的接收模块 用java建立socket服务端,监听端口25,实现SMTP协议.即可完成邮件服务器的接收模块. 这里要注意的是,SMTP协议其实可以分为两种.一种是你用手机.PC等 ...
- Jmeter+Ant+Jenkins接口自动化测试(二)_测试方案设计及jmeter脚本开发
前言 根据之前部署好的测试环境,进行接口自动化测试的方案设计及Jmeter脚本开发.测试方案设计过程中采用了数据分离和对象分离等思路,因此直接通过特定的测试用例文档来驱动整个自动化接口测试的执行,相关 ...
- App架构师实践指南二之App开发工具
App架构师实践指南二之App开发工具 1.Android Studio 2.编译调试---条件断点.右键单击断点,在弹出的窗口中输入Condition条件.---日志断点.右键单击断点,在弹 ...
- 【JMeter4.0学习(二)】之搭建openLDAP在windows8.1上的安装配置以及JMeter对LDAP服务器的性能测试脚本开发
目录: 概述 安装测试环境 安装过程 配置启动 配置搭建OpenLDAP 给数据库添加数据 测试查询刚刚插入的数据 客户端介绍 JMeter建立一个扩展LDAP服务器的性能测试脚本开发 附:LDAP学 ...
- Vue学习笔记-Vue.js-2.X 学习(二)===>组件化开发
===重点重点开始 ========================== (三) 组件化开发 1.创建组件构造器: Vue.extends() 2.注册组件: Vue.component() 3.使用 ...
随机推荐
- JVM调优之垃圾定位、垃圾回收算法、垃圾处理器对比
谈垃圾回收器之前,要先讲讲垃圾回收算法,以及JVM对垃圾的认定策略,JVM垃圾回收器是垃圾回收算法的具体实现,了解了前面的前置知识,有利于对垃圾回收器的理解. 什么是垃圾? 垃圾,主要是指堆上的对象, ...
- jackson学习之七:常用Field注解
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 【LAMP】搭建Web网站过程中的记录【Ubuntu18.04+Apache2.4+PHP7.2+MySQL5.7】
全文使用的环境如题,主机使用的是腾讯云主机. 内容应该会是linux和apache这些所有部分都有一点,因为是遇见一个问题就记录一个. 配置LAMP环境 这部分可以参考这篇文章:https://www ...
- Java程序操作HDFS
1.新建项目2.导包 解压hadoop-2.7.3.tar.gzE:\工具\大数据\大数据提升资料\01-软件资料\06-Hadoop\安装包\Java1.8环境下编译\hadoop-2.7.3\ha ...
- FZU - 1901 Period II (kmp)
传送门:FZU - 1901 题意:给你个字符串,让你求有多少个p可以使S[i]==S[i+P] (0<=i<len-p-1). 题解:这个题是真的坑,一开始怎么都觉得自己不可能错,然后看 ...
- Codeforces Round #660 (Div. 2) Uncle Bogdan and Country Happiness dfs
题目链接:Uncle Bogdan and Country Happiness 题意: t组输入,每组数据输入如下 首先一个n代表有n个城市,所有城市总人数为m,后面输入pi表示第i个城市的居住人数, ...
- P1387 最大正方形 && P1736 创意吃鱼法(DP)
题目描述 在一个n*m的只包含0和1的矩阵里找出一个不包含0的最大正方形,输出边长. 输入输出格式 输入格式: 输入文件第一行为两个整数n,m(1<=n,m<=100),接下来n行,每行m ...
- Codeforces Round #343 (Div. 2) E. Famil Door and Roads (树形dp,lca)
Famil Door's City map looks like a tree (undirected connected acyclic graph) so other people call it ...
- 2019 Multi-University Training Contest 5——permutation 2
传送门 题意: t组输入,之后每组例子有三个数n.x.y代表在一个以x为开头y为结尾的长为n的数组里面,开头和结尾数据已经固定,让你从1--n中找其他数据填入数组中 (每个数据不能重复使用),使它满足 ...
- Ubuntu上安装Python3编译器和 Pycharm 集成开发环境
一.安装python3 (Ubuntu上面是自带python编译器的,可以用命令"python -V"来查看版本号.我下面安装的是pyhton3编译器) 一条命令就可以 sudo ...