【发布时间】:2013-11-15 18:29:19
【问题描述】:
我正在尝试处理一个非常大的 unicode 文本文件 (6GB+)。我想要的是计算每个唯一单词的频率。在遍历文件时,我使用严格的Data.Map 来跟踪每个单词的计数。
该过程需要太多时间和太多内存(20GB+)。我怀疑地图很大,但我不确定它应该达到文件大小的 5 倍!
代码如下所示。请注意,我尝试了以下方法:
使用
Data.HashMap.Strict代替Data.Map.Strict。Data.Map似乎在较慢的内存消耗增加率方面表现更好。-
使用惰性
ByteString而不是惰性Text读取文件。然后我将其编码为 Text 进行一些处理,然后将其编码回ByteStringforIO。import Data.Text.Lazy (Text(..), cons, pack, append) import qualified Data.Text.Lazy as T import qualified Data.Text.Lazy.IO as TI import Data.Map.Strict hiding (foldr, map, foldl') import System.Environment import System.IO import Data.Word dictionate :: [Text] -> Map Text Word16 dictionate = fromListWith (+) . (`zip` [1,1..]) main = do [file,out] <- getArgs h <- openFile file ReadMode hO <- openFile out WriteMode mapM_ (flip hSetEncoding utf8) [h,hO] txt <- TI.hGetContents h TI.hPutStr hO . T.unlines . map (uncurry ((. cons '\t' . pack . show) . append)) . toList . dictionate . T.words $ txt hFlush hO mapM_ hClose [h,hO] print "success"
我的方法有什么问题?就时间和内存性能而言,完成我想做的事情的最佳方法是什么?
【问题讨论】:
-
@leftaroundabout 让我们假设最坏的情况,文件中的所有单词都是唯一的。 Map 大小应该达到 30GB 吗?
-
我想是的,但对于
Map来说可能相当困难。如果您不希望单词中有太多重复,也许您应该完全切换到其他单词。 External merge sort(将重复计数和结块作为单独的步骤)相对简单。当然 anything external 必然会涉及到大量的脏 IO;我敢打赌,用 C 或 C++ 编写代码实际上更容易,这也让您可以更好地控制数据结构的开销。 -
一点也不奇怪,@duplode 只是使用了一个文本文件,其中的唯一词少了很多(自然语言不可避免,并且使用许多 same的副本也无济于事> text) 比你在文件中明显有的要多。
-
只是问一些愚蠢的问题:您正在使用
-O2进行编译,对吧? -
你可能会从使用
bytestring-trie之类的东西中获利
标签: haskell text hashmap bigdata file-processing