我在问我能否,但我也想知道我是否。
这是我的情景:
我小批量收到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?
答案 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...");
}