Как сериализовать/десериализовать хэш-карту?

У меня есть большой хэш файл, содержащий миллионы записей, и я хочу сохранить его на диске, так что, когда он снова считывается с диска, у меня нет накладных расходов на вставку пар ключ-значение обратно в снова отобразите карту.

Я пытаюсь использовать библиотеку злаков, чтобы сделать это, но похоже, что тип данных 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