Avro schema Specification

本文介绍了Apache Avro的数据格式及应用。Avro是一种数据序列化系统,支持丰富的数据结构并具备灵活的schema演化特性。文章详细解释了Avro中的各种数据类型,包括基本类型、复杂类型等,并给出了具体的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Introduction

    此文档定义了Apache Avro,它是权威的指南,Avro的实现必须遵循此文档。

Schema Declaration

    schema是以Json的形式展现,存在以下几种形式:
    1)Json字符串,命名为以定义类型。
    2)Json对象,形式:{"type": "typeName" ...attributes...},typename要么是原始类型或派生类型。在文档中为定义的attribute可以作为元数据,但不能影响序列化数据的格式。
    3)Json数组,代表了内嵌类型的联合体

Primitive types

    基础数据类型如下:
    1)null:无指
    2)boolean:二进制值
    3)int:32位有符号整数
    4)long:64位有符号整数
    5)float:单精度(32位)浮点数
    6)double:双精度(64位)浮点数
    7)bytes:8位bit字节序列
    8)string:unicode字符序列
    基本类型没有指定的属性,{"type":"string"}

Complex Types

    avro支持六种复杂类型:records,enums,arrays,maps,unions和fixed。

record

records:使用name为"record",支持三种属性。
        1)name:json字符串,提供record的名称
        2)namespace:name的全名。
        3)doc:此schema的描述
        4)aliases:json的字符串数组,name的替代值。
        5)fields:json数组,filed列表,每一个filed是一个json对象,其属性如下:
           1)name:json字符串
           2)doc:field的描述
           3)type:json对象的定义schema。
           4)default:此filed的默认值

           5)order:指定此record中filed的压缩排序顺序。有效值为ascending descending ignore

{
  "type": "record", 
  "name": "LongList",
  "aliases": ["LinkedLongs"],                      // old name for this
  "fields" : [
    {"name": "value", "type": "long"},             // each element has a long
    {"name": "next", "type": ["LongList", "null"]} // optional next element
  ]
}

Enums

    枚举使用类型名称为"enum",支持一下属性:
    1)name:json字符串
    2)namespace:全名
    3)aliases:json字符串数组,别名
    4)doc:此schema的描述
    5)symbols:json数组,symbols列表
{ "type": "enum",
  "name": "Suit",
  "symbols" : ["SPADES", "HEARTS", "DIAMONDS", "CLUBS"]
}

Arrays

    使用type的名称为array,支持单个属性。items:数组元素的schema。
{"type": "array", "items": "string"}

Maps

   使用type的名称为map,支持一个属性。values:map的value的schema。map的keys设定为字符串。
{"type": "map", "values": "long"}

Unions

   Union使用json数组代表,如["string","null"],声明schema要么是null要么是null。对于同一个类型,union不会包含多于一个的schema。

Fixed

   支持两个属性。
   1)name,此filed的名称 
   2)namespace:全名
   3)aliases:别名,json字符串数组
   4)size:integer,每个值的字节数
{"type": "fixed", "size": 16, "name": "md5"} 

Data Serialization

    avro data序列化伴随着schema。存储Avro数据的文件也包括此数据的schema。Avro的RPC系统必须保证远程数据接受者写数据时有schema的备份。因为当数据读取时,写入数据的schema通常是可获取的,所以Avro数据本身并不包含类型信息。一般来说,序列化和反序列化的过程是:深度优先,由左至右遍历schema。
Encodings
    avro提供了两种学裂化编码方式:二进制和Json。大多数使用二进制编码,因为小巧,快速。基于调试和web的application,Json编码会更加合适。
Binary Encoding
    

  
### 定义并列的Avro Schema 在处理数据流或消息队列时,可能需要支持多个版本的 Avro schema 或者完全独立的不同类型的 schema。这可以通过定义并列的 Avro schema 来实现。 #### 使用不同的命名空间和名称区分 为了确保不同用途下的 schema 不会发生冲突,可以采用不同的命名空间(namespace) 和 名称(name),即使它们具有相同的字段结构。例如: ```json { "type": "record", "name": "UserV1", "namespace": "com.example.v1", "fields": [ {"name": "id", "type": "int"}, {"name": "username", "type": "string"} ] } ``` 以及另一个版本: ```json { "type": "record", "name": "UserV2", "namespace": "com.example.v2", "fields": [ {"name": "userId", "type": "long"}, // 更改了类型 {"name": "userName", "type": "string"} // 字段名也做了调整 ] } ``` 通过这种方式可以在同一环境中安全地维护多套相互独立却又相似的数据模型[^4]。 #### 利用Schema Registry管理并列schema 当涉及到实际应用中对于这些并列存在的 schema 的管理和使用时,则推荐借助于像 Confluent Schema Registry 这样的工具。它允许用户基于特定的主题(topic)上传多种版本的 schema,并且能够自动处理向前兼容性和向后兼容性的验证工作。这意味着应用程序可以根据实际情况灵活选择适用的具体 schema 版本来进行序列化/反序列化的操作而不用担心破坏已有系统的正常运作[^2]。 #### 实现代码示例 下面是一个简单的例子展示如何在一个 Kafka 生产者程序里同时发送两种不同类型的消息给同一个 topic,这里假设已经配置好了相应的 schema registry 地址。 ```java Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "io.confluent.kafka.serializers.KafkaAvroSerializer"); props.put("schema.registry.url", "http://localhost:8081"); KafkaProducer<String, GenericRecord> producer = new KafkaProducer<>(props); // 创建两个不同版本的 avro 记录对象 GenericData.Record userV1 = new GenericData.Record(Schema.Parser().parse(schemaStringV1)); userV1.put("id", 1); userV1.put("username", "Alice"); GenericData.Record userV2 = new GenericData.Record(Schema.Parser().parse(schemaStringV2)); userV2.put("userId", 1L); userV2.put("userName", "Bob"); producer.send(new ProducerRecord<>("users_topic", null, userV1)); producer.send(new ProducerRecord<>("users_topic", null, userV2)); producer.close(); ``` 在这个案例中,`users_topic` 接收到了来自 `UserV1` 和 `UserV2` 类型的消息,但是由于有 schema registry 存在于中间件层面做协调,所以消费者端依然能正确解析收到的内容而不必担心因为 schema 变更带来的不一致问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值