读取Amazon Kinesis Firehose流写入s3的数据

时间:2015-12-26 03:48:42

标签: 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"}

没有COMMA分离。

在Json数组中没有开始支持

[

在Json数组中没有结束括号

]

我想读取这些数据获取ItemPurchase对象的列表。

List<ItemPurchase> purchases = getPurchasesFromS3(IOUtils.toString(s3ObjectContent))

阅读此数据的正确方法是什么?

9 个答案:

答案 0 :(得分:5)

我也有同样的问题,这就是我的解决方法。

  1. 将“} {”添加到}} \ n {“
  2. 分割为“\ n”的行。

    input_json_rdd.map(lambda x : re.sub("}{", "}\n{", x, flags=re.UNICODE))
                  .flatMap(lambda line: line.split("\n"))
    
  3. 嵌套的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