• hadoop深入研究:(十八)——Avro schema兼容


    转载请写明来源地址:http://blog.csdn.net/lastsweetop/article/details/9900129

    所有源码在github上,https://github.com/lastsweetop/styhadoop

     

    兼容条件

    在实际的应用中,因为应用版本的问题经常遇到读和写的schema不相同的情况,幸运的是avro已经提供了相关的解决方案。

    下面图示说明:

     

    record兼容

    在hadoop的实际应用中,更多是以record的形式进行交互,接下来我们重点讲解下record的兼容。
    首先从读写schema的角度取考虑,读写schema的不同无外乎就两种,读的schema比写的schema多了一个field,读的schema比写的schema少了一个field,这两种情况处理起来都很简单。
    先看下写的schema:
    {
        "type":"record",
        "name":"com.sweetop.styhadoop.StringPair",
        "doc":"A pair of strings",
        "fields":[
            {"name":"left","type":"string"},
            {"name":"right","type":"string"}
        ]
    }

    增加了field的情况

    增加了field后的schema
    {
        "type":"record",
        "name":"com.sweetop.styhadoop.StringPair",
        "doc":"A pair of strings",
        "fields":[
            {"name":"left","type":"string"},
            {"name":"right","type":"string"},
            {"name":"description","type":"string","default":""}
        ]
    }
    用增加了field的schema取读数据。new GenericDatumReader<GenericRecord>(null, newSchema),第一个参数为写的schema,第二个参数为读的schema,
    由于读的是avro datafile,schema已经在文件的头部指定,所以写的schema可以忽略掉。
        @Test
        public void testAddField() throws IOException {
            //将schema从newStringPair.avsc文件中加载
            Schema.Parser parser = new Schema.Parser();
            Schema newSchema = parser.parse(getClass().getResourceAsStream("/addStringPair.avsc"));
    
            File file = new File("data.avro");
            DatumReader<GenericRecord> reader = new GenericDatumReader<GenericRecord>(null, newSchema);
            DataFileReader<GenericRecord> dataFileReader = new DataFileReader<GenericRecord>(file, reader);
            for (GenericRecord record : dataFileReader) {
                System.out.println("left=" + record.get("left") + ",right=" + record.get("right") + ",description="
                        + record.get("description"));
            }
        }
    

    输出结果为
    left=L,right=R,description=
    left=L,right=R,description=
    description用默认值空字符串代替

    减少了field的情况

    减少了field的schema
    {
        "type":"record",
        "name":"com.sweetop.styhadoop.StringPair",
        "doc":"A pair of strings",
        "fields":[
            {"name":"left","type":"string"}
        ]
    }
    用减少了field的schema取读取
        @Test
        public void testRemoveField() throws IOException {
            //将schema从StringPair.avsc文件中加载
            Schema.Parser parser = new Schema.Parser();
            Schema newSchema = parser.parse(getClass().getResourceAsStream("/removeStringPair.avsc"));
    
            File file = new File("data.avro");
            DatumReader<GenericRecord> reader = new GenericDatumReader<GenericRecord>(null, newSchema);
            DataFileReader<GenericRecord> dataFileReader = new DataFileReader<GenericRecord>(file, reader);
            for (GenericRecord record : dataFileReader) {
                System.out.println("left=" + record.get("left"));
            }
        }
    输出结果为:
    left=L
    left=L
    删除的field被忽略掉

    新旧版本schema

    如果从新旧版本的角度取考虑。
    新版本schema比旧版本schema增加了一个字段
    1.新版本取读旧版本的数据,使用新版本schema里新增field的默认值
    2.旧版本读新版本的数据,新版本schema里新增field被旧版本的忽略掉
    新版本schema比旧版半schema较少了一个字段
    1.新版本读旧版本的数据,减少的field被新版本忽略掉
    2.旧版本读新版本的数据,旧版本的schema使用起被删除field的默认值,如果没有就会报错,那么升级旧版本

    别名

    别名是另一个用于schema兼容的方法,可以将写的schema的field名字转换成读的schema的field,记住并不是加了aliases字段。
    而是将写的filed的name属性变为aliases,读的时候只认name属性。
    来看下加了别名的schema
    {
        "type":"record",
        "name":"com.sweetop.styhadoop.StringPair",
        "doc":"A pair of strings",
        "fields":[
            {"name":"first","type":"string","aliases":["left"]},
            {"name":"second","type":"string","aliases":["right"]}
        ]
    }
    使用别名schema去读数据,这里不能再用left,right,而要用first,second
        @Test
        public void testAliasesField() throws IOException {
            //将schema从StringPair.avsc文件中加载
            Schema.Parser parser = new Schema.Parser();
            Schema newSchema = parser.parse(getClass().getResourceAsStream("/aliasesStringPair.avsc"));
    
            File file = new File("data.avro");
            DatumReader<GenericRecord> reader = new GenericDatumReader<GenericRecord>(null, newSchema);
            DataFileReader<GenericRecord> dataFileReader = new DataFileReader<GenericRecord>(file, reader);
            for (GenericRecord record : dataFileReader) {
                System.out.println("first=" + record.get("first")+",second="+record.get("second"));
            }
        }
    输出结果
    first=L,second=R
    first=L,second=R
  • 相关阅读:
    谈谈你对MVC和三层架构的理解?(月薪三万的面试题)
    logic:iterate 遍历
    db2, oracle和sqlserver取前几行的语法
    数据库常用操作语句
    css中em与px的介绍及换算方法
    禁止浏览器缓存
    JavaScript学习笔记(一)
    CSS控制表格隔行变色与鼠标滑过变色
    程序员——好好规划自己的路
    css规范
  • 原文地址:https://www.cnblogs.com/james1207/p/3278408.html
Copyright © 2020-2023  润新知