Clojure/Java:在AmazonS3数据流上执行复杂操作时最小化带宽消耗的最有效方法

Clojure/Java:在AmazonS3数据流上执行复杂操作时最小化带宽消耗的最有效方法,java,clojure,amazon-s3,bufferedreader,lazy-sequences,Java,Clojure,Amazon S3,Bufferedreader,Lazy Sequences,我正在使用BufferedReader执行对象的流式读取 我需要对这个对象做两件事: 将其传递给超级SV csv阅读器 获取原始行并将它们保持在(Clojure)惰性序列中 目前,我不得不使用两个不同的BufferedReader:一个作为SuperCSV CSV reader类的参数,另一个用于初始化原始行的惰性序列。我实际上下载了两次S3对象,这既昂贵($)又慢 我的一位同事指出,我正在寻找类似于Unix“tee”命令的东西。一个BufferedReader可能会以某种方式被“拆分”,下载一

我正在使用BufferedReader执行对象的流式读取

我需要对这个对象做两件事:

  • 将其传递给超级SV csv阅读器
  • 获取原始行并将它们保持在(Clojure)惰性序列中
  • 目前,我不得不使用两个不同的BufferedReader:一个作为SuperCSV CSV reader类的参数,另一个用于初始化原始行的惰性序列。我实际上下载了两次S3对象,这既昂贵($)又慢

    我的一位同事指出,我正在寻找类似于Unix“tee”命令的东西。一个BufferedReader可能会以某种方式被“拆分”,下载一块数据,并将副本传递给惰性序列和csv阅读器功能,这将非常有用

    我目前还在研究是否可以将惰性序列包装在BufferedReader中并将其传递给super csv。在将非常大的惰性序列传递给多个使用者时,我遇到了一些Java堆空间问题,因此我有点担心采用这种解决方案

    另一种解决方案是在本地下载文件,然后在此文件上打开两个流。这消除了流背后的原始动机:允许在数据开始到达时就开始处理文件

    最后一个解决方案,我认为只有在没有其他工作的情况下,实现我自己的CSV读取器,它返回已解析的CSV和原始未解析的行。如果您使用了一个非常可靠的CSV阅读器,它可以返回解析CSV数据的Java哈希和原始未解析行,请告诉我


    谢谢

    我倾向于从网络创建一个序列行,然后将其移交给需要处理该序列的多个进程;持久数据结构就是这样的。如果需要将一系列字符串转换为一个读取器,您可以将其交给SuperCSV api,这似乎是可行的:

    (import '[java.io Reader StringReader]) (defn concat-reader "Returns a Reader that reads from a sequence of strings." [lines] (let [srs (atom (map #(StringReader. %) lines))] (proxy [Reader] [] (read ([] (let [c (.read (first @srs))] (if (and (neg? c) (swap! srs next)) (.read this) c))) ([cbuf] (.read this cbuf 0 (count cbuf))) ([cbuf off len] (let [actual (.read (first @srs) cbuf off len)] (if (and (neg? actual) (swap! srs next)) (.read this cbuf off len) actual)))) (close [] )))) (导入“[java.io读取器StringReader]” (defn concat阅读器 “返回从字符串序列读取的读取器。” [行] (让[srs(原子(映射#(StringReader.%)行))] (代理[读者][] (读 ([] (让[c(.read(first@srs))] (如果(和(neg?c)(互换!srs下一个)) (.读这个) c) )) ([cbuf] (.读取此cbuf 0(计数cbuf))) ([cbuf关闭透镜] (让[实际(.read(first@srs)cbuf off len)] (如果(和(负-实际)(交换!srs下一个)) (.从透镜上读取此cbuf) (实际数字) (关闭[])) 例如

    用户=>(DEFR(concat读卡器[“foo”“bar]”) #'用户/r 用户=>(def cbuf(字符数组2)) #'用户/cbuf 用户=>(.read r cbuf) 2. 用户=>(seq cbuf) (\f\o) 用户=>(字符(.read r)) \o 用户=>(字符(.read r)) \b
    解决方案是对所有访问使用一个BufferedReader,然后每次将其传递到需要从头开始读取的功能时都将其重置。

    我想我有点不清楚如何从S3中获取字符-可能更具体一点?我可能完全错过了,所以请原谅我是这样的-可能是老邓宁·克鲁格在说什么。嘿,艾萨克,我正在使用我使用jclouds blobstore.clj构建的功能返回一个BufferedReader,它允许我读取Amazon S3对象。wwmorgan on#clojure向我推荐了一个从根本上符合您声明的解决方案:“我倾向于从网络中创建一个序列行,然后将其交给我使用的序列(序列行(create-buffered-reader-for-s3-object“object name.csv”))为了获得延迟序列,然后将每一行包装在自己的StringReader中,然后将其传递给自己的CsvMapReader。我必须为每一行创建一个CsvMapReader,而不是将读取整个文件的读取器传递给CsvMapReader。我的最终解决方案如下所示:(行seq amazon-s3-reader)[(map#(.read(CsvMapReader.(java.io.StringReader.line)CsvPreference/STANDARD#PREFERENCE))行])上面的代码没有解析,但它概述了一般的解决方案:它返回解析的CSV数据和原始行,让我在没有奇怪交互的情况下访问它们。呃。对我的解决方案进行的广泛测试显示带宽消耗比我想要的高4倍,而不是我使用两个单独的读卡器时得到的2倍。我认为seq'ing a network resources的问题在于,每个seq被消耗的地方都会导致资源一次又一次地从网络中被拉下来,从而导致我遇到的高带宽消耗问题。 user=> (def r (concat-reader ["foo" "bar"])) #'user/r user=> (def cbuf (char-array 2)) #'user/cbuf user=> (.read r cbuf) 2 user=> (seq cbuf) (\f \o) user=> (char (.read r)) \o user=> (char (.read r)) \b