AVRO模式是否也在二进制部分中编码?

时间:2015-04-07 20:35:20

标签: serialization deserialization avro

Avro文件包含纯文本架构,后跟二进制格式的数据。我想知道模式(或它的某些部分)是否也存在于二进制部分中?我预感到架构(或者只是字段名称)也会在二进制文件中编码,因为当我在AVRO文件的普通架构部分进行一些更改时,我在使用Avro工具导出架构时收到错误消息.jar。

1 个答案:

答案 0 :(得分:3)

使用二进制编码时,整个文件使用二进制格式。

文件以4字节标头开头,然后紧接着包含一些元数据的地图。此地图包含“avro.schema”条目。此条目的值是存储为字符串的模式。在地图之后,您将找到您的数据。

如果您手动编辑架构,请阅读更改其大小,然后在此字符串不一致且文件已损坏之前存储长度前缀。

请参阅Binary encoding specification以了解各种类型的二进制编码方式。

我不确定你想要达到的目标,我确信不应该这样做。但为了好玩,让我们尝试在适当的位置编辑架构。

对于此示例,我将使用avro源代码树中的weather.avro文件:

$ java -jar avro-tools-1.8.0.jar getmeta weather-orig.avro avro.codec null avro.schema {"type":"record","name":"Weather","namespace":"test","fields":[{"name":"station","type":"string"},{"name":"time","type":"long"},{"name":"temp","type":"int"}],"doc":"A weather reading."}

$ java -jar avro-tools-1.8.0.jar getschema weather-orig.avro { "type" : "record", "name" : "Weather", "namespace" : "test", "doc" : "A weather reading.", "fields" : [ {"name" : "station", "type" : "string"}, {"name" : "time", "type" : "long"}, {"name" : "temp", "type" : "int"} ] }

$ java -jar /avro-tools-1.8.0.jar tojson weather-orig.avro {"station":"011990-99999","time":-619524000000,"temp":0} {"station":"011990-99999","time":-619506000000,"temp":22} {"station":"011990-99999","time":-619484400000,"temp":-11} {"station":"012650-99999","time":-655531200000,"temp":111} {"station":"012650-99999","time":-655509600000,"temp":78}

行。这是我们的源文件。简单,两个元数据条目和模式定义了三个字段。现在,我们将尝试了解事物以二进制形式存储的方式以及我们如何编辑文件以更改重命名station int station-id

$ hexdump weather-orig.avro -n 256 -C 00000000 4f 62 6a 01 04 14 61 76 72 6f 2e 63 6f 64 65 63 |Obj...avro.codec| 00000010 08 6e 75 6c 6c 16 61 76 72 6f 2e 73 63 68 65 6d |.null.avro.schem| 00000020 61 f2 02 7b 22 74 79 70 65 22 3a 22 72 65 63 6f |a..{"type":"reco| 00000030 72 64 22 2c 22 6e 61 6d 65 22 3a 22 57 65 61 74 |rd","name":"Weat| 00000040 68 65 72 22 2c 22 6e 61 6d 65 73 70 61 63 65 22 |her","namespace"| 00000050 3a 22 74 65 73 74 22 2c 22 66 69 65 6c 64 73 22 |:"test","fields"| 00000060 3a 5b 7b 22 6e 61 6d 65 22 3a 22 73 74 61 74 69 |:[{"name":"stati| 00000070 6f 6e 22 2c 22 74 79 70 65 22 3a 22 73 74 72 69 |on","type":"stri| 00000080 6e 67 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 74 69 |ng"},{"name":"ti| 00000090 6d 65 22 2c 22 74 79 70 65 22 3a 22 6c 6f 6e 67 |me","type":"long| 000000a0 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 74 65 6d 70 |"},{"name":"temp| 000000b0 22 2c 22 74 79 70 65 22 3a 22 69 6e 74 22 7d 5d |","type":"int"}]| 000000c0 2c 22 64 6f 63 22 3a 22 41 20 77 65 61 74 68 65 |,"doc":"A weathe| 000000d0 72 20 72 65 61 64 69 6e 67 2e 22 7d 00 b0 81 b3 |r reading."}....| 000000e0 c4 0a 0c f6 62 fa c9 38 fd 7e 52 00 a7 0a cc 01 |....b..8.~R.....| 000000f0 18 30 31 31 39 39 30 2d 39 39 39 39 39 ff a3 90 |.011990-99999...|

  • 前四个字节4f 62 6a 01是标题
  • 接下来是long描述“元数据”地图的第一个块的大小。 long使用可变长度的zig-zag编码进行编码,因此04表示与getmeta的输出相关的2。 (记得阅读Avro规范以了解各种数据类型的编码方式)
  • 在您找到地图的第一个键之后。键是一个字符串,字符串的长度以字节为前缀。这里0x14表示以UTF-8编码时的10个字节,即“avro.codec”的长度。
  • 然后,您可以跳过接下来的10个字节并转到下一个元素。等等。您可以前进,直到找到avro.schema部分。
  • 此字符串之后是map值的长度(因为它是我们的架构,所以是一个字符串)。这就是你想要修改的内容。我们正在将station重命名为station-id,因此您希望将3添加到当前长度,因此f2 02现在应该是f8 02(还记得可变长度之字形编码吗?)。< / LI>
  • 您现在可以更新架构字符串以添加“-id”
  • 享受

java -jar /home/cmathieu/Sources/avro-trunk/lang/java/tools/target/avro-tools-1.8.0-SNAPSHOT.jar tojson weather.avro {"station-id":"011990-99999","time":-619524000000,"temp":0} {"station-id":"011990-99999","time":-619506000000,"temp":22} {"station-id":"011990-99999","time":-619484400000,"temp":-11} {"station-id":"012650-99999","time":-655531200000,"temp":111} {"station-id":"012650-99999","time":-655509600000,"temp":78}

但正如我所说,你很可能不想这样做。