【问题标题】:Avro and java: deserialized map of string doesn't "equals" original mapAvro 和 java:字符串的反序列化映射不“等于”原始映射
【发布时间】:2013-03-19 10:21:33
【问题描述】:

我正在使用由字符串和映射组成的简单记录来测试 Avro for java。这是我的架构:

{
  "type":"record",
  "name":"TableRecord",
  "fields":[
    {"name":"ActionCode","type":"string"},
    {
      "name":"Fields",
      "type":{"type":"map","values":["string","long","double","null"]}
    }
  ]
}

这是一个非常简单但失败的测试用例:

@Test
public void testSingleMapSerialization() throws IOException {
    final String schemaStr; // see above

    // create some data
    Map<String, Object> originalMap = new Hashtable<>();
    originalMap.put("Ric", "sZwmXAdYKv");
    originalMap.put("QuoteId", 4342740204922826921L);
    originalMap.put("CompanyName", "8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ");
    originalMap.put("Category", "AvrIfd");

    // serialize data
    Schema.Parser parser = new Schema.Parser();
    Schema schema = parser.parse(schemaStr);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    DatumWriter<GenericRecord> writer = new GenericDatumWriter<>(schema);
    Encoder encoder = EncoderFactory.get().binaryEncoder(out, null);
    GenericRecord datum = new GenericData.Record(schema);
    datum.put("ActionCode", "R");
    datum.put("Map", originalMap);
    writer.write(datum, encoder);
    encoder.flush();
    out.flush();

    // deserialize data
    DatumReader<GenericRecord> reader = new GenericDatumReader<>(schema);
    Decoder decoder = DecoderFactory.get().binaryDecoder(out.toByteArray(), null);
    datum = new GenericData.Record(schema);
    Map<String, Object> deserializedMap = (Map<String, Object>) reader.read(datum, decoder).get("Map");
    System.out.println(originalMap);
    System.out.println(deserializedMap);
    Assert.assertEquals("Maps data don't match", originalMap, deserializedMap);
}

这是测试的输出:

{CompanyName=8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric=sZwmXAdYKv, Category=AvrIfd, QuoteId=4342740204922826921}
{QuoteId=4342740204922826921, Category=AvrIfd, CompanyName=8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric=sZwmXAdYKv}

java.lang.AssertionError: Maps data don't match expected:<{CompanyName=8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric=sZwmXAdYKv, Category=AvrIfd, QuoteId=4342740204922826921}> but was:<{QuoteId=4342740204922826921, Category=AvrIfd, CompanyName=8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric=sZwmXAdYKv}>

如您所见,两张地图看起来相同,但测试失败。 JUnit 在幕后调用“equals”方法,这应该返回 true。顺便说一句,如果您想知道什么是胡言乱语,我通常会使用随机生成的数据创建测试用例,这就是它的来源。

我做错了吗?我不知道字符串序列化/反序列化有什么问题吗?我在网上搜索没有成功。

想法?

谢谢

乔杜德

【问题讨论】:

  • 我不这么认为。只需尝试创建两个具有相同内容的哈希表并进行比较。你会得到真实的。这是 java.util.Map 的 equals 方法的 javadoc:“将指定对象与此映射进行比较是否相等。如果给定对象也是映射并且两个映射表示相同的映射,则返回 true。更正式地说,两个映射 m1如果 m1.entrySet().equals(m2.entrySet()) 和 m2 表示相同的映射。这确保了 equals 方法在 Map 接口的不同实现中正常工作。"
  • 由于 entrySet() 返回一个 Set,这里是 Set 的 equals 方法的 javadoc:“比较指定的对象和这个 set 是否相等。如果指定的对象也是一个 set,则返回 true,这两个集合具有相同的大小,并且指定集合的​​每个成员都包含在这个集合中(或者等效地,这个集合的每个成员都包含在指定集合中)。这个定义确保了 equals 方法在集合的不同实现中正常工作界面。”
  • 能不能一一浏览map的入口集,看看哪个不相等?
  • deserializedMap 是否有可能是一个未实现的 avro Map 实现。 equals() 正确吗?

标签: java string serialization utf-8 avro


【解决方案1】:

我弄清楚了“捕获”是什么。我正在将包含java.lang.Strings 的地图与包含org.apache.avro.util.Utf8 的地图进行比较。事实证明,如果与字符串一起使用,Utf8 equals 方法将不起作用。我通过在我的测试用例中添加以下内容来实现这一点:

for (Object o : deserializedMap.values())
  System.out.println(o.getClass());
for (Object o : deserializedMap.keySet())
  System.out.println(o.getClass());

打印以下内容:

class java.lang.Long
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8

我想这是意料之中的,因为 Avro 总是将字符串转换为其本机 Utf8 类型。我以为它会按原样复制我的地图,但事实并非如此。奇怪的是,类型转换为 Map 成功,我不清楚这是怎么发生的。

【讨论】:

  • 转换为 Map 忽略模板参数,因为该信息在运行时不可用。编译器应该能够给你一个警告。
【解决方案2】:

是的,从 1.5 开始,Avro 映射使用 org.apache.avro.util.Utf8 作为默认键,并且可以更改为字符串。更多详情可以参考:https://issues.apache.org/jira/browse/AVRO-803Apache Avro: map uses CharSequence as key

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 2015-04-10
    • 1970-01-01
    • 2014-10-15
    • 2011-05-29
    相关资源
    最近更新 更多