我有一个包含数百万条目的大型哈希表,我想将其持久化到磁盘上,这样当再次从磁盘读取它时,就不需要再将键值对插入回哈希表中,以减少开销。
我尝试使用cereal库来实现这个目的,但似乎HashMap数据类型需要派生一个通用类型。有没有办法解决这个问题?
我有一个包含数百万条目的大型哈希表,我想将其持久化到磁盘上,这样当再次从磁盘读取它时,就不需要再将键值对插入回哈希表中,以减少开销。
我尝试使用cereal库来实现这个目的,但似乎HashMap数据类型需要派生一个通用类型。有没有办法解决这个问题?
deriving instance (Generic k, Generic v) => Generic (H.HashMap k v)
。但是 GHC 报错说 HashMap 的所有数据构造函数不在作用域内(即 它们并不都被导出)。看起来这种方法行不通啊,<叹气>。 - donatello我不确定使用泛型是否是实现高性能的最佳选择。我的最佳建议实际上是编写自己的Serializable实例,就像这样:
instance (Serializable a) => Serializable (HashMap a) where
...
newtype SerializableHashMap a = SerializableHashMap { toHashMap :: HashMap a }
instance (Serializable a) => SerializableHashMap a where
...
...
?toList
/fromList
函数并存储/读取HashMap
的大小。目前,没有办法在不修改HashMap库本身的情况下使其可序列化。
无法使用@mergeconflict答案中描述的独立派生方式将Data.HashMap作为Generic的实例(用于cereal),因为Data.HashMap未导出所有构造函数(这是GHC的要求)。
因此,似乎唯一的序列化HashMap的解决方案是使用toList/fromList接口。
{-# 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
data Something = Something Int Int deriving Generic
如果数据类型在Hackage库中(除了向库维护者提交补丁之外),该怎么做呢? - donatelloMap
,它对我来说性能足够好。 - Michael Fox