我正在尝试在第5列中使用JSON制作适合导入到mongoDB的大型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%的时间花在括号上,19.6%用于keyTo_id,17.1%用于主要。
如果括号匹配,肯定有更好的方法可以保持括号中的术语不变吗?
我简单地看了一下attoparsec-conduit,但我不知道如何使用该库,甚至无法判断这是否可以用于它。
编辑:更新了代码。数据来自openlibrary.org,e。 G。 http://openlibrary.org/data/ol_dump_authors_latest.txt.gz
答案 0 :(得分:2)
使用scan
功能。它允许您扫描维护状态的字符串。在你的情况下,状态将是一个数字 - 你到目前为止遇到的开始和结束括号的差异。
当状态为0时,这意味着大括号在当前子字符串内匹配。
诀窍在于你不会以这种方式解构和重构字符串,所以它应该更快。
此外,即使使用当前算法,您也可以通过使用惰性文本获得一些性能 - concat
函数可以更有效地工作。