Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

create json representation for decimal logical type and byte types for avro schema

I am trying to create JSON string as per below avro schema, for decimal value. https://avro.apache.org/docs/1.8.2/spec.html#Logical+Types

{
 "name": "score",
 "type": "bytes",
 "logicalType": "decimal",
 "precision": 10,
 "scale": 5
 }

value

"score":3.4,

I am getting exception

Caused by: org.apache.avro.AvroTypeException: Expected bytes. Got VALUE_NUMBER_FLOAT.

Instead of 3.4 if I give "\u0000" then it works but this is representation of 0, how I will get representation for 3.4? For now I am creating hard-coded JSON String, but in future I have to convert output into Decimal, how I can do that in scala.

Is there any way to convert value into decimal logical format?

like image 276
Kalpesh Avatar asked Sep 18 '19 14:09

Kalpesh


People also ask

Does Avro support decimal?

Avro allows arrays of supported basic types, except: String. Decimal.

What is logical type in Avro schema?

Avro supports logical types. A logical type is defined as a higher level representation for a primitive type. For eg, a higher level type of UUID could be represented as a primitive type string. Similarly, a higher level java. time.

Is Avro compatible with JSON?

There are two data serialization formats which Avro supports: JSON format and Binary format.


1 Answers

Java code:

byte[] score = new BigDecimal("3.40000").unscaledValue().tobyteArray();
for (byte b : score) {​
    System.out.println(String.format("\\u%04x", b));
}

Will print out following:

\u00fa
\u00cf
\u00e0

You then need to write json score value like this:

"score":"\u00fa\u00cf\u00e0",

And it should translate to 3.40000. The reason why 3.40000 is because 'scale' in your schema has value 5. If scale would have value 2, then we would have new BigDecimal("3.40")

Scala function for converting BigDecimal to json so avro will understand it

def toJsonString(value: java.math.BigDecimal): String = {
    val bytes = value.unscaledValue().toByteArray
    bytes
      .map(_.formatted("\\u%04x"))
      .mkString
}
like image 171
vanillaSugar Avatar answered Oct 20 '22 00:10

vanillaSugar