Rx java 如何在Apache NiFi onTrigger方法中使用RxJava?
如何让RxJava在NiFi中工作??或者如何让NiFi和RxJava玩得更好?它们看起来是如此完美的互补 我遇到了一个我不知道如何解决的问题。NiFi不断抱怨Rx java 如何在Apache NiFi onTrigger方法中使用RxJava?,rx-java,apache-nifi,Rx Java,Apache Nifi,如何让RxJava在NiFi中工作??或者如何让NiFi和RxJava玩得更好?它们看起来是如此完美的互补 我遇到了一个我不知道如何解决的问题。NiFi不断抱怨IllegalStateException或FlowFileHandlingException,这取决于我在哪里以及如何从FlowFile输入流读取数据的方法 我正在学习ApacheNIFI和RxJava2(即Flowables)。我想创建一个ApacheNIFI处理器,它的操作与现有的SplitText处理器类似——只是更简单。没有标题
IllegalStateException
或FlowFileHandlingException
,这取决于我在哪里以及如何从FlowFile输入流读取数据的方法
我正在学习ApacheNIFI和RxJava2(即Flowables)。我想创建一个ApacheNIFI处理器,它的操作与现有的SplitText处理器类似——只是更简单。没有标题处理,没有片段大小处理——只需拉出每一行数据——我称之为SplitLine
这里没有什么奇特的线程——这意味着我不想用Flowable.observeOn()或Flowable.subscribeOn()做任何事情。一切都应该在一个线程上完成…当前线程
我想我会用RxJava解决这个问题。我将从流文件中读取字符,并使用移位的缓冲区发布它们;例如
Flowable<Tuple<Long, Integer>> chars =
Flowable.generate(
() -> 0L,
(cnt, emitter) -> {
int ch = flowStream.read();
emitter.onNext(new Tuple<>(cnt, ch);
if (ch == -1) emitter.onComplete();
return cnt++;
});
return chars.buffer(2, 1).publish().autoConnect();
我也尝试过使用回调版本,但不出意外地收到一个异常,因为流是从回调而不是读取回调访问的。那就是
session.read(flowFile, stream -> {
RxLineSplitter splitter = new RxLineSplitter(stream);
// RxLineSplitter contains the code above which is the other callback it is complaining about...
}
为什么我要发布字符流?为什么是成对的?我在char流上有两个订阅者。一个查找行首,另一个查找行尾。由于Windows的原因,我需要查找[\r;\n;或\r\n]中的一个。基本上,该对中的第二个字符是一个前瞻字符
如果你感兴趣的话,我的RxSplitLine的核心看起来像
Flowable<Tuple<Long, Integer>> findLineMarkers(
Flowable<List<Tuple<Long, Integer>>> charPairs,
BiFunction<Tuple<Long, Integer>, Optional<Tuple<Long, Integer>>, Optional<Tuple<Long, Integer>>> strategy) {
return charPairs().map(pair -> {
Tuple<Long, Integer> fst = pair.get(0);
Optional<Tuple<Long, Integer>> snd = pair.size() > 1 ? Optional.of(pair.get(1)) : Optional.empty();
return strategy.apply(fst, snd);
}).filter(Optional::isPresent).map(Optional::get);
}
Flowable<SplitInfo> split(InputStream stream) throws IOException {
return findLineMarkers(stream, startingPositionStrategy)
.zipWith(findLineMarkers(stream, endingPositionStrategy),
(s, e) -> new Split(s.item1, e.item1 - s.item1))
.filter(split -> !removeEmptyLines || split.length > 0)
.zipWith(counter(), Tuple::new)
.timeInterval(TimeUnit.MILLISECONDS)
.map(x -> new SplitInfo(x.value().item1.start,
x.value().item1.length,
x.value().item2,
x.time(), x.unit()));
}
可流动findLineMarkers(
可流动碳对,
双功能策略{
返回charPairs().map(对->{
Tuple fst=pair.get(0);
Optional snd=pair.size()>1?Optional.of(pair.get(1)):Optional.empty();
返回策略。应用(fst、snd);
}).filter(可选::isPresent).map(可选::get);
}
可流动拆分(InputStream)引发IOException{
返回findLineMarkers(流、开始位置策略)
.zipWith(findLineMarkers(流、结束位置策略),
(s,e)->新拆分(s.item1,e.item1-s.item1))
.filter(split->!removeMptyline | | split.length>0)
.zipWith(计数器(),元组::新建)
.timeInterval(时间单位为毫秒)
.map(x->new SplitInfo(x.value().item1.start,
x、 value().item1.length,
x、 value().item2,
x、 时间(),x.单位();
}
别胡扯了。。。我将非常感谢在让NiFi和RxJava 2友好相处方面提供的任何帮助或建议。我相信我已经找到了答案。。。至少我的SplitLine处理器显示它已经收到了流文件,读取的字节也很准确 如果您计划在正常的
InputStreamCallback
之外读取或处理输入流,NiFi文档将指示您在ProcessSession.read
上使用其他重载之一,具体地说是InputStream input=session.read(flowFile)
。文档还声明您有责任正确关闭流。对于那些尝试这一点的人,我可能会补充尽可能快地关闭流
在RxJava2中,这意味着我的Flowable.create
方法很接近,但还不够。您需要将一个可流动。在可流动的周围使用
。创建
。下面是我修改过的构造函数和有效的方法
需要注意的几个要点:
您可能会尝试将ProcessSession
传递给Flowable中的resourceSupplier
并将其用于。。。这让我头疼不已,ymmv,我不推荐(但如果你能找到办法,请告诉我)
我使用了Flowable。使用允许您指定eager
参数的
重载。我将我的设置为true以急切地关闭/处理资源(InputStream)
RxLineSplitter(InputStream输入,布尔RemoveEmptyline){
this.inputStream=输入;
this.removemptylines=removemptylines;
}
私有可流动getCharacters(){
流动炭=
流动(
()->这个.inputStream,
输入->可流动。创建(发射器->{
试一试{
长cnt=0;
while(true){
int ch=input.read();
如果(isEOF.试验(ch))断裂;
onNext(新元组(cnt,ch));
++碳纳米管;
}
emitter.onComplete();
}捕获(例外情况除外){
发射极误差(ex);
}
},背压等级缓冲器),
InputStream::close,
正确的);
返回字符缓冲区(2,1);
}
最后的想法:
- 我喜欢支持RxLineSplitter类对NiFi没有依赖性。减少耦合
- 我不喜欢NiFi Processor.onTrigger方法获取InputStream,但需要RxLineSplitter关闭和处置。文档中对此进行了一些讨论,但我觉得它肮脏且容易出错。为了缓解上述问题,InputStream只在一种方法中使用,并使用
Flowable.using
以非常明显和清晰的方式进行清理
希望这对其他人有帮助。。。是时候看看我在使用NiFi和Rx时遇到的其他[学习]障碍了。我相信我已经找到了答案。。。至少我的SplitLine处理器显示它已经收到了流文件,读取的字节也很准确
如果您计划读取或处理no之外的输入流
session.read(flowFile, stream -> {
RxLineSplitter splitter = new RxLineSplitter(stream);
// RxLineSplitter contains the code above which is the other callback it is complaining about...
}
Flowable<Tuple<Long, Integer>> findLineMarkers(
Flowable<List<Tuple<Long, Integer>>> charPairs,
BiFunction<Tuple<Long, Integer>, Optional<Tuple<Long, Integer>>, Optional<Tuple<Long, Integer>>> strategy) {
return charPairs().map(pair -> {
Tuple<Long, Integer> fst = pair.get(0);
Optional<Tuple<Long, Integer>> snd = pair.size() > 1 ? Optional.of(pair.get(1)) : Optional.empty();
return strategy.apply(fst, snd);
}).filter(Optional::isPresent).map(Optional::get);
}
Flowable<SplitInfo> split(InputStream stream) throws IOException {
return findLineMarkers(stream, startingPositionStrategy)
.zipWith(findLineMarkers(stream, endingPositionStrategy),
(s, e) -> new Split(s.item1, e.item1 - s.item1))
.filter(split -> !removeEmptyLines || split.length > 0)
.zipWith(counter(), Tuple::new)
.timeInterval(TimeUnit.MILLISECONDS)
.map(x -> new SplitInfo(x.value().item1.start,
x.value().item1.length,
x.value().item2,
x.time(), x.unit()));
}
RxLineSplitter(InputStream input, boolean removeEmptyLines) {
this.inputStream = input;
this.removeEmptyLines = removeEmptyLines;
}
private Flowable<List<Tuple<Long, Integer>>> getCharacters() {
Flowable<Tuple<Long, Integer>> chars =
Flowable.using(
() -> this.inputStream,
input -> Flowable.create(emitter -> {
try {
long cnt = 0;
while (true) {
int ch = input.read();
if (isEOF.test(ch)) break;
emitter.onNext(new Tuple<>(cnt, ch));
++cnt;
}
emitter.onComplete();
} catch (Exception ex) {
emitter.onError(ex);
}
}, BackpressureStrategy.BUFFER),
InputStream::close,
true);
return chars.buffer(2, 1);
}