我正在写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"}
没有COMMA分离。
在Json数组中没有开始支持
[
在Json数组中没有结束括号
]
我想读取这些数据获取ItemPurchase对象的列表。
List<ItemPurchase> purchases = getPurchasesFromS3(IOUtils.toString(s3ObjectContent))
阅读此数据的正确方法是什么?
答案 0 :(得分:5)
我也有同样的问题,这就是我的解决方法。
分割为“\ n”的行。
input_json_rdd.map(lambda x : re.sub("}{", "}\n{", x, flags=re.UNICODE))
.flatMap(lambda line: line.split("\n"))
嵌套的json对象有几个“}”,因此用“}”分割线并不能解决问题。
答案 1 :(得分:4)
令人难以理解的是,Amazon Firehose以这种方式将JSON消息转储到S3,并且不允许您设置分隔符或任何内容。
最终,我发现处理问题的技巧是使用JSON raw_decode方法处理文本文件
这将允许您读取一堆连接的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
答案 2 :(得分:3)
我遇到了同样的问题。
如果AWS
允许我们设置分隔符,但我们可以自行完成,那会更好。
在我的用例中,我一直在倾听一连串推文,一旦收到新推文,我立即将其发送到Firehose
。
当然,这导致了一个无法解析的1行文件。
因此,为了解决这个问题,我将推文的JSON与\n
连接起来。
反过来,这让我可以使用一些在读取流内容时可以输出行的包,并轻松地解析文件。
希望这会对你有所帮助。
答案 3 :(得分:2)
如果firehose的输入源是Google Analytics(分析)应用程序,则此不带分隔符的JSON 是已知的问题,引用为here。您应该有一个here的lambda函数,该函数可以多行输出JSON对象。
答案 4 :(得分:1)
我使用了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}
答案 5 :(得分:0)
如果有办法改变数据的写入方式,请将所有记录分开。这样,您可以简单地逐行读取数据。如果没有,那么只需构建一个扫描仪对象,其中包含&#34;}&#34;作为分隔符并使用扫描仪进行读取。那就可以了。
答案 6 :(得分:0)
我认为解决此问题的最佳方法是首先创建一个格式正确的json文件,其中包含分离良好的json对象。在我的情况下,我将','添加到被推入firehose的事件中。然后在s3中保存文件后,所有文件都将包含由某些分隔符分隔的json对象(在我们的例子中为逗号)。另一件必须添加的是文件开头和结尾的'['和']'。然后你有一个包含多个json对象的正确的json文件。现在可以解析它们。
答案 7 :(得分:0)
您可以通过计算方括号来找到每个有效的JSON。假设文件以{
开头,则此python代码段应该可以正常工作:
import json
def read_block(stream):
open_brackets = 0
block = ''
while True:
c = stream.read(1)
if not c:
break
if c == '{':
open_brackets += 1
elif c == '}':
open_brackets -= 1
block += c
if open_brackets == 0:
yield block
block = ''
if __name__ == "__main__":
c = 0
with open('firehose_json_blob', 'r') as f:
for block in read_block(f):
record = json.loads(block)
print(record)
答案 8 :(得分:0)
使用此简单的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