持久图数据(Java)

我有一个利用图形(树状)自定义结构的应用程序。 结构不是真正的树木,但几乎所有的东西都是连在一起的。 数据量也很大(可以存在数百万个节点)。 树节点的类型可以不同,以使其更有趣(inheritance)。 我不想改变数据结构以适应持久性存储。

我希望在没有太多额外工作的情况下保留这些数据。 我已经调整了一些选项来解决这个问题,但找不到任何符合我需要的东西。 可能的选择:序列化,带有ORM(Hibernate?)的数据库,JCR(JackRabbit?),还有其他什么?

性能很重要,因为它是基于GUI的“实时”应用程序(无批处理),并且可能有数百万个图形节点应该在内存和持久数据存储之间进行读写。

有没有人有关于存储这类数据的经验或想法?

由于您的数据使用图形数据结构(基本上:节点和边缘/关系),图形数据库将是一个非常好的匹配。 有关某些链接,请参阅我对下一代数据库的回答。 我是Neo4j开源图数据库项目的一部分,请参阅此主题以进行一些讨论。 在像你这样的情况下使用Neo4j的一大优势是跟踪持久/激活对象或激活深度等没有问题。 您可能不需要更改应用程序中的数据结构,但当然需要一些额外的代码。 设计指南提供了一个代码如何与数据库交互的示例。

由于您指示存在大量数据,因此您可能需要一种可以根据需要轻松引入数据的机制。 对于大量数据,序列化可能不是很容易处理。 为了将其分解为可管理的部分,您需要在磁盘上使用单独的文件或将它们存储在其他位置。 JCR(JackRabbit)更像是一个内容管理系统。 那些适用于’文档’类型对象。 听起来你要存储的树的各个部分可能很小,但它们一起可能很大。 这不是CMS的想法。

你提到的另一个选择,ORM,可能是你最好的选择。 JPA(Java Persistence API)非常适合在Java中进行ORM。 您可以写入JPA规范并使用Hibernate,Eclipselink或任何其他类型的月提供程序。 这些将适用于您想要的任何数据库。 http://java.sun.com/javaee/5/docs/api/index.html?javax/persistence/package-summary.html

JPA的另一个好处是您可以使用惰性FetchType来加载树依赖项。 这样,您的应用程序只需要加载它正在处理的当前组件。 由于需要其他东西,JPA层可以根据需要从数据库中检索它们。

我有几乎确切的问题,并使用hibernate。 我们在项目后期遇到了很多问题,因为即使使用惰性提取类型,视图也基本上强制整个图形进入内存。 这些工具早期很好,因为我们可以快速获得一个给我们一些东西的数据库层(huzzah agile)。 只有当我们进行性能改进时,才意识到我们需要编写一个更智能的持久层。

是否可以对您的数据进行一些预处理? 如果问题类似,那么尝试将数据转换为比原始域更接近您的视图的中间forms并将其存储在数据库中有很多价值。 您始终可以使用延迟提取类型链接回原始源。

基本上我们使用的是4层系统:Domain DB,ViewModel-DB hybrid(预处理层),ViewModel,View

这个预处理步骤(特别是实时UI)的优点是,您可以将数据分页到ViewModel并很好地呈现它。 实时应用程序中的大部分性能都是轻微的,只需保持响应并在等待时向他们展示一些不错的东西。 在我们的例子中,我们可以显示正在分页的数据的3d框区域,链接到加载数据的数据也可以显示可视指示符。 ViewModel-DB混合也可以做一些很好的事情,比如适合我们域数据的LRU队列。 最大的优点是删除直接链接。 节点与其链接数据的URL类似。 渲染时我们可以渲染链接,或渲染有链接,我们现在正在分页。

数据库级别的持久性是JPA(Hibernate)的开始,但最终它为我们的inheritance结构生成的表是可怕的并且难以维护。 最后,我们希望更多地控制表而不是JPA允许(或至少容易允许)。 这是一个艰难的决定,因为JPA确实使很多DB层变得容易。 由于JPA保持良好的状态和POJO,因此不需要使用我们的数据类型。 所以这很好。

我希望你能从这个蜿蜒的答案中得到一些东西,祝你好运:)

ORM,例如使用JPA api(Hibernate,EclipseLink,…)可能会很快实现持久性。 与纯JDBC相比,整个树持久性的原始性能往往难以实现。 因此,如果您的唯一性能标准是一次性保持整棵树,那可能不是最好的选择。
另一方面,如果您还需要加载树,同步树的更改,那么JPA提供内置的function(经过一些调整后)比许多手动实现更好的性能。

java中的序列化往往非常慢并且会产生大量数据。 当您在应用程序中更改类时,序列化也非常脆弱,如果您需要同步树更改,则序列化完全无用。

在与序列化相同的类别中,您可以使用XML序列化并将其保存在某个XML数据库(Oracle XDB)中。 然而,这些设计更多是为了存储/查询的灵活性而不是原始速度。

如果时间不是问题,那么最好的方法就是让一个称职的DBA参与并设计一个最佳的数据模型并相应地重构树。

考虑将节点存储在数据库中,合适的模式可能是:

t1(node_id,child_id) t2(node_id,data1,data2,..,datan) 

然后使用JDBC访问/修改数据。 如果你使用适当的索引,它将表现得相当好,可以扩展到大约1亿条记录。 我的直觉是避免通用对象序列化,如果性能非常重要,因为你失去了对这些解决方案的代码性能特征的一些控制。

如果您需要更好的性能,可以使用memcached层。

我相信你的问题的解决方案是使用Terracotta作为你的持久存储机制。 我鼓励你阅读这篇关于这样做的优秀文章 。

它解决了您的两个主要问题: 性能透明度 。 它可以轻松扩展到大型图形,同时保持高性能,因为它具有高效的同步机制,只能通过网络发送实例差异。 它还可以透明地保持图形,因为它可以在VM级别上运行,从而避免了您在其他答案(ORM或OCM)中提到的替代方案所面临的阻抗不匹配问题。

需要明确的是,兵马俑不是每个案例的持久解决方案。 当您需要跨机器重新启动时可用数据并且您需要快速使用时,最好使用它。 当您需要“存档”数据时,这不是一个好的解决方案,例如,在运行的系统停止使用数据后很长时间内需要访问该数据。 想想进入网上商店的订单。 您可能希望在这些订单完成后存储多年。 在这些情况下,您可以查看混合方法,其中需要归档的选择数据可以从Terracotta群集中提取出来并使用传统的RDBMS进行存储。

有关优缺点的更全面的评论,请务必阅读此StackOverflowpost ,其中涵盖了更多的细节选择。