15

我需要在 Scala 中有一个非常非常长的对 (X, Y) 列表。太大了,它不适合内存(但很好地适合磁盘)。

  • 所有更新操作都是缺点(头部附加)。
  • 所有读取访问都从头部开始,并有序地遍历列表,直到找到预定的对。
  • 缓存会很棒,因为大多数读取访问会一遍又一遍地保留相同的数据。

所以,这基本上是一个“disk-persisted-lazy-cacheable-List”™

在我开始推出自己的产品之前,关于如何获得一个的任何想法?


附录:是的.. mongodb,或任何其他不可嵌入的资源,是一种矫枉过正。如果您对此的特定用例感兴趣,请参阅Timeline 此处的课程。基本上,我有一个非常非常大的时间表(几个月内有数百万对),尽管我的比赛只需要触及最后几个小时。

4

4 回答 4

4

The easiest way to do something like this is to extend Traversable. You only have to define foreach, and you have full control over the traversal, so you can do things like open and close the file.

You can also extend Iterable, which requires defining iterator and, of course, returning some sort of Iterator. In this case, you'd probably create an Iterator for the disk data, but it's going to be much harder to control things like open files.

Here's one example of a Traversable such as I described, written by Josh Suereth:

class FileLinesTraversable(file: java.io.File) extends Traversable[String] {
  override def foreach[U](f: String => U): Unit = {
     val in = new java.io.BufferedReader(new java.io.FileReader(file))
     try {
       def loop(): Unit = in.readLine match {
          case null => ()
          case line => f(line); loop()
       }
       loop()
     } finally {
       in.close()
     }
  }
}
于 2012-01-30T02:05:40.620 回答
4

你写:

mongodb,或任何其他不可嵌入的资源,是一种矫枉过正

你知道有嵌入式数据库引擎,包括一些非常小的引擎吗?如果您知道,我不确定您的确切要求以及您为什么不使用它们。

你确定 Hibernate + 一个可嵌入的数据库(比如 SQLite)还不够吗?或者,可以选择BerkeleyDB Java 版、HSQLDB 或其他嵌入式数据库

如果你不对对象本身执行查询(听起来你真的没有),也许序列化会比复杂对象的对象关系映射更简单,但我从未尝试过,我不知道哪个会更快。但是序列化可能是在类型中完全通用的唯一方法,假设您选择的框架提供了合适的接口来编写[T <: Serializable]. 如果没有,您可以[T: MySerializable]在创建自己的“类型类”之后编写MySerializable[T](例如Ordering[T]在 Scala 标准库中)。

但是,您不想为此任务使用标准 Java 序列化。“任何可序列化的东西”听起来是一个糟糕的要求,因为它建议为此使用序列化,但我想你可以将其放松为“使用我选择的框架可序列化的任何东西”。序列化在时间和空间上效率极低,并且不是为序列化单个对象而设计的,而是为您返回一个带有特殊标题的文件。我建议使用一些不同的序列化框架 - 看看这里进行比较。

走自定义实现之路的其他原因

此外,听起来您实际上是在向后读取文件,这在非 SSD 磁盘上的性能方面是一种非常糟糕的访问模式:读取一个扇区后,访问一个扇区需要几乎完整的磁盘轮换.

此外,正如 Chris Shain 在上面的评论中指出的那样,您需要使用基于页面的解决方案,并且您需要处理可变大小的对象。

于 2012-02-03T23:38:21.460 回答
2

这个 Java 库可能包含您需要的内容。它旨在比标准 Java 集合更有效地将条目存储在内存中。

http://code.google.com/p/vanilla-java/wiki/HugeCollections

于 2012-02-01T14:54:17.550 回答
2

如果您不想升级到其中一个可嵌入数据库,那么内存映射文件中的堆栈怎么样?

  • 堆栈似乎满足您所需的访问特性。(推送一堆数据,频繁迭代最近推送的数据)
  • 您可以直接从 Scala使用 Java 的MappedByteBuffer 。您可以像处理内存一样处理文件,而无需尝试将文件实际加载到内存中。
  • 通过这种方式,您可以从操作系统免费获得一些缓存,因为映射文件的功能类似于虚拟内存。最近写入/访问的页面将保留在操作系统文件缓存中,直到操作系统认为适合将它们刷新(或您手动刷新它们)回磁盘
  • 如果您担心顺序读取性能,您可以从文件的任一端构建您的堆栈,但如果您通常读取刚刚写入的数据,我不认为这会是一个问题,因为它仍然会在内存中。(尽管如果您正在读取跨页面数小时/数天编写的数据,那么这可能是个问题)
  • 即使在 64 位 JVM 上,以这种方式寻址的文件的大小也被限制为 2GB,但您可以使用多个文件来克服这个限制。
于 2012-02-08T05:45:58.003 回答