Attoparsec:Begriffe in Klammern überspringen?
-
13-12-2019 - |
Frage
Ich versuche, große TSV-Dateien mit JSON in der 5. Spalte für den Import in MongoDB geeignet zu machen.Insbesondere möchte ich die Schlüsselfelder der obersten Ebene und nur der obersten Ebene in _id ändern.Das habe ich bisher, es scheint zu funktionieren, ist aber langsam:
{-# LANGUAGE OverloadedStrings #-}
import System.Environment (getArgs)
import Data.Conduit.Binary (sourceFile, sinkFile)
import Data.Conduit
import qualified Data.Conduit.Text as CT
import qualified Data.Conduit.List as CL
import qualified Data.Text as T
import Data.Monoid ((<>))
import Data.Attoparsec.Text as APT
import Control.Applicative
main = do
(inputFile : outputFile : _) <- getArgs
runResourceT $ sourceFile inputFile
$= CT.decode CT.utf8 $= CT.lines $= CL.map jsonify
$= CT.encode CT.utf8 $$ sinkFile outputFile
jsonify :: T.Text -> T.Text
jsonify = go . T.splitOn "\t"
where
go (_ : _ : _ : _ : content : _) = case parseOnly keyTo_id content of
Right res -> res <> "\n"
_ -> ""
go _ = ""
keyTo_id :: Parser T.Text
keyTo_id = skipWhile(/='{') >> T.snoc <$>
(T.cons <$> (char '{')
<*> (T.concat <$> many1 ( bracket
<|> (string "\"key\":" >> return "\"_id\":")
<|> APT.takeWhile1(\x -> x /= '{' && x /= '}' && x/= '"')
<|> T.singleton <$> satisfy (/= '}')
)))
<*> char '}'
bracket :: Parser T.Text
bracket = T.cons <$> char '{'
<*> scan 1 test
where
test :: Int -> Char -> Maybe Int
test 0 _ = Nothing
test i '}'= Just (i-1)
test i '{' = Just (i+1)
test i _ = Just i
Laut Profiler werden 58,7% der Zeit in Klammern verbracht, 19,6% in keyTo_id, 17,1% in main.
Sicherlich gibt es eine bessere Möglichkeit, eingeklammerte Begriffe unverändert zurückzugeben, wenn die Klammern übereinstimmen?
Ich habe mir kurz attoparsec-conduit angesehen, aber ich habe keine Ahnung, wie ich diese Bibliothek verwenden soll, und kann nicht einmal sagen, ob dies die Art von Dingen ist, für die sie verwendet werden kann.
BEARBEITEN:Den Code aktualisiert.Die Daten stammen von openlibrary.org , e.g. http://openlibrary.org/data/ol_dump_authors_latest.txt.gz
Lösung
Verwenden Sie die scan
Funktion.Es ermöglicht Ihnen, über eine Zeichenfolge zu scannen, die einen Status verwaltet.In Ihrem Fall ist der Status eine Zahl - der Unterschied zwischen dem Öffnen und Schließen von Klammern, auf den Sie bisher gestoßen sind.Wenn Ihr Status 0 ist, bedeutet dies, dass geschweifte Klammern innerhalb der aktuellen Teilzeichenfolge übereinstimmen.
Der Trick ist, dass Sie die Saite nicht auf diese Weise dekonstruieren und rekonstruieren, also sollte sie schneller sein.
Außerdem könnten Sie auch mit Ihrem aktuellen Algorithmus etwas Leistung erzielen, indem Sie Lazy Text verwenden - the concat
funktion würde effizienter arbeiten.