Iterator [Something] to Iterator [Seq [Something]]

时间:2015-10-24 15:54:32

标签: scala

我需要处理一个“大”文件(不适合内存的东西)。

我想批量处理数据。假设我想将它们插入数据库中。但由于它太大而无法适应内存,因此逐个处理元素也太慢了。

所以我想从Iterator[Something]转到Iterator[Iterable[Something]]批处理元素。

从这开始:

CSVReader.open(new File("big_file"))
  .iteratorWithHeaders
  .map(Something.parse)
  .foreach(Jdbi.insertSomething)

我可以在foreach语句中用可变序列做一些脏事并刷新每个 x 元素,但我确信有一种更聪明的方法可以做到这一点......

// Yuk... :-(
val buffer = ArrayBuffer[Something]()
CSVReader.open(new File("big_file"))
  .iteratorWithHeaders
  .map(Something.parse)
  .foreach {
     something =>
       buffer.append(something)
       if (buffer.size == 1000) {
         Jdbi.insertSomethings(buffer.toList)
         buffer.clear()
       }
   }
Jdbi.insertSomethings(buffer.toList)

2 个答案:

答案 0 :(得分:3)

如果您的批次具有固定大小(如您的示例所示),则Scala grouped上的Iterator方法完全符合您的要求:

val iterator = Iterator.continually(1)

iterator.grouped(10000).foreach(xs => println(xs.size))

这将在恒定的内存量中运行(当然,不计算终端在内存中存储的任何文本)。

我不确定你的iteratorWithHeaders会返回什么,但如果它是Java迭代器,你可以将它转换为这样的Scala:

import scala.collection.JavaConverters.

val myScalaIterator: Iterator[Int] = myJavaIterator.asScala

这将保持适当的懒惰。

答案 1 :(得分:1)

如果我无法正确解决您的问题,您可以使用Iterator.grouped。所以适应一点你的例子:

val si: Iterator[Something] = CSVReader.open(new File("big_file"))
  .iteratorWithHeaders
  .map(Something.parse)

val gsi: GroupedIterator[Something] = si.grouped(1000)

gsi.foreach { slst: List[Something] =>
  Jdbi.insertSomethings(slst)
}