在PySpark中读取自定义序列文件

时间:2017-03-09 05:59:54

标签: java scala hadoop apache-spark pyspark

我在Hadoop中有一个自定义可写类,它保存为序列文件,如下所示

   public class ABC implements Writable{
    private byte[] myId;
    private byte[] myType;

    //Constructor and other methods
    @Override
    public void write(DataOutput out) throws IOException {
        myId.write(out);
        myType.write(out);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        myId.readFields(in);
        myType.readFields(in);
    }
}

我想使用PySpark读取序列文件并获取数据。我尝试了以下三种方式:

  1. 直接阅读:
  2. sc.sequenceFile(" file:///Test.seq" ;, keyClass =" ABC",valueClass =" ABC")

    但是

    object not serializable (class: ABC, value: ABC@451de3ec)
    
    1. 写转换器:
    2. 来自官方教程http://spark.apache.org/docs/latest/programming-guide.html#external-datasets,其中说

        

      如果您有自定义序列化二进制数据(例如从中加载数据)   Cassandra / HBase),那么你首先需要转换那些数据   Scala / Java方面可以用Pyrolite来处理   皮克勒。为此提供了转换器特性。简单地扩展一下   trait并在convert方法中实现转换代码。

      因此,我按如下方式实现转换器:

      import test.ABC
      import java.io.DataInput
      import org.apache.spark.api.python.Converter
      
      /**
       * Implementation of [[org.apache.spark.api.python.Converter]] that converts data
       * to ABC
       */
      class DataToABCConverter extends Converter[Any, ABC] {
        override def convert(obj: Any): ABC = {
          if (obj == null) {
            return null
          }
          val in = obj.asInstanceOf[DataInput]
          val abc = new ABC()
          abc.readFields(in)
          abc
        }
      }
      

      在PySpark中,我使用以下代码

      sc.sequenceFile("file:///Test.seq", keyClass = "ABC", valueClass ="ABC",  keyConverter="DataToABCConverter",  valueConverter="DataToABCConverter" )
      

      但是得到以下错误

      java.lang.ClassCastException: ABC cannot be cast to java.io.DataInput
      

      转换器的输入似乎是我的ABC类而不是java.io.DataInput,因此我无法应用readFields方法来获取数据。

      1. 使用BytesWritable:
      2. 我添加geID()方法来获取byets并按如下方式更改转换器:

        class DataToChunkConverter extends Converter[Any, BytesWritable] {
          override def convert(obj: Any): BytesWritable = {
            if (obj == null) {
              return null
            }
            val abc = obj.asInstanceOf[ABC]
            val idd = abc.getID()
            new BytesWritable(idd)
          }
        }
        

        比我使用

        运行pyspark
        pyspark --master=local[8] --conf "spark.kryo.classesToRegister=org.apache.hadoop.io.BytesWritable" --conf "spark.serializer=org.apache.spark.serializer.KryoSerializer"
        

        但是得到以下错误

        Failed to pickle Java object as value: BytesWritable, falling back
        to 'toString'. Error: couldn't pickle object of type class org.apache.hadoop.io.BytesWritable
        

        所以我的问题是在PySpark中读取自定义序列文件的正确方法是什么?什么类型可以通过PySpark序列化?任何建议表示赞赏!!

1 个答案:

答案 0 :(得分:0)

经过一些实验(遵循第三种方法),事实证明,如果将scala或Java中的本机类型用作转换器的返回类型,它就可以工作。

例如,使用Array[Byte]作为返回类型,Pyspark可以成功获取数据:

 class DataToChunkConverter extends Converter[Any,  Array[Byte]] {
  override def convert(obj: Any):  Array[Byte] = {
    if (obj == null) {
      return null
    }
    val abc = obj.asInstanceOf[ABC] 
    val idd = abc.getID()
    idd
  }
}