我正在使用NiFi进行恢复并将很多数据存储到Kafka。我实际上处于测试阶段,并且正在使用大型Json文件。
我的Json文件记录了500K录音。
实际上,我有一个用于获取文件的处理器getFile
和一个SplitJson
。
JsonPath表达式:$..posts.*
此配置适用于可记录50K记录的小文件,但对于大文件,它会崩溃。
我的Json文件看起来像这样,"posts":[]
中有50万个寄存器
{
"meta":{
"requestid":"request1000",
"http_code":200,
"network":"twitter",
"query_type":"realtime",
"limit":10,
"page":0
},
"posts":[
{
"network":"twitter",
"posted":"posted1",
"postid":"id1",
"text":"text1",
"lang":"lang1",
"type":"type1",
"sentiment":"sentiment1",
"url":"url1"
},
{
"network":"twitter",
"posted":"posted2",
"postid":"id2",
"text":"text2",
"lang":"lang2",
"type":"type2",
"sentiment":"sentiment2",
"url":"url2"
}
]
}
我阅读了一些有关此问题的文档,但是,主题是文本文件,并且演讲者建议链接许多SplitText
以便逐步拆分文件。像我的Json这样的僵化结构,我不知道该怎么做。
我正在寻找一种解决方案,她可以很好地完成500K录音工作。
答案 0 :(得分:1)
尝试在NiFi中使用SplitRecord处理器。
在SplitRecord处理器中定义记录Reader/Writer controller服务。
然后将Records Per Split
配置为1
,并使用Splits
关系进行进一步处理。
(OR)
如果您想展平并整理记录,请在NiFi中使用ForkRecord处理器。
此链接的用法refer。
答案 1 :(得分:1)
不幸的是,我认为这种情况(记录中的大数组)目前无法很好地处理...
SplitJson要求将整个流文件读取到内存中,并且也没有传出的拆分大小。所以这行不通。
SplitRecord通常是正确的解决方案,但是当前有两个JSON记录读取器-JsonTreeReader和JsonPathReader。这两个流记录,但是这里的问题是只有一个巨大的记录,因此它们每个都将整个文档读入内存。
已经针对此特定问题进行了一些努力,但不幸的是,没有一个人将其发布。
此PR(现已关闭)添加了一个新的JSON记录读取器,该读取器可以从JSON路径开始传输记录,在您的情况下,该路径可能是$ .posts:
https://github.com/apache/nifi/pull/3222
使用该读取器,您甚至都不需要拆分,您只需将流文件发送到PublishKafkaRecord_2_0(或PublishKafkaRecord的任何适当版本),它就会读取每个记录并将其发布到Kafka。
对于新的SelectJson处理器,还有一个开放的PR,看起来可能会有所帮助:
答案 2 :(得分:0)
我在使用json时遇到了同样的问题,并曾经编写流解析器
将ExeuteGroovyScript
处理器与
以下代码。
它应该将较大的传入文件拆分为较小的文件:
@Grab(group='acme.groovy', module='acmejson', version='20191029')
import groovyx.acme.json.AcmeJsonParser
import groovyx.acme.json.AcmeJsonOutput
def ff=session.get()
if(!ff)return
def objMeta=null
def count=0
ff.read().withReader("UTF-8"){reader->
new AcmeJsonParser().withFilter{
onValue('$.meta'){
//just remember it to use later
objMeta=it
}
onValue('$.posts.[*]'){objPost->
def ffOut = ff.clone(false) //clone without content
ffOut.post_index=count //add attribite with index
//write small json
ffOut.write("UTF-8"){writer->
AcmeJsonOutput.writeJson([meta:objMeta, post:objPost], writer, true)
}
REL_SUCCESS << ffOut //transfer to success
count++
}
}.parse(reader)
}
ff.remove()
输出文件示例:
{
"meta": {
"requestid": "request1000",
"http_code": 200,
"network": "twitter",
"query_type": "realtime",
"limit": 10,
"page": 0
},
"post": {
"network": "twitter",
"posted": "posted11",
"postid": "id11",
"text": "text11",
"lang": "lang11",
"type": "type11",
"sentiment": "sentiment11",
"url": "url11"
}
}