如何在Hadoop中读写Avro文件

时间:2020-01-09 10:34:36  来源:igfitidea点击:

在本文中,我们将介绍如何使用Java API在Hadoop中读写Avro文件。

所需的Jar包

要编写Java程序来读写Avro文件,我们需要将以下jar文件放在classpath中。我们可以将它们添加为Maven依赖项或者复制jar。

  • avro-1.8.2.jar
  • avro-tools-1.8.2.jar
  • Hymanson-mapper-asl-1.9.13.jar
  • Hymanson-core-asl-1.9.13.jar
  • slf4j-api-1.7.25.jar

Java程序编写avro文件

由于使用了Avro,因此我们需要avro模式。

schema.avsc

{
  "type":	"record",
  "name":	"EmployeeRecord",
  "doc":	"employee records",
  "fields": 
    [{
      "name":	"id",	
      "type":	"int"
    }, 
    {
      "name":	"empName",
      "type":	"string"
    }, 
    {
      "name":	"age",
      "type":	"int"
    }
  ]
}

Java代码

import java.io.File;
import java.io.IOException;
import org.apache.avro.Schema;
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumWriter;

public class ExampleAvroWriter {

  public static void main(String[] args) {
    Schema schema = parseSchema();
    writeToAvroFile(schema);
  }
	
  // Method to parse the schema
  private static Schema parseSchema() {
    Schema.Parser parser = new Schema.Parser();
    Schema schema = null;
    try {
      // Path to schema file
      schema = parser.parse(ClassLoader.getSystemResourceAsStream("resources/schema.avsc"));			
    } catch (IOException e) {
      e.printStackTrace();			
    }
    return schema;		
  }
		
  private static void writeToAvroFile(Schema schema) {
    GenericRecord emp1 = new GenericData.Record(schema);
    emp1.put("id", 1);
    emp1.put("empName", "Batista");
    emp1.put("age", 45);
    
    GenericRecord emp2 = new GenericData.Record(schema);
    emp2.put("id", 2);
    emp2.put("empName", "Jigmi");
    emp2.put("age", 23);
          
    DatumWriter datumWriter = new GenericDatumWriter(schema);
    DataFileWriter dataFileWriter = null;
    try {
      
      // Local File system - out file path
      File file = new File("/home/theitroad/emp.avro");
      
      dataFileWriter = new DataFileWriter(datumWriter);
      // for compression
      //dataFileWriter.setCodec(CodecFactory.snappyCodec());
      dataFileWriter.create(schema, file);
      
      dataFileWriter.append(emp1);
      dataFileWriter.append(emp2);
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }finally {
      if(dataFileWriter != null) {
        try {
          dataFileWriter.close();
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }			
    }	        
  }
}

请注意,在此代码输出中,avro文件是在本地文件系统中创建的。如果要在HDFS中创建输出文件,则需要使用以下更改来传递路径。

// For HDFS - out file path
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create("hdfs://hostname:port/user/out/emp.avro"), conf);
OutputStream out = fs.create(newPath("hdfs://hostname:port/user/out/emp.avro"));

并在create方法中传递此OutputStream对象

dataFileWriter.create(schema, out);

在Hadoop环境中执行程序

在Hadoop环境中运行该程序之前,我们需要将上述jars放入$ HADOOP_INSTALLATION_DIR / share / hadoop / mapreduce / lib中。

如果版本不匹配,还将当前版本的Avro-1.x.x jar放在$ HADOOP_INSTALLATION_DIR / share / hadoop / common / lib位置。
要在Hadoop环境中执行上述Java程序,我们需要在Hadoop的类路径中添加包含Java程序的.class文件的目录。

export HADOOP_CLASSPATH='/huser/eclipse-workspace/theitroad/bin'

我的exampleAvroWriter.class文件位于/ huser / eclipse-workspace / theitroad / bin位置,因此我已经导出了该路径。

然后,我们可以使用以下命令运行该程序-

$ hadoop org.theitroad.ExampleAvroWriter

Java程序读取avro文件

为了读取上一个示例中存储在HDFS中的avro文件,可以使用以下方法。根据配置提供HOSTNAME和PORT的值。

private static void readFromAvroFile(Schema schema) {		
  Configuration conf = new	Configuration();
  DataFileReader dataFileReader = null;
  try {
    FsInput in = new FsInput(new Path("hdfs://HOSTNAME:PORT/user/out/emp.avro"), conf);
    DatumReader datumReader = new GenericDatumReader(schema);
    dataFileReader = new DataFileReader(in, datumReader);
    GenericRecord emp = null;
    while (dataFileReader.hasNext()) {
      emp = dataFileReader.next(emp);
      System.out.println(emp);
    }
  }catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }finally {
    if(dataFileReader != null) {
      try {
        dataFileReader.close();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }			
  }	   
}

输出量

{"id": 1, "empName": "Batista", "age": 45}
{"id": 2, "empName": "Jigmi", "age": 23}

如果要从本地文件系统读取avro文件,则可以使用以下方法。

private static void readFromAvroFile(Schema schema) {
  DataFileReader dataFileReader = null;
  try {
    File file = new File("/home/theitroad/emp.avro");
    DatumReader datumReader = new GenericDatumReader(schema);
    dataFileReader = new DataFileReader(file, datumReader);
    GenericRecord emp = null;
    while (dataFileReader.hasNext()) {
      emp = dataFileReader.next(emp);
      System.out.println(emp);
    }
  }catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }finally {
    if(dataFileReader != null) {
      try {
        dataFileReader.close();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }	   
}