如何使用GenericRecordBuilder设置记录数组

时间:2019-05-27 06:01:32

标签: scala apache schema avro bytearrayoutputstream

我正在尝试将Scala对象(即case类)转换为字节数组。

为此,我将使用其特定的架构将对象内容插入GenericRecordBuilder中,并最终使用GenericDatumWriter将其转换为字节数组。

我可以很容易地设置基本类型,并将基本类型的数组设置到GenericRecordBuilder中。

但是,我需要将记录数组插入GenericRecordBuilder中并从中创建字节数组的帮助。

将记录数组插入GenericRecordBuilder中的正确方法是什么?

这是我想要做的事情的一部分:

这是架构:

{
    "type": "record",
    "name": "test1",
    "namespace": "ns",
    "fields": [
      {
        "name": "t_name",
        "type": "string",
        "default": "a"
      },
      {
        "name": "t_num",
        "type": "int",
        "default": 0
      },
      {"name" : "t_arr", "type":
        ["null",
         {"type": "array", "items": {
              "name": "t_arr_a",
              "type": "record",
              "fields": [
                {
                  "name": "t_arr_f1",
                  "type": "int",
                  "default": 0
                },
                {
                  "name": "t_arr_f2",
                  "type": "int",
                  "default": 0
                }
              ]
            }
            }
         ]
       }
    ]
}

这是Scala类,用于填充GenericRecordBuilder并将其转换为字节数组:

package utils

import java.io.ByteArrayOutputStream

import org.apache.avro.{Schema, generic}
import org.apache.avro.generic.{GenericData, GenericDatumWriter}
import org.apache.avro.io.EncoderFactory
import org.apache.avro.generic.GenericRecordBuilder

object CheckRecBuilder extends App {

  val avroSchema: Schema = new Schema.Parser().parse(this.getClass.getResourceAsStream("/data/myschema.avsc"))
  val recordBuilder = new GenericRecordBuilder(avroSchema)

  recordBuilder.set("t_name", "X")
  recordBuilder.set("t_num", 100)


  recordBuilder.set("t_arr", ???)

  val record = recordBuilder.build()


  val w = new GenericDatumWriter[GenericData.Record](avroSchema)
  val outputStream = new ByteArrayOutputStream()
  val e = EncoderFactory.get.binaryEncoder(outputStream, null)
  w.write(record, e)
  val barr =  outputStream.toByteArray

  println("End")

}

1 个答案:

答案 0 :(得分:0)

我设法设置对象数组。

我想知道是否有更好或更合适的方法。

这是我所做的:

  1. 创建了一个案例类:

case class t_arr_a(t_arr_f1:Int, t_arr_f2:Int)

  1. 创建了一种将案例类转换为GenericData.Record的方法:

def caseClassToGenericDataRecord(cc:Product, schema:Schema): GenericData.Record = { val childRecord = new GenericData.Record(schema.getElementType)
val values = cc.productIterator cc.getClass.getDeclaredFields.map(f => childRecord.put(f.getName, values.next )) childRecord }

  1. 更新了上面的CheckRecBuilder类:

已替换:

recordBuilder.set("t_arr", ???)

使用:

  val childSchema = new GenericData.Record(avroSchema2).getSchema.getField("t_arr").schema().getTypes().get(1)
  val tArray = Array(t_arr_a(2,4), t_arr_a(25,14))
  val tArrayGRecords: util.List[GenericData.Record] 
    = Some(yy.map(x => caseClassToGenericDataRecord(x,childSchema))).map(arr => java.util.Arrays.asList(arr: _*)).orNull

  recordBuilder.set("t_arr", tArrayGRecords)