Как сериализовать/десериализовать хэш-карту?
У меня есть большой хэш файл, содержащий миллионы записей, и я хочу сохранить его на диске, так что, когда он снова считывается с диска, у меня нет накладных расходов на вставку пар ключ-значение обратно в снова отобразите карту.
Я пытаюсь использовать библиотеку злаков, чтобы сделать это, но похоже, что тип данных HashMap должен получить Generic. Есть ли способ сделать это?
Ответы
Ответ 1
В настоящее время невозможно сделать сериализацию HashMap без изменения самой библиотеки HashMap.
Невозможно сделать Data.HashMap экземпляром Generic (для использования с зерном) с использованием автономного вывода, как описано в ответе @mergeconflict, поскольку Data.HashMap не экспортирует все его конструкторы (это требование для GHC).
Таким образом, единственным решением, оставшимся после сериализации HashMap, является использование интерфейса toList/fromList.
Ответ 2
Возможно, вы сможете использовать автономное получение для создания собственного экземпляра Generic
для HashMap
. Вероятно, вы получите предупреждение о сиротских экземплярах, но вам также, вероятно, все равно:) Во всяком случае, я не пробовал это, но это, вероятно, стоит того...
Ответ 3
Я не уверен, что использование Generics - лучший способ добиться высокой производительности. Лучше всего на самом деле написать собственный экземпляр для 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
.
Другой (который будет похож на использование Generics) будет заключаться в написании прямой сериализации на основе внутренней структуры HashMap. Учитывая тот факт, что вы действительно не экспортировали внутренности, это было бы работой только для Generics.
Ответ 4
Если вы можете использовать двоичный код, существуют двоичные-сироты, которые предоставляют экземпляры для неупорядоченных контейнеров. Я не мог установить двоичных сирот из-за какого-то конфликта с кабкой, но просто хватал нужные мне части, например:
{-# 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
Ответ 5
Пакет CerealPlus предоставляет определение Serialize для строгих HashMaps.
http://hackage.haskell.org/package/cereal-plus