将org.apache.avro.generic.GenericRecord转换为org.apache.spark.sql.Row

时间:2017-06-13 10:13:34

标签: apache-spark spark-dataframe avro mapr spark-avro

我有org.apache.avro.generic.GenericRecordavro schema的列表,我们需要在dataframe API的帮助下创建SQLContext,以创建它需要的dataframe { {1}}和RDD的{​​1}}。创建DF的先决条件是我们应该有org.apache.spark.sql.Row的RDD,它可以使用下面的代码来实现,但是它有些不起作用并且给出错误,示例代码。

org.apache.spark.sql.Row

但是在创建avro schema时会出错。有人可以帮我解决上面代码中的错误。除此之外,如果某人有不同的逻辑来转换和创建 1. Convert GenericRecord to Row import org.apache.spark.sql.Row import org.apache.spark.sql.catalyst.expressions.GenericRowWithSchema import org.apache.avro.Schema import org.apache.spark.sql.types.StructType def convertGenericRecordToRow(genericRecords: Seq[GenericRecord], avroSchema: Schema, schemaType: StructType): Seq[Row] = { val fields = avroSchema.getFields var rows = new Seq[Row] for (avroRecord <- genericRecords) { var avroFieldsSeq = Seq[Any](); for (i <- 0 to fields.size - 1) { avroFieldsSeq = avroFieldsSeq :+avroRecord.get(fields.get(i).name) } val avroFieldArr = avroFieldsSeq.toArray val genericRow = new GenericRowWithSchema(avroFieldArr, schemaType) rows = rows :+ genericRow } return rows; } 2. Convert `Avro schema` to `Structtype` Use `com.databricks.spark.avro.SchemaConverters -> toSqlType` function , it will convert avro schema to StructType 3. Create `Dataframe` using `SQLContext` val rowSeq= convertGenericRecordToRow(genericRecords, avroSchema, schemaType) val rowRdd = sc.parallelize(rowSeq, 1) val finalDF =sqlContext.createDataFrame(rowRDD,structType)

每当我在Dataframe上调用任何操作时,它都会执行DAG并尝试创建DF对象,但是在这种情况下,它会因以下异常而失败

DataFrame

在此之后我试图在spark提交的jar参数中给出正确的版本jar,并使用其他参数作为--conf spark.driver.userClassPathFirst = true 但现在它失败了MapR

dataframe

我们正在使用MapR分布和spark-submit中的类路径更改后,它失败并出现上述异常。

有人可以帮助我或者我基本需要它将Avro GenericRecord转换为Spark Row,这样我就可以用它创建Dataframe,请帮助
感谢。

3 个答案:

答案 0 :(得分:3)

也许这可以帮助以后再玩的人。

由于spark-avro已被弃用,现在已集成到Spark中,因此可以通过另一种方式来实现。

import org.apache.spark.sql.avro._
import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.types.StructType
import org.apache.spark.sql.catalyst.encoders.RowEncoder

...

val avroSchema = data.head.getSchema
val sparkTypes = SchemaConverters.toSqlType(avroSchema).dataType.asInstanceOf[StructType]
val converter = new AvroDeserializer(avroSchema, sparkTypes)
val enconder = RowEncoder.apply(sparkTypes).resolveAndBind()

val rows = data.map { record =>
    enconder.fromRow(converter.deserialize(record).asInstanceOf[InternalRow])
}

val df = sparkSession.sqlContext.createDataFrame(sparkSession.sparkContext.parallelize(rows), sparkTypes)

答案 1 :(得分:0)

希望这会有所帮助。在第一部分中,您可以找到如何从GenericRecord转换为Row

How to convert RDD[GenericRecord] to dataframe in scala?

答案 2 :(得分:0)

从RDD [GenericRecord]创建数据框时,步骤很少

  1. 首先需要将org.apache.avro.generic.GenericRecord转换为org.apache.spark.sql.Row
  2.   

    使用com.databricks.spark.avro.SchemaConverters.createConverterToSQL(   sourceAvroSchema:Schema,targetSqlType:DataType)

    这是spark-avro 3.2版本中的私有方法。如果我们有相同或小于3.2,那么将此方法复制到您自己的util类中并使用它,否则直接使用它。

    1. 从Row(rowSeq)的集合创建Dataframe。
    2.   

      val rdd = ssc.sparkContext.parallelize(rowSeq,numParition)val   dataframe = sparkSession.createDataFrame(rowRDD,schemaType)

      这解决了我的问题。