【问题标题】:Java: versioned data structures?Java:版本化数据结构?
【发布时间】:2010-06-11 17:08:08
【问题描述】:

我有一个非常简单的数据结构(基本上是一个包含一些数组和单个值的结构),但是我需要记录数据结构的历史,以便我可以随时有效地获取数据结构的内容及时。

有没有相对简单的方法来做到这一点?

我能想到的最好的方法是封装整个数据结构,通过将数据存储在functional data structures 中来处理所有变异操作,然后为每个变异操作在 Map 中缓存数据结构的副本按时间排序索引(例如,以实时为键的 TreeMap,或具有突变操作计数器的 HashMap,结合存储在 TreeMaps 中的一个或多个索引,将实时/滴答计数等映射到突变操作)

有什么建议吗?

编辑:在一种情况下,我已经将历史记录作为一系列事务(这是从数据文件中读取项目),因此我可以重播它们,但这需要 O(n) 步骤( n = # of transactions) 每次我需要访问数据时。我正在寻找替代品。

【问题讨论】:

    标签: java data-structures


    【解决方案1】:

    你是对的。将数据存储在纯函数数据结构中是可行的方法。使用 do/undo 操作支持任何适度复杂的操作都依赖于程序员了解每个操作的所有副作用,这不会扩展和破坏封装。

    【讨论】:

      【解决方案2】:

      您应该使用某种形式的不可变且基于结构共享的持久性数据结构(即,数据结构中不会在版本之间更改的部分仅存储一次)。

      我在这里创建了此类数据结构的开源 Java 库:

      http://code.google.com/p/mikeralib/source/browse/#svn/trunk/Mikera/src/mikera/persistent

      这些在某种程度上受到 Clojure 的持久数据结构的启发,这可能也适合您的目的(它们也是用 Java 编写的)。

      【讨论】:

        【解决方案3】:

        如果您只存储少量数据并且没有太多更改,那么存储每个版本都可以。

        如果你不需要太频繁地访问旧版本的数据,我不会缓存每一个,我只是做它,这样你就可以重建它。

        您可以通过将突变保存为事务并重放事务来做到这一点(具有随时停止的能力。

        所以你从一个空的数据结构开始,你可能会得到一个“添加”指令,然后是一个“更改”和另一个“添加”,然后可能是一个“删除”。这些对象中的每一个都将包含正在添加或更改的事物的副本(不是指向同一对象的指针)。

        您可以将每个操作连接到一个列表中,同时改变您的集合。

        如果您发现您需要一个较旧时间戳的版本,请从一个新的空集合开始,重播直到您达到该时间戳,然后停止,您将拥有当时的集合。

        如果这是一个运行时间很长的应用程序,并且您经常需要访问接近尾声的项目,您可以为每个添加/更改/删除操作对象编写一个“撤消”,并实际来回改变数据。

        所以假设你有你的数据对象和这个突变数组,你可以轻松地在突变列表上下运行,将数据对象来回更改为你想要的任何版本。

        您甚至可以包含多个数据对象,只需创建一个新的空对象并在突变数组上运行它(将其视为时间线——每个存储的突变将包含一个时间戳或某个版本号),直到您得到它到你想要的时间戳——这样你可以有“里程碑”,你可以立即达到——例如,如果你为每个线程分配一个里程碑,你可以使 addMutation 方法同步,这个数据收集将成为 100% 线程安全的。

        请注意,如果您实际返回数据对象,则应该只返回数据的副本 - 否则下次您更改该里程碑时,它会更改您返回的数据对象。

        嗯,您还可以包含“汇总”功能——如果您决定不需要访问尾部(前几笔交易),您可以将它们应用到“开始”结构,然后删除它们——从那时起,您复制起始结构以从头开始,而不是始终从空数据结构开始。

        伙计,这是一个很棒的模式——现在我想实现它。

        【讨论】:

          【解决方案4】:

          要么按照您的建议进行操作,要么拥有某种基类,其中包含代表不同更改的子类。然后在运行时通过将版本/时间戳/任何内容传递给工厂,让您返回正确的类,从而在运行时获取正确的类。

          【讨论】:

            【解决方案5】:

            多级撤消可以基于模型(即数据结构)和一系列操作。每个动作都支持两种操作:“do”和“undo”。要对模型执行更改,您注册一个新操作并“执行”它。这可以让你在历史中来回“走动”,但模型在特定索引处的状态无法在常数时间内访问。

            也许这样的事情适用于你的情况?

            【讨论】:

            • 谢谢:我已经有了可以重播的操作历史,但是当然这需要 O(n) 次操作才能在任意时间点访问模型的状态(需要重播所有问题点之前的操作)
            【解决方案6】:

            应用程序将运行多长时间?

            您似乎可以按照您的建议执行 - 回放交易 - 但在特定时间点(每小时还是每天?)缓存数据结构和交易列表,以减轻不得不离开的痛苦每次需要从头开始重建集合时,都需要通过 O(n) 次操作。

            当然,在空间(缓存占用的空间)和重新构建它所需的操作数量之间肯定存在权衡,但希望您能够找到一个合适的媒介。

            【讨论】:

              猜你喜欢
              • 2011-03-10
              • 2015-01-05
              • 1970-01-01
              • 2011-05-06
              • 1970-01-01
              • 1970-01-01
              • 2013-03-08
              • 2015-06-29
              • 2015-07-26
              相关资源
              最近更新 更多