我有一个包含数百万个条目的大型哈希图,我想将它持久化到磁盘,这样当再次从磁盘读取它时,我没有将键值对再次插入映射的开销。
我正在尝试使用谷物库来执行此操作,但似乎HashMap数据类型需要派生通用。有没有办法做到这一点?
我有一个包含数百万个条目的大型哈希图,我想将它持久化到磁盘,这样当再次从磁盘读取它时,我没有将键值对再次插入映射的开销。
我正在尝试使用谷物库来执行此操作,但似乎HashMap数据类型需要派生通用。有没有办法做到这一点?
我不确定使用泛型是否是实现高性能的最佳方法。我最好的选择实际上是为 Serializable 编写自己的实例,如下所示:
instance (Serializable a) => Serializable (HashMap a) where
...
为避免创建孤立实例,您可以使用 newtype 技巧:
newtype SerializableHashMap a = SerializableHashMap { toHashMap :: HashMap a }
instance (Serializable a) => SerializableHashMap a where
...
问题是如何定义...
?
在您实际尝试实施和对可能的解决方案进行基准测试之前,没有明确的答案。
一种可能的解决方案是使用toList
/fromList
函数并存储/读取HashMap
.
另一个(类似于使用泛型)是基于内部 HashMap 结构编写直接序列化。鉴于您实际上并没有导出内部结构,这仅适用于泛型。
目前,在不修改 HashMap 库本身的情况下,无法使 HashMap 可序列化。
正如@mergeconflict 的回答所描述的那样,使用独立派生无法使 Data.HashMap 成为 Generic 的实例(用于谷物),因为 Data.HashMap 不会导出其所有构造函数(这是 GHC 的要求)。
因此,序列化 HashMap 的唯一解决方案似乎是使用 toList/fromList 接口。
如果您可以使用二进制,则可以使用 binary-orphans 为无序容器提供实例。由于一些阴谋集团的冲突,我无法安装二进制孤儿,但只是抢走了我需要的部分,例如:
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
module Bin where
import Data.Binary
import Data.ByteString.Lazy.Internal
import Data.Hashable (Hashable)
import qualified Data.HashMap.Strict as M
import qualified Data.Text as T
#if !(MIN_VERSION_text(1,2,1))
import Data.Text.Binary ()
#endif
instance (Hashable k, Eq k, Binary k, Binary v) => Binary (M.HashMap k v) where
get = fmap M.fromList get
put = put . M.toList
-- Note: plain `encode M.fromList []` without type annotations won't work
encodeModel :: M.HashMap T.Text Int -> ByteString
encodeModel m =
encode m
CerealPlus 包为严格的 HashMap 提供了 Serialize 的定义。