我有一个 279MB 的文件,其中包含约 1000 万个键/值对,以及约 500,000 个唯一键。它按键分组(每个键只需要编写一次),因此给定键的所有值都在一起。
我想要做的是转置关联,创建一个文件,其中对按值分组,并且给定值的所有键都存储在一起。
目前,我正在使用 Parsec 将成对作为元组列表读取(K,[V])
(使用惰性 IO,因此我可以在 Parsec 处理输入文件时将其作为流处理),其中:
newtype K = K Text deriving (Show, Eq, Ord, Hashable)
newtype V = V Text deriving (Show, Eq, Ord, Hashable)
tupleParser :: Parser (K,[V])
tupleParser = ...
data ErrList e a = Cons a (ErrList e a) | End | Err e
parseAllFromFile :: Parser a -> FilePath-> IO (ErrList ParseError a)
parseAllFromFile parser inputFile = do
contents <- readFile inputFile
let Right initialState = parse getParserState inputFile contents
return $ loop initialState
where loop state = case unconsume $ runParsecT parser' state of
Error err -> Err err
Ok Nothing _ _ -> End
Ok (Just a) state' _ -> a `Cons` loop state'
unconsume v = runIdentity $ case runIdentity v of
Consumed ma -> ma
Empty ma -> ma
parser' = (Just <$> parser) <|> (const Nothing <$> eof)
我试图将元组插入到 aData.HashMap.Map V [K]
中以转置关联:
transpose :: ErrList ParseError (K,[V]) -> Either ParseError [(V,[K])]
transpose = transpose' M.empty
where transpose' _ (Err e) = Left e
transpose' m End = Right $ assocs m
transpose' m (Cons (k,vs) xs) = transpose' (L.foldl' (include k) m vs) xs
include k m v = M.insertWith (const (k:)) v [k] m
但是当我尝试它时,我得到了错误:
memory allocation failed (requested 2097152 bytes)
我可以想到几件事我做错了:
- 2MB 似乎有点低(远小于我机器安装的 2GB RAM),所以也许我需要告诉 GHC 可以使用更多?
- 我的问题可能与算法/数据结构有关。也许我使用了错误的工具来完成这项工作?
- 我尝试使用惰性 IO 可能会回来咬我。
我现在倾向于(1),但我不确定。