如何在ProtoBuf中有效地对HashMap/字典进行建模

我有一个由.NET代码序列化的protobuf文件,我想把它用到Java中。在 .NET 代码中,有字典数据类型,原型架构看起来像

message Pair {
   optional string key = 1;
   optional string value = 2;
}

message Dictionary {
   repeated Pair pairs = 1;
}

正如协议缓冲区中的堆栈溢出 post 字典中所述。

我可以使用protoc将proto文件编译成Java类。我可以成功地将protobuf文件反序列化为Java对象。唯一的问题是它在Java中转换为配对对象列表,而不是HashMap。当然,我仍然拥有所有数据,但我无法像我想要的那样有效地访问数据。如果我有键的值,我必须遍历整个列表才能获得其相应的值。这似乎不是最佳的。

我想知道是否有更好的方法来在原型中对字典/地图数据类型进行建模。

谢谢

更新:

我尝试了Jon Skeet的建议,在地址簿示例中添加地图类型字段,但仍然遇到了问题。

message Person {
  required string name = 1;
  required int32 id = 2;        // Unique ID number for this person.
  optional string email = 3;
  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }
  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }
  repeated PhoneNumber phone = 4;
  map<string, string> mapdata = 5;
}

原型在编译时引发错误

addressbook.proto:25:3: Expected "required", "optional", or "repeated".
addressbook.proto:25:6: Expected field name.

根据Google protobuf doc,proto 2确实支持地图类型 https://developers.google.com/protocol-buffers/docs/proto#maps。正如我引用的,

地图不能重复、可选或必需。

所以我真的不知道为什么protoc不能编译它。这里还有另一个讨论,必须为现有的原型创建java pojo,包括Map。答案表明,地图只是一个原型3特征。这与谷歌的文档相矛盾。


答案 1

好吧,从v3.0开始,“protobuf proper”中已经支持了地图。例如,您的原型实际上是:

message Dictionary {
    map<string, string> pairs = 1;
}

好消息是,使用您定义的键和值字段,这与您现有的数据完全向后兼容:)

坏消息是我不知道protobuf-net是否支持它。如果您实际上没有在.NET端使用该文件,并且以声明方式执行所有操作,则可能只需修改文件,重新生成Java代码,然后....proto.proto

剩下的坏消息是,在撰写本文时,地图是在v3.0中引入的,该版本仍处于alpha/beta阶段。现在,根据您需要交付的时间,您可能会决定在需要的时候发布v3.0 - 在我看来,拥有漂亮的地图语法的好处非常显着。目前所做的大多数更改都是围绕新的proto3功能进行的 - 而proto2语法文件中也允许映射...只是你需要v3.0编译器和运行时来使用它们。


答案 2