Próbuję napisać kod, aby wykonać następujące proste zadanie w Haskell: wyszukiwanie etymologii słów przy użyciu tego słownika, przechowywanych jako duży plik tsv (http://www1.icsi.berkeley.edu/~demelo/etymwn/). Pomyślałem, że przeanalizuję (z attoparsec) plik tsv w Mapie, który mógłbym następnie użyć do efektywnego zbadania etymologii, w zależności od potrzeb (i innych rzeczy).skutecznie czyta duży plik na mapie
To był mój kod:
{-# 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
To działa dla małych ilości danych wejściowych, ale szybko rośnie zbyt nieefektywne. Nie jestem całkiem pewien, na czym polega problem i szybko zdałem sobie sprawę, że nawet trywialne zadania, takie jak przeglądanie ostatniej postaci pliku, trwały zbyt długo, gdy próbowałem, np. z
foo = fmap DTL.last $ DTLIO.readFile "../../../../etymwn.tsv
Moje pytania są następujące: jakie są główne rzeczy, które robię źle, pod względem podejścia i wykonania? Wszelkie wskazówki, jak uzyskać lepszy/lepszy kod?
Dzięki,
Reuben
Czy profilowałeś swój kod? 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
Jeśli plik, który czytasz jest zbyt duży, dobrym rozwiązaniem, aby zmniejszyć czas uruchamiania programu, jest przeniesienie zawartości tego pliku do bazy danych (wbudowany lub nie). Po zaindeksowaniu w bazie danych wyszukiwania losowe mogą być wykonywane bezpośrednio, bez uprzedniego odczytu pliku. – fgv
Oprócz profilowania sugeruję przejrzenie tego krótkiego przewodnika dotyczącego zagadnień związanych z wydajnością: https://hackage.haskell.org/package/attoparsec-0.13.0.1/docs/Data-Attoparsec-ByteString.html#g:3 – erdeszt