Json 读取Amazon Kinesis Firehose stream写入s3的数据
我正在向Kinesis Firehose流写入记录,最终由Amazon Kinesis Firehose写入S3文件 我的记录对象看起来像Json 读取Amazon Kinesis Firehose stream写入s3的数据,json,amazon-s3,amazon-kinesis,amazon-kinesis-firehose,Json,Amazon S3,Amazon Kinesis,Amazon Kinesis Firehose,我正在向Kinesis Firehose流写入记录,最终由Amazon Kinesis Firehose写入S3文件 我的记录对象看起来像 ItemPurchase { String personId, String itemId } 写入S3的数据如下所示: {"personId":"p-111","itemId":"i-111"}{"personId":"p-222","itemId":"i-222"}{"personId":"p-333","itemId":"i-333"
ItemPurchase {
String personId,
String itemId
}
写入S3的数据如下所示:
{"personId":"p-111","itemId":"i-111"}{"personId":"p-222","itemId":"i-222"}{"personId":"p-333","itemId":"i-333"}
没有逗号分隔
在Json数组中没有起始括号
[
]
在Json数组中没有结束括号
[
]
我想读取此数据以获取ItemPurchase对象的列表
List<ItemPurchase> purchases = getPurchasesFromS3(IOUtils.toString(s3ObjectContent))
List purchases=getPurchasesFromS3(IOUtils.toString(s3ObjectContent))
读取此数据的正确方法是什么?如果有方法更改写入数据的方式,请用一行分隔所有记录。这样,您就可以简单地逐行读取数据。如果没有,那么只需构建一个以“}”为分隔符的scanner对象,并使用scanner进行读取。那就行了。我也遇到过同样的问题 如果AWS允许我们设置分隔符会更好,但我们可以自己设置 在我的用例中,我一直在收听推特流,一旦收到一条新推特,我立即将其放到
Firehose
当然,这会导致无法解析的单行文件
因此,为了解决这个问题,我将tweet的JSON与\n
连接起来。
这反过来让我可以使用一些包,在读取流内容时可以输出行,并且可以轻松地解析文件
希望这对你有帮助。我也有同样的问题,下面是我如何解决的
一个嵌套的json对象有几个“}”,所以按“}”分割行并不能解决问题 我认为解决这个问题的最佳方法是首先创建一个格式正确的json文件,其中包含分离良好的json对象。在我的例子中,我在推到消防水龙带的事件中添加了“,”。然后,在s3中保存一个文件后,所有文件都将包含json对象,对象之间用一些分隔符分隔(在本例中为逗号)。必须添加的另一项内容是文件开头和结尾的“[”和“]”。然后就有了一个包含多个json对象的正确json文件。现在就可以解析它们了 Amazon Firehose以这种方式将JSON消息转储到S3,并且不允许您设置分隔符或任何东西,这让我感到不可思议 最终,我发现解决这个问题的诀窍是使用JSON raw_解码方法处理文本文件 这将允许您读取一组连接的JSON记录,而不在它们之间使用任何分隔符 Python代码:
import json
decoder = json.JSONDecoder()
with open('giant_kinesis_s3_text_file_with_concatenated_json_blobs.txt', 'r') as content_file:
content = content_file.read()
content_length = len(content)
decode_index = 0
while decode_index < content_length:
try:
obj, decode_index = decoder.raw_decode(content, decode_index)
print("File index:", decode_index)
print(obj)
except JSONDecodeError as e:
print("JSONDecodeError:", e)
# Scan forward and keep trying to decode
decode_index += 1
导入json
decoder=json.JSONDecoder()
以open('giant_-kinisis_-s3_-text_-file_,带有连接的_-json_-blobs.txt,'r')作为内容文件:
content=content\u file.read()
内容长度=长度(内容)
解码索引=0
解码索引<内容长度时:
尝试:
对象,解码索引=解码器。原始解码(内容,解码索引)
打印(“文件索引:”,解码索引)
打印(obj)
除了JSONDecodeError作为e:
打印(“JSONDecodeError:,e)
#向前扫描并继续尝试解码
解码索引+=1
您可以通过计算括号找到每个有效JSON的名称。假设文件以{
开头,此python代码段应该可以工作:
导入json
def read_块(流):
开括号=0
块=“”
尽管如此:
c=流。读取(1)
如果不是c:
打破
如果c=='{':
开括号+=1
elif c=='}':
开括号-=1
块+=c
如果开括号==0:
屈服块
块=“”
如果名称=“\uuuuu main\uuuuuuuu”:
c=0
打开('firehose\u json\u blob','r')作为f:
对于读取块(f)中的块:
record=json.loads(块)
打印(记录)
如果firehose的输入源是一个分析应用程序,那么这个不带分隔符的连接JSON是一个众所周知的问题。您应该有一个lambda函数,可以输出多行JSON对象。使用这个简单的Python代码
input_str = '''{"personId":"p-111","itemId":"i-111"}{"personId":"p-222","itemId":"i-222"}{"personId":"p-333","itemId":"i-333"}'''
data_str = "[{}]".format(input_str.replace("}{","},{"))
data_json = json.loads(data_str)
然后(如果你想)变成熊猫
import pandas as pd
df = pd.DataFrame().from_records(data_json)
print(df)
这就是结果
itemId personId
0 i-111 p-111
1 i-222 p-222
2 i-333 p-333
我使用转换Lambda在每条记录的末尾添加一个换行符
def lambda_handler(event, context):
output = []
for record in event['records']:
# Decode from base64 (Firehose records are base64 encoded)
payload = base64.b64decode(record['data'])
# Read json as utf-8
json_string = payload.decode("utf-8")
# Add a line break
output_json_with_line_break = json_string + "\n"
# Encode the data
encoded_bytes = base64.b64encode(bytearray(output_json_with_line_break, 'utf-8'))
encoded_string = str(encoded_bytes, 'utf-8')
# Create a deep copy of the record and append to output with transformed data
output_record = copy.deepcopy(record)
output_record['data'] = encoded_string
output_record['result'] = 'Ok'
output.append(output_record)
print('Successfully processed {} records.'.format(len(event['records'])))
return {'records': output}
我曾考虑过这样做,但我认为如果JSON对象中的一个字符串碰巧包含一个}{,那么这项技术就会失败。如果您遍历每个字符,如果您点击一个(表示输入或离开字符串),则切换一个布尔值,计算您所处对象的级别(看到时递增){在一个字符串外,在一个字符串外看到“递减”),然后考虑对象的结尾,当你的级别计数器再次命中0。分离器<代码> } />代码是有问题的,因为内部字符串可以在其中有JSON:<代码> { \代码>(带有逃逸引号),所以使用<代码> }“作为分隔符要好一点,因为内部字符串不能有quotesTo来构建Eran的答案,我使用了一个负的前瞻来解释
}{
出现在字符串末尾的情况:re.sub('}{((?![,}]),'}\n{',string)
警告:这只是一个盲流读取器,因此,如果任何JSON blob包含碰巧包含转义括号的字符串,它将中断。这适用于JSON,但不适用于更复杂的标记,如XML。如果每条记录都是XML文档,则需要对其进行解析,并将根元素包装到新的XML文档和其他类型中封闭元素(我使用了
)。我目前正试图弄清楚如何以这种方式读取S3。