AttoParsec:括弧付きの用語をスキップ?
-
13-12-2019 - |
質問
MongoDBへの輸入に適した5列目のJSONを持つ大きなTSVファイルを作成しようとしています。 特に、トップレベルと最上位キーフィールドのみを_IDに変更します。これは私がこれまでに持っているものです、それはうまくいくようですが遅い:
{-# 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
.
プロファイラーに従って、58.7%の時間は括弧内に費やされ、keyto_idの19.6%、メインの17.1%。
大括弧が一致した場合、括弧付きの用語を変更するのは良い方法がありますか?
私はattoparsec-conduitを簡単に見たが、そのライブラリの使い方はどのように使いやすく、それが使われることができるのかどうかを言うことさえできません。
編集:コードを更新しました。データはOpenLibrary.org、eからです。g。 http://openlibrary.org/data/ol_dump_authors_latest.txt.gz
解決
scan
関数を使用します。状態をメイン管理する文字列をスキャンできます。あなたの場合には、状態は数値になります - これまでに遭遇したのが遭遇したカレンの開閉の違いです。
あなたの状態が0のとき、それはブレースが現在の部分文字列内に一致することを意味します。
トリックはあなたがこのように分解して文字列を再構築しないので、それは速くなるべきです。
また、遅延テキストを使用して現在のアルゴリズムでも、パフォーマンスを得ることができます.concat
関数はより効率的に機能します。
所属していません StackOverflow