Sto cercando di scrivere codice per eseguire il seguente semplice compito in Haskell: cercare le etimologie delle parole usando questo dizionario, memorizzato come un file tsv di grandi dimensioni (http://www1.icsi.berkeley.edu/~demelo/etymwn/). Ho pensato di analizzare (con attoparsec) il file tsv in una mappa, che potrei quindi utilizzare per cercare in modo efficiente l'etimologia, come richiesto (e fare altre cose con).lettura efficiente di un file di grandi dimensioni in una mappa
Questo è stato il mio codice:
{-# LANGUAGE OverloadedStrings #-}
import Control.Arrow
import qualified Data.Map as M
import Control.Applicative
import qualified Data.Text as DT
import qualified Data.Text.Lazy.IO as DTLIO
import qualified Data.Text.Lazy as DTL
import qualified Data.Attoparsec.Text.Lazy as ATL
import Data.Monoid
text = do
x <- DTLIO.readFile "../../../../etymwn.tsv"
return $ DTL.take 10000 x
--parsers
wordpair = do
x <- ATL.takeTill (== ':')
ATL.char ':' *> (ATL.many' $ ATL.char ' ')
y <- ATL.takeTill (\x -> x `elem` ['\t','\n'])
ATL.char '\n' <|> ATL.char '\t'
return (x,y)
--line of file
line = do
a <- (ATL.count 3 wordpair)
case (rel (a !! 2)) of
True -> return . (\[a,b,c] -> [(a,c)]) $ a
False -> return . (\[a,b,c] -> [(c,a)]) $ a
where rel x = if x == ("rel","etymological_origin_of") then False else True
tsv = do
x <- ATL.many1 line
return $ fmap M.fromList x
main = (putStrLn . show . ATL.parse tsv) =<< text
Si lavora per piccole quantità di ingresso, ma rapidamente cresce troppo inefficiente. Non sono del tutto chiaro su quale sia il problema, e presto mi sono reso conto che anche compiti banali come la visualizzazione dell'ultimo carattere del file richiedevano troppo tempo quando ho provato, ad es. con
foo = fmap DTL.last $ DTLIO.readFile "../../../../etymwn.tsv
Quindi le mie domande sono: quali sono le cose principali che sto sbagliando, in termini di approccio ed esecuzione? Qualche consiglio per più codice Haskelly/migliore?
Grazie,
Reuben
Hai profilato il tuo codice? https://nikita-volkov.github.io/profiling-cabal-projects/ https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/prof-heap.html http://book.realworldhaskell.org/read/profiling-and-optimization.html – grwp
Se il file che stai leggendo è troppo grande, una buona opzione per ridurre il tempo di avvio del programma è spostare il contenuto di quel file in un database (incorporato o non). Una volta indicizzati nel database, le ricerche casuali possono essere eseguite direttamente senza prima leggere il file in ordine sequenziale. – fgv
Oltre alla profilazione, suggerisco di consultare questa breve guida sulle considerazioni sulle prestazioni: https://hackage.haskell.org/package/attoparsec-0.13.0.1/docs/Data-Attoparsec-ByteString.html#g:3 – erdeszt