【问题标题】:Avro record with Any type field in ScalaScala 中任何类型字段的 Avro 记录
【发布时间】:2017-01-19 09:31:47
【问题描述】:

假设我在 Avro 中有一个简单的键值对,其中的值可以是 floatdoubleintstring 等;

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

在 Avro 中表示这一点的最佳方式是什么?

  1. 有一个字节数组,在 Scala 中以某种方式反序列化并推断类型或添加另一个带有元数据的值字段
  2. 为每个有值的原始类型创建自定义记录类型,并在 Avro 中使用通用记录解析
  3. 为我们希望表示的每个原始值类型创建一个键/值对。

另一个问题是我们如何在 Scala 中表示它。拥有 Any 类型是一件痛苦的事情,知道类型(如果它的数字等)要好得多,而不必到处进行类型测试......

【问题讨论】:

    标签: scala apache-kafka avro avro4s


    【解决方案1】:

    您可以尝试使用 Avro 的 Union DataTypes 吗?

    https://avro.apache.org/docs/1.8.1/spec.html#Unions

    【讨论】:

      【解决方案2】:

      如果您使用的是avro4s,那么如果您只有两种类型,则可以使用Either[A,B]。定义您的案例类以包括其中一个,例如:

      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 的 Coproduct。案例类现在看起来像这样:

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

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

      现在您可以像这样创建实例:

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

      其余的都是一样的。

      更多示例请参见此处的 avro4s 中的 unit tests

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-28
        • 2019-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-27
        相关资源
        最近更新 更多