为啥 kafka-avro-console-producer 不遵守该字段的默认值?

Posted

技术标签:

【中文标题】为啥 kafka-avro-console-producer 不遵守该字段的默认值?【英文标题】:Why kafka-avro-console-producer doesn't honour the default value for the field?为什么 kafka-avro-console-producer 不遵守该字段的默认值? 【发布时间】:2019-08-24 00:07:38 【问题描述】:

虽然为字段定义了默认值,但kafka-avro-console-producer 完全忽略了它:

$ kafka-avro-console-producer --broker-list localhost:9092 --topic test-avro \
--property schema.registry.url=http://localhost:8081 --property \
value.schema='"type":"record","name":"myrecord1","fields": \
["name":"f1","type":"string","name": "f2", "type": "int", "default": 0]'

"f1": "value1"

org.apache.kafka.common.errors.SerializationException: Error 
deserializing json "f1": "value1" to Avro of schema 
"type":"record","name":"myrecord1","fields": 
["name":"f1","type":"string","name":"f2","type":"int","default":0]
Caused by: org.apache.avro.AvroTypeException: Expected int. Got END_OBJECT
    at org.apache.avro.io.JsonDecoder.error(JsonDecoder.java:698)
    at org.apache.avro.io.JsonDecoder.readInt(JsonDecoder.java:172)
    at org.apache.avro.io.ValidatingDecoder.readInt(ValidatingDecoder.java:83)
    at org.apache.avro.generic.GenericDatumReader.readInt(GenericDatumReader.java:511)
    at org.apache.avro.generic.GenericDatumReader.readWithoutConversion(GenericDatumReader.java:182)
    at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:152)
    at org.apache.avro.generic.GenericDatumReader.readField(GenericDatumReader.java:240)
    at org.apache.avro.generic.GenericDatumReader.readRecord(GenericDatumReader.java:230)
    at org.apache.avro.generic.GenericDatumReader.readWithoutConversion(GenericDatumReader.java:174)
    at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:152)
    at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:144)
    at io.confluent.kafka.formatter.AvroMessageReader.jsonToAvro(AvroMessageReader.java:213)
    at io.confluent.kafka.formatter.AvroMessageReader.readMessage(AvroMessageReader.java:180)
    at kafka.tools.ConsoleProducer$.main(ConsoleProducer.scala:54)
    at kafka.tools.ConsoleProducer.main(ConsoleProducer.scala)

那么如何使用它来接受默认值呢?***配置设置为"BACKWARD" 兼容性级别检查,尽管我认为这与问题无关。此架构是版本 2,版本 1 仅使用 f1 字段定义,但正如我所说,我认为这并不重要。

【问题讨论】:

AFAIK,default 值仅适用于读者/消费者。该字段仍然需要由作者/制作者定义。 我已经投了这个有用的评论,如果你推荐它回答,我会接受它作为解决问题的,并且是最有用的。 @hdjur_jcv 我相信我的回答解释了如何做 cricket_007 所描述的事情。 嗨,Giorgos Myrianthous,我认为您的回答也很有用,对此我表示感谢,但我认为 cricket_007 的回答是正确的,因为它揭示了我的误解。从您的示例中可以看出,在生产者端启用空输入值并不意味着在消费者端使用默认的零值(这应该是我唯一的目标)。 【参考方案1】:

如Avro spec中所定义

default:此字段的默认值,在读取缺少此字段的实例时使用

因此,生产者仍然需要提供该字段。

我不确定在使用 Avro 控制台生成器时是否可以完全排除某个字段,因为即使您将该字段设置为像 Giorgos 显示的那样可以为空,您仍然需要显式设置它。

【讨论】:

【参考方案2】:

该错误表明该消息与您定义的 Avro 架构不兼容。据我了解,您希望为字段f2 允许null 值。为此,您需要将您的value.schema 更改为(注意"type" 的定义):

value.schema='"type":"record","name":"myrecord1","fields": ["name":"f1","type":"string","name": "f2", "type": ["null", "int"], "default": 0]' 

但您仍然需要使用 null 值定义 f2 键。以下应该可以为您解决问题:

kafka-avro-console-producer --broker-list localhost:9092 --topic test-avro \ 
    --property schema.registry.url=http://localhost:8081 \ 
    --property value.schema='"type":"record","name":"myrecord1","fields": ["name":"f1","type":"string","name": "f2", "type": ["null", "int"], "default": 0]'

"f1":"value1","f2":null 

您可以使用kafka-avro-console-consumer 确认这是否有效:

kafka-avro-console-consumer --bootstrap-server localhost:9092 --topic test-avro --from-beginning
"f1":"value1","f2":null
^CProcessed a total of 1 messages

【讨论】:

以上是关于为啥 kafka-avro-console-producer 不遵守该字段的默认值?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?

为啥 CAP 定理中的 RDBMS 分区不能容忍,为啥它可用?