【问题标题】:Does AVRO schema also get encoded in the binary part?AVRO 模式是否也在二进制部分编码?
【发布时间】:2015-04-07 20:35:20
【问题描述】:

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

【问题讨论】:

    标签: serialization deserialization avro


    【解决方案1】:

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

    该文件以 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 使用可变长度之字形编码进行编码,所以这里04 表示与getmeta 的输出一致的2。 (记得阅读 Avro 规范以了解各种数据类型是如何编码的)
    • 就在您找到地图的第一个键之后。键是一个字符串,字符串以字节长度为前缀。这里0x14 表示 10 个字节,即 UTF-8 编码时“avro.codec”的长度。
    • 然后您可以跳过接下来的 10 个字节并转到下一个元素。等等。您可以前进,直到找到avro.schema 部分。
    • 紧跟在这个字符串之后的是映射值的长度(这是一个字符串,因为它是我们的架构)。这就是您要修改的内容。我们正在将 station 重命名为 station-id,因此您希望将 3 添加到当前长度,因此 f2 02 现在应该是 f8 02(还记得可变长度之字形编码吗?)。
    • 您现在可以更新架构字符串以添加“-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}

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

    【讨论】:

    • Mac OS X 上是hexdump -n 256 -C weather-orig.avro
    猜你喜欢
    • 2014-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-25
    • 2012-01-08
    • 2022-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多