Avro запись с любым типом поля в Scala

Скажем, у меня есть простая пара ключ-значение в 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?

  1. Иметь массив байтов, который каким-то образом десериализован в Scala, и вывести тип или добавить другое поле значения с метаданными.
  2. Создайте пользовательский тип записи для каждого примитивного типа, который имеет значение, и используйте общий анализ записей в Avro.
  3. Создайте пару ключ / значение для каждого типа примитива, который мы хотим представить.

Другая проблема в том, как бы мы представили это в Scala. Любой тип - это боль, гораздо приятнее знать тип, если он числовой и т. Д., Чем везде делать тесты типов...

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()

Если у вас есть более двух типов, вы можете использовать Coproduct от Shapeless. Класс case теперь выглядит так:

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

Если вы не знакомы с синтаксисом сопроизведения из бесформенного, то это немного необычно, когда вы впервые видите его, но вы просто комбинируете типы вместе, используя стиль инфикс, а +: + на самом деле является именем типа, подобного::это имя непустого списка в стандартном скала.

Теперь вы создаете такие экземпляры:

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

А в остальном тоже самое.

Смотрите модульные тесты в avro4s здесь для дальнейших примеров.

Вы можете попробовать использовать Union DataTypes of Avro?

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

Другие вопросы по тегам