httpSink 和解析 json

httpSink and parsing json

我认为这对我来说有点高级,但我的目标是从 http API 获取原始 json,从中解析第一个列表,做任何我需要的这样做然后转到下一个列表,依此类推。我希望这应该允许一次只将一个列表加载到内存中(每个列表都非常小,但是 json 中有很多列表)。 我用 Aeson 试过,它吃光了所有的 ram 并无休止地处理了几个小时,我最终不得不杀死它。

如果我理解正确,httpSink 应该是可行的方法,也许 json-stream 可以进行实际的解析。我阅读了有关管道的教程,但我显然没有正确理解它,因为我无法做到这一点。

我知道如何使用 parseByteString 以我需要的方式解码 ByteString(至少我的测试似乎有效),但我想不出将 parseByteString 用作 httpSink 第二个参数的 Sink 的方法。 我是否遗漏了一些明显的东西,或者我是否误解了管道的工作方式?

谢谢

您写道:

I read the tutorial about conduits, but I'm clearly not understanding it properly since I can't make that work.

I can't figure out a way to use parseByteString as a Sink for httpSink's second parameter.

这里的问题是 Sink 只是管道的简称:

type Sink i m r = ConduitM i Void m r

Sink 是一种没有下游组件的管道。

管道是您需要的解决方案,我假设 this 是您阅读的教程。如果您对其中的某些概念不满意,请尝试提出一个具体问题。

我还没有测试过这个,因为老实说我对这个库不太熟悉,但我认为这个适配器函数可以让它与管道一起工作:

module Data.JsonStream.Parser.Conduit
  ( jsonConduit
  , JsonStreamException (..)
  ) where

import Data.Conduit
import Data.JsonStream.Parser
import Data.ByteString (ByteString)
import Control.Monad.Catch
import Data.Typeable

jsonConduit
  :: MonadThrow m
  => Parser a
  -> ConduitM ByteString a m ()
jsonConduit =
    go . runParser
  where
    go (ParseYield x p) = yield x >> go p
    go (ParseNeedData f) = await >>= maybe
      (throwM JsonStreamNotEnoughData)
      (go . f)
    go (ParseFailed str) = throwM $ JsonStreamException str
    go (ParseDone bs) = leftover bs

data JsonStreamException
  = JsonStreamException !String
  | JsonStreamNotEnoughData
  deriving (Show, Typeable)
instance Exception JsonStreamException