一、在使用nifi的过程中会使用到遇到avro schema、avro data、avroReader、avroWriter等,所以本节课和大家一起学习下avro相关知识。
二、什么是Avro
Apache Avro是hadoop中的一个子项目,也是一个数据序列化系统,其数据最终以二进制格式,采用行式存储的方式进行存储。
三、什么是avro schema
Avro依赖"schema"(模式)来实现数据结构的定义,schema通过json对象来进行描述表示(类似于java代码中的bean类),具体表现为:
- 一个json字符串命名一个定义的类型
- 一个json对象,其格式为`{"type":"typeName" ...attributes...}`,其中`typeName`为原始类型名称或复杂类型名称。
- 一个json数组,表示嵌入类型的联合
schema中的类型由原始类型(也就是基本类型)(null、boolean、int、long、float、double、bytes和string)和复杂类型(record、enum、array、map、union和fixed)组成。
1、原始类型
原始类型包括如下几种:
- null:没有值
- boolean:布尔类型的值
- int:32位整形
- long:64位整形
- float:32位浮点
- double:64位浮点
- bytes:8位无符号类型
- string:unicode字符集序列
原始类型没有指定的属性值,原始类型的名称也就是定义的类型的名称,因此,schema中的"string"等价于{"type":"string"}。
2、复杂类型
Avro支持6种复杂类型:records、enums、arrays、maps、unions和fixed。
1)Records
- reocrds使用类型名称"record",并支持以下属性
- name:提供记录名称的json字符串(必选)
- namespace:限定名称的json字符串
- doc:一个json字符串,为用户提供该模式的说明(可选)
- aliases:字符串的json数组,为该记录提供备用名称
- fields:一个json数组,罗列所有字段(必选),每个字段又都是一个json对象,并包含如下属性:
- name:字段的名称(必选)
- doc:字段的描述(可选)
- type:一个schema,定义如上
- default:字段的默认值
- order:指定字段如何影响记录的排序顺序,有效值为`"ascending"`(默认值)、"descending"和"ignore"。
demo 如下:
{ "type": "record", "name": "person", "aliases": ["xiaojingang"], "fields", [ {"name": "id", "type": "long"}, {"name": "name", "type": "string"} ] }
2)Enums
Enum使用类型名称"enum",并支持以下属性
- name:提供记录名称的json字符串(必选)
- namespace:限定名称的json字符串
- aliases:字符串的json数组,为该记录提供备用名称
- doc:一个json字符串,为用户提供该模式的说明(可选)
- symbols:一个json数组,以json字符串的形式列出符号。在枚举中每个符号必须唯一,不能重复,每个符号都必须匹配正则表达式"[A-Za-z_][A-Za-z0-9_]*"。
- default:该枚举的默认值。
demo 如下:
{ "type": "enum", "name": "personType", "symbols": ["xiaojinang", "dajingang"] }
3) Arrays
-
item:数组中元素的schema
声明一个value为string的array,demo如下:
{ "type": "array", "items": "string", "default": [] }
4)Maps
-
values:map的值(value)的schema,其key被假定为字符串
声明一个value为long类型,(key类型为string)的map,demo如下:
{ "type": "map", "values": "long", "default": {} }
5)Unions
联合使用json数组表示,例如[null, "test"]声明一个模式,它可以是空值或字符串。
需要注意的是:当为union类型的字段指定默认值时,默认值的类型必须与union第一个元素匹配,因此,对于包含"null"的union,通常先列出"null",因为此类型的union的默认值通常为空。
另外, union不能包含多个相同类型的schema,类型为record、fixed和eum除外。
6)Fixed
Fixed使用类型名称"fixed"并支持以下属性:
- name:提供记录名称的json字符串(必选)
- namespace:限定名称的json字符串
- aliases:字符串的json数组,为该记录提供备用名称
- doc:一个json字符串,为用户提供该模式的说明(可选)
- size:一个整数,指定每个值的字节数(必须)
16字节的数,demo如下:
{ "type": "fixed", "name": "md5", "size": 16 }
四、avro的优点
Avro 格式相比 JSON 具有以下几个优点:
1. 紧凑的数据表示: Avro 使用二进制格式进行数据存储,相比 JSON 的文本格式,二进制数据通常更加紧凑,占用更小的存储空间。这意味着在网络传输和持久化存储时,Avro 可以减少数据的大小,降低传输和存储成本。
2. 快速的序列化和反序列化: Avro 的二进制格式使得序列化和反序列化的过程更加高效。相比 JSON 的文本解析,Avro 的二进制序列化和反序列化速度更快,特别是对于大型数据集,性能提升更为显著。
3. Schema 的支持: Avro 要求数据必须按照预先定义的 schema 进行序列化和反序列化。这意味着数据的结构和类型在传输过程中是明确的,可以提供更强的数据验证和类型安全性。而 JSON 是一种自描述的文本格式,数据结构和类型信息嵌入在数据中,有时候可能存在解析不准确或不一致的情况。
4. Schema 的演化: Avro 允许 schema 的演化,即可以在不破坏现有数据的前提下对 schema 进行更新。这使得系统可以灵活地适应数据结构的变化,而无需进行大规模的数据迁移。相比之下,JSON 的结构变更可能需要更复杂的处理和数据转换。
5. 支持多种语言: Avro 提供了多种编程语言的支持,包括 Java、Python、C++ 等。通过 Avro 的各语言库,可以方便地在不同的平台和系统中进行数据交换和处理。
Avro 格式相对于 JSON 具有更高的效率、更严格的数据约束和更好的可扩展性,特别适用于大规模数据处理和分布式系统中的数据交换与存储。
五、示例演示:
首先定义schema的内容,具体为4个字段的表,名称(字符串)、年龄(整型)、技能(数组)、其他(map类型),详细如下所示:
{ "type":"record", "name":"person", "fields": [ { "name": "name", "type": "string" }, { "name": "age", "type": "int" }, { "name": "skill", "type": { "type":"array", "items": "string" } }, { "name": "other", "type": { "type": "map", "values": "string" } } ] }
再按照上面的schema定义两条数据(person.json):
{"name":"java小金刚","age":20,"skill":["java","go","python","kafka"],"other":{"interests":"basketball"}} {"name":"java大金刚","age":18, "skill":["java","scala"],"other":{}}
通过avro-tools可以生成一个avro文件:
java -jar avro-tools-1.7.4.jar fromjson --schema-file person.avsc person.json > person.avro
对于一个已存在的文件,也可以通过avro-tools工具查看schema内容、数据内容。
java -jar avro-tools-1.7.4.jar getschema person.avro
java -jar avro-tools-1.7.4.jar tojson person.avro