2012-06-23 3 views
10

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

Я пытаюсь использовать библиотеку злаков для этого, но, похоже, что тип данных HashMap должен получить Generic. Есть ли способ сделать это?

+0

В чем проблема с получением Generic? – Cubic

+1

Для получения Generic, для пользовательского типа, мы должны написать что-то вроде: 'Что-то данных = Something Int Int Generic' вытекающих Как это можно сделать, если тип данных в библиотеке на Hackage (кроме представления патч для сопровождающего библиотеки)? – donatello

+0

Хм ...Ну, я лично подозреваю, что Serializing HashMaps вроде бы не сработает, и вам придется использовать другую реализацию, которая поддерживает нужный тип сериализации, но позволяет увидеть, что говорят другие. – Cubic

ответ

0

В настоящее время невозможно сделать сериализацию HashMap без изменения самой библиотеки HashMap.

Невозможно сделать Data.HashMap экземпляром Generic (для использования с зерном) с использованием автономного вывода, как описано в ответе @ mergeconflict, поскольку Data.HashMap не экспортирует все его конструкторы (это требование для GHC).

Итак, единственное решение, оставшееся после сериализации HashMap, похоже, должно использовать интерфейс toList/fromList.

5

Возможно, вы сможете использовать stand-alone deriving, чтобы сгенерировать собственный экземпляр Generic для HashMap. Вероятно, вы получите предупреждение о orphan instances, но вам также, наверное, все равно :) Во всяком случае, я не пробовал это, но это, вероятно, стоит сделать ...

+2

Я думаю, что это хороший ответ. Еще один момент, возможно, заключается в том, как избежать появления сиротских экземпляров: просто определите newtype, обертывающий HashMap и определите экземпляр для этого типа. Когда вам нужно сериализовать HashMap, просто оберните его в свой тип и выполните сериализацию. – Tener

+0

@mergeconflict, @Tener Я добавил строку: 'производный экземпляр (Generic k, Generic v) => Generic (H.HashMap kv)' Но GHC жалуется, что все конструкторы данных HashMap не входят в объем (т.е. [они не все экспортированы] (http://hackage.haskell.org/packages/archive/unordered-containers/0.2.1.0/doc/html/src/Data-HashMap-Base.html#HashMap)). Похоже, что такой подход не будет работать в конце концов. donatello

+0

@donatello Bummer :( – mergeconflict

1

Я не уверен, что если использовать Generics is лучший снимок при достижении высокой производительности. Моя лучшая ставка будет на самом деле писать свой собственный экземпляр для Сериализуемый как это:

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.

0

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

{-# 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