如何使用ruby-msgpack gem存储32位浮点数?
我正在研究一个需要存储大量简单,可扩展数据的数据系统(以及我们在内部开发的一些专业索引,而不是这个问题的一部分).我希望存储数十亿条记录,因此高效的序列化是系统的关键部分.序列化需要快速,节省空间,并且支持多种平台和语言(因为打包和解包这些数据将是客户端组件的责任,而不是存储系统的一部分)
数据类型实际上是具有可选键/值对的散列.键将是小整数(在应用程序层解释).值可以是各种简单数据类型 – String,Integer,Float. 作为一种技术选择,我们选择了MessagePack,我正在编写代码来通过Ruby的msgpack-ruby gem进行数据序列化. 我不需要Ruby的64位Float的精度.即使对于32位的限制,存储的数字也没有任何有意义的精度.所以我想使用MessagePack支持32位浮点值.这肯定存在.但是,Ruby在任何64位系统上的默认行为是将Float序列化为64位: MessagePack.pack(10.3) => "xCB@$x99x99x99x99x99x9A" 看看MessagePack代码,似乎有一个方法 MessagePack::DefaultFactory.packer.write_float32(10.3).to_s => "xCAA$xCCxCD" . . .但我找不到设置默认打包器或创建新打包器的方法,在序列化更大的结构时将使用此方法. 作为对我的理解的考验,我尝试了这个: class Float def to_msgpack_ext packer.write_float32(self) end def self.from_msgpack_ext s unpacker.read(s) end end MessagePack::DefaultFactory.register_type(0,Float ) MessagePack.pack(10.3) => "xCB@$x99x99x99x99x99x9A" 没有任何区别. . .很明显,我对MessagePack中使用的对象模型缺失或误解.我想做什么,我需要做什么? 解决方法
我知道使用MessagePack.pack会很好,但Ruby shim非常薄.它几乎没有为您提供进入C(或Java)库的入口点.正如AnoE指出的那样,我认为你只能为注册类型定制to_msgpack_ext和self.from_msgpack_ext,而不是内置类型.
您尝试的另一个问题是您无法从这些方法访问打包程序和解包程序.我想,你必须使用Array#pack和String#unpack,即使你能找到一种方法让你的库调用你的方法.要获得打包程序的句柄,您必须覆盖不同的方法: class Float private def to_msgpack_with_packer(packer) packer.write_float32 self packer end end 然后适当地调用它(参见this code为什么): 10.3.to_msgpack(MessagePack::Packer.new).to_s # => "xCAA$xCCxCD" 但是,当你在一个包含float的Hash上调用#to_msgpack时,这就会崩溃;它只是恢复其内部方法来打包哈希键和值.这就是为什么我在上面说过Ruby shim只给你一个入口点:核心扩展只用于初始调用. 我认为最好,最简单的解决方案是编写一个小的序列化函数,迭代Ruby中的哈希值,使用MessagePack::Packer API在看到浮点数时做你想做的事情等等.零C-hacking,零猴子修补,零混淆有人试图在六个月内阅读你的代码. def pack_float32(obj,packer=MessagePack::Packer.new) case obj when Hash packer.write_map_header(obj.size) obj.each_pair do |key,value| pack_float32(value,pack_float32(key,packer)) end when Enumerable packer.write_array_header(obj.size) obj.each do |value| pack_float32(value,packer) end when Float packer.write_float32(obj) else packer.write(obj) end packer end pack_float32(1=>[10.3]).to_s # => "x81x01x91xCAA$xCCxCD" 显然,这并没有经过严格测试,它可能无法处理所有边缘情况,但希望它足以让你开始. 另一个注意事项:您不必担心打开包装. msgpack-ruby似乎正确地将32位浮点数打包到64位浮点数,而我们没有任何摆弄. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |