Apache Avro: map使用CharSequence作为键

15

我正在使用Apache Avro

我的模式有map类型:

{"name": "MyData", 
  "type" :  {"type": "map", 
              "values":{
                   "type": "record",
                   "name": "Person",
                   "fields":[
                      {"name": "name", "type": "string"},
                      {"name": "age", "type": "int"},

                ]
                }
               }
}
编译模式后,生成的Java类将使用 CharSequence 作为 Map 的键 MyData。在 Apache Avro 中有没有一种方法可以生成 String 类型的键用于 Map 呢? P.S. 问题在于,例如 dataMap.containsKey("SOME_KEY") 将返回 false,即使存在这样的键,仅仅因为它是 CharSequence。此外,使用现有键添加 map 条目并不会替换旧条目。这就是我说使用 CharSequence 作为键不方便的原因。

根据您对一个回答的评论,您是否确切地找出了是什么导致了问题?也就是说,您得到的“Map”实际上是否使用了非“String”键? - millimoose
Millimoose,生成的Map使用CharSequence作为键。 - Mellon
生成的地图默认使用Utf8,您可以选择将其设置为String。CharSequence只是一个接口。 - Alex A.
6个回答

12
这个JIRA讨论是相关的。CharSequence仍然被使用的主要原因是向后兼容性。正如Charles Forsythe指出的那样,现在已经添加了一个解决方案,当需要使用String时,在模式中设置字符串属性即可。
 { "type": "string", "avro.java.string": "String" }

这里的默认类型是他们自己的Utf8类。除了手动指定和pom.xml设置之外,甚至还有一个用于它的avro-tools编译选项,即-string选项:

java -jar avro-tools.1.7.5.jar compile -string schema /path/to/schema .

9

显然,在Avro 1.6中有一个解决此问题的方法。您需要在项目的POM文件中指定字符串类型:

  <stringType>String</stringType>

这个问题在AVRO-803中提到...尽管插件的Web文档没有反映这一点。

根据该问题,更加令人气愤的是使用的CharSequence子类实际上是一个特定于Avro的类(Utf8),他们本可以将其变为可哈希/可比较的String以减轻一些痛苦。 - millimoose
这是一个很好的观点。如果还没有添加,这可能是Avro值得改变的地方。另一方面,CharSequence不能保证相等的行为,因此在这些情况下使用toString()可能更好。 - Alex A.
1
@millimoose 不,这是不可能的。你不能使用String使其工作,因为String首先要做的是检查传递的其他对象是否等于String。没有非字符串实现的CharSequence可以正确地与String进行hashCode/equals交互。 - Scott Carey

6
显然,默认情况下,Avro使用CharSequence。我发现一种将其配置为转换为String的方法
从Avro 1.6.0开始,有一个选项可以让Avro始终执行转换为String。有几种实现这个选项的方法。第一种方法是在模式中设置avro.java.string属性为String:
         { "type": "string", "avro.java.string": "String" }

我没有测试过这个。


这是正确的做法,而且这个属性存在是为了处理这个确切的问题。 - Alex A.
2
这是每个字段的配置吗?如何为地图键执行此操作? 另外,该链接已失效。 - andresp

4

无论是否可以强制 Avro 使用 String,直接使用 CharSequence 是一种糟糕的实现方式,因为 CharSequence 不是 Comparable<CharSequence>,甚至不指定两个相同序列的相等性。我建议将此作为错误报告提交给 Avro。


事实上,即使在一个相当琐碎的情况下(StringStringBuilder),哈希码也不匹配:http://ideone.com/cX76YN。(对于`StringBuffer`和`StringBuilder`,它们是匹配的,但这可能是因为后者大部分是前者的副本,同步已被删除。) - millimoose
@millimoose StringBufferStringBuilder 都扩展了包保护的 AbstractStringBuilder,因此它们的行为相似并不奇怪。同意这是一个实现问题。 - Charles Forsythe

4

我认为显式将字符串转换为Utf8格式会起作用。 "some_key" -> 新的 Utf8("some_key"),然后将其用作地图中的键。


-1

一个快速的解决方案(值类型可以是其他对象,现在我是):

Map<String, String> convertToStringMap(Map<CharSequence, CharSequence> map){
    if (null == map){
        return null;
    }
    HashMap<String, String> result = new  HashMap<String, String>();
    for(CharSequence key: map.keySet()){
        CharSequence k_value = map.get(key);
        String s_key = key.toString();
        String s_value = k_value.toString();
        result.put(s_key, s_value);
    }
    return result;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接