我可以将Avro序列化数据附加到现有的Azure blob吗?

时间:2014-09-17 01:22:16

标签: azure hadoop hive azure-storage-blobs avro

我在问我能否,但我也想知道我是否

这是我的情景: 我小批量收到Avro序列化邮件。我想将它们存储起来,以便以后使用带有Avro SerDe的Hive表进行分析。我在Azure中运行,我将消息存储在blob中。 我试图避免有很多小blob(因为我相信这会对Hive产生负面影响)。如果我已将Avro标头写入blob,我相信可以使用CloudBlockBlob.PutBlockAsync()附加Avro数据块。 (只要我知道同步标记。)

但是,我已经检查了两个.NET库,但似乎不支持我的方法。 (我必须立即编写整个Avro容器文件。)

我采取了正确的方法吗? 我是否遗漏了图书馆中的内容?

我的问题与此问题类似(但不同): Can you append data to an existing Avro data file?

2 个答案:

答案 0 :(得分:1)

这里简短的回答是我试图做错事。

首先,我们认为Avro不适合在线序列化。首先,因为Avro希望模式定义出现在每个Avro文件中。这增加了传递的重量。您可以仍然使用Avro,但这不是它的设计目标。 (它专为HDFS上的大文件而设计。)

其次,现有的库(用于.NET)仅支持通过流附加到Avro文件。这不能很好地映射到Azure块blob(您不希望将块blob作为流打开)。

第三,即使可以绕过前两个,单个Avro文件中的所有项目都应该共享相同的模式。我们有一组异类项目,我们希望缓冲,批处理和写入blob。在我们将它们写入blob时,尝试按类型/模式隔离项目会增加许多复杂性。最后,我们选择使用JSON。

答案 1 :(得分:1)

可以这样做。

首先,您必须使用CloudAppendBlob:

CloudAppendBlob appBlob = container.GetAppendBlobReference(
            string.Format("{0}{1}", date.ToString("yyyyMMdd"), ".log"));


appBlob.AppendText(
                string.Format(
                "{0} | Error: Something went wrong and we had to write to the log!!!\r\n",
                dateLogEntry.ToString("o")));

第二步是告诉avro lib不要在追加时写标题并在追加之间共享相同的同步标记:

var avroSerializer = AvroSerializer.Create<Object>();
        using (var buffer = new MemoryStream())
        {
            using (var w = AvroContainer.CreateWriter<Object>(buffer, Codec.Deflate))
            {
                Console.WriteLine("Init Sample Data Set...");
                var headerField = w.GetType().GetField("header", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                var header = headerField.GetValue(w);
                var marker = header.GetType().GetField("syncMarker", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                marker.SetValue(header, new byte[16]);
                using (var writer = new SequentialWriter<Object>(w, 24))
                {
                    // Serialize the data to stream by using the sequential writer
                    for (int i = 0; i < 10; i++)
                    {
                        writer.Write(new Object());
                    }
                }
            }
            Console.WriteLine("Append Sample Data Set...");

            //Prepare the stream for deserializing the data
            using (var w = AvroContainer.CreateWriter<Object>(buffer, Codec.Deflate))
            {
                var isHeaderWritten = w.GetType().GetField("isHeaderWritten", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                isHeaderWritten.SetValue(w, true);
                var headerField = w.GetType().GetField("header", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                var header = headerField.GetValue(w);
                var marker = header.GetType().GetField("syncMarker", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                marker.SetValue(header, new byte[16]);

                using (var writer = new SequentialWriter<Object>(w, 24))
                {
                    // Serialize the data to stream by using the sequential writer
                    for (int i = 10; i < 20; i++)
                    {
                        writer.Write(new Object());
                    }
                }
            }
            Console.WriteLine("Deserializing Sample Data Set...");
        }