我需要处理一个“大”文件(不适合内存的东西)。
我想批量处理数据。假设我想将它们插入数据库中。但由于它太大而无法适应内存,因此逐个处理元素也太慢了。
所以我想从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)
答案 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)
}