scala中任意类型字段的avro记录

kx1ctssn  于 2021-06-07  发布在  Kafka
关注(0)|答案(2)|浏览(434)

假设我在avro中有一个简单的键值对,其中的值可以是 float , double , int , string 等;

{"namespace": "com.namespace.kafka.event",
 "type": "record",
 "name": "RecordName",
 "fields": [
    {"name": "key", "type": "String"},
    {"name": "value", "type": "Any/Object/Bytes???"}
 ]
}

在avro中,最好的表达方式是什么?
有一个字节数组,以某种方式在scala中反序列化,并推断类型或添加另一个带有元数据的值字段
为值中的每个基元类型创建一个自定义记录类型,并在avro中使用泛型记录解析
为我们希望表示的每个原语值类型创建一个键/值对。
另一个问题是如何在scala中表示这一点。拥有一个任何类型都是一件痛苦的事,如果它是数字等的话,最好知道它的类型,而不是到处做类型测试。。。

k10s72fa

k10s72fa1#

你能尝试使用avro的union数据类型吗?
https://avro.apache.org/docs/1.8.1/spec.html#unions

f8rj6qna

f8rj6qna2#

如果您使用的是avro4s,那么您可以使用 Either[A,B] 如果你只有两种类型。定义您的case类以包含以下两种情况之一:

case class Moo(either: Either[String, BigDecimal])

然后可以为其创建架构:

val schema = Schemafor[Moo]

或写出数据:

val moo1 = Moo(Left("moo1"))
val moo2 = Moo(Right(12.3))

val output = new ByteArrayOutputStream
val avro = AvroOutputStream.data[Moo](output)
avro.write(moo1, moo2)
avro.close()

读取数据:

val in = AvroInputStream.data[Moo](bytes)
val moos = in.iterator.toList
in.close()

如果有两种以上的类型,可以使用shapeless的余积。case类现在如下所示:

case class Moo(coproduct: String :+: BigDecimal :+: CNil)

如果您不熟悉shapeless中的coproduct语法,那么当您第一次看到它时就有点不寻常了,但是您只是使用中缀样式将类型组合在一起,而+:+实际上是 :: 是标准scala中非空列表的名称。
现在创建如下示例:

val moo1 = Moo(Coproduct[String]("moo1"))
val moo2 = Moo(Coproduct[BigDecimal](12.3))

其余的都一样。
有关更多示例,请参见这里的avro4s中的单元测试。

相关问题