Question

J'essaie de créer de gros fichiers TSV avec JSON dans la 5ème colonne adaptés à l'importation dans mongoDB.En particulier, je souhaite modifier les champs clés de niveau supérieur et uniquement de niveau supérieur en _id.Voici ce que j'ai jusqu'à présent, cela semble fonctionner mais c'est lent :

{-# 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

Selon le profileur, 58,7% du temps est passé en bracket, 19,6% en keyTo_id, 17,1% en main.

Il existe sûrement un meilleur moyen de renvoyer les termes entre parenthèses inchangés si les parenthèses correspondent ?

J'ai brièvement regardé attoparsec-conduit, mais je n'ai aucune idée de comment utiliser cette bibliothèque et je ne peux même pas dire si c'est le genre de chose pour laquelle elle peut être utilisée.

MODIFIER:Mise à jour du code.Les données proviennent d'openlibrary.org, par ex.g. http://openlibrary.org/data/ol_dump_authors_latest.txt.gz

Était-ce utile?

La solution

Utilisez le scan fonction.Il vous permet de parcourir une chaîne en conservant un état.Dans votre cas, l'état sera un nombre - la différence entre les accolades ouvrantes et fermantes que vous avez rencontrées jusqu'à présent.Lorsque votre état est 0, cela signifie que les accolades correspondent à l'intérieur de la sous-chaîne actuelle.

L'astuce est que vous ne déconstruisez pas et ne reconstruisez pas la chaîne de cette façon, cela devrait donc être plus rapide.

En outre, vous pourriez gagner en performances même avec votre algorithme actuel en utilisant du texte paresseux - le concat la fonction fonctionnerait plus efficacement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top