У меня есть файл размером 279 МБ, который содержит ~10 миллионов пар ключ/значение с ~500 000 уникальных ключей. Он сгруппирован по ключу (каждый ключ нужно записать только один раз), поэтому все значения для данного ключа находятся вместе.
Что я хочу сделать, так это перенести ассоциацию, создать файл, в котором пары сгруппированы по значению, а все ключи для данного значения хранятся вместе.
В настоящее время я использую Parsec для чтения пар в виде списка кортежей (K,[V])
(используя ленивый ввод-вывод, поэтому я могу обрабатывать его как поток, пока 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)
Я попытался вставить кортежи в Data.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)
Я мог бы подумать о паре вещей, которые я делаю неправильно:
- 2 МБ кажется маловато (значительно меньше 2 ГБ ОЗУ, установленных на моей машине), так что, может быть, мне нужно сказать GHC, что можно использовать больше?
- Мои проблемы могут быть связаны с алгоритмами/структурой данных. Может быть, я использую неправильные инструменты для работы?
- Моя попытка использовать ленивый ввод-вывод может обернуться против меня.
Я склоняюсь к (1) на данный момент, но я никоим образом не уверен.
+RTS -sstderr -RTS
- это работает, когда яC-c
останавливаю исполняемый файл досрочно, но если я жду возникновения ошибки, информация о профилировании не печатается. Любые предложения о том, как сообщить об объеме памяти во время ошибки? - person rampion   schedule 06.12.2012transpose' m (Cons (k,vs) xs) = transpose' (L.foldl' (include k) m vs) xs
создаст огромные санки, так какtranspose'
не является строгим в аргументеMap
, поэтомуfoldl'
не будет оцениваться до конца. Сделатьtranspose'
строгим в аргументеMap
может быть достаточно, но, возможно, потребуется больше. - person Daniel Fischer   schedule 06.12.2012(K,[V])
из файла за раз и вставлять его в свою карту, только сErrList
, действующим как промежуточный поток, чтобы я мог разделить проблемы. Но, возможно, я терплю неудачу в этом. - person rampion   schedule 06.12.2012transpose'
строгим в аргументе карты, то мне потребовалось гораздо больше времени, пока я не достиг сбоя памяти. - person rampion   schedule 07.12.2012HashMap
, а сколько потрачено впустую. - person rampion   schedule 08.12.2012tar
отредактировал иgzip
отредактировал, и загрузил сюда. Этоcategory
в строке, за которым следует ноль или более строкrank. url
. Я даю немного больше деталей в моем коде. - person rampion   schedule 25.02.2013