Database design 在图形数据库中保存事件时间历史记录的最佳建模实践

Database design 在图形数据库中保存事件时间历史记录的最佳建模实践,database-design,graph,Database Design,Graph,在对图形数据库建模时,为了能够在需要时重建导致当前图形的事件序列的任何部分,跟踪关系更改的日期和时间,最佳做法是什么 例如,让我们假设如下: 我们想建立一个有用户和“是朋友”关系的社交图 “是朋友”的关系随着时间的推移来来去去去 我们很容易看出Bob目前与Tom是朋友,但我们也想知道: 鲍勃在第一次约会时开始和汤姆成为朋友 然后在D2约会时就不再和汤姆做朋友了 然后在第三次约会时和汤姆又成了朋友 在没有更好的建议的情况下,我正在考虑做以下工作: 创建三种类型的关系(假设第二种和第三种关

在对图形数据库建模时,为了能够在需要时重建导致当前图形的事件序列的任何部分,跟踪关系更改的日期和时间,最佳做法是什么

例如,让我们假设如下:

  • 我们想建立一个有用户和“是朋友”关系的社交图
  • “是朋友”的关系随着时间的推移来来去去去
  • 我们很容易看出Bob目前与Tom是朋友,但我们也想知道:
    • 鲍勃在第一次约会时开始和汤姆成为朋友
    • 然后在D2约会时就不再和汤姆做朋友了
    • 然后在第三次约会时和汤姆又成了朋友
在没有更好的建议的情况下,我正在考虑做以下工作:

  • 创建三种类型的关系(假设第二种和第三种关系存储在带有某种“created at”时间戳的图形数据库中):
    • “是朋友”
    • “开始成为朋友”
    • “不再是朋友”
  • 每次事件发生时,通过更新(即创建或删除)与“是好友”的关系以及创建添加到潜在现有关系的“开始”或“停止是好友”关系来保持一致性

显然,不同的图形数据库可能存在实现差异。但我的看法是:

创建属性为“开始”和“停止”的边缘“朋友”。仅当友谊结束时才设置stopped属性。如果关系重新点燃,你可以在人与人之间拥有多个“朋友”边缘

我从“幸存者和参数”部分复制粘贴。我相信这个例子与你的问题非常相似。它使用Prolog编写部分查询,我认为这是一个非常好的想法

gremlin> pt = pt.extend(''' \
  livingAsOf(Person, Year) :- property(Person, 'born', Year1), Year1 =< Year, livingAsOfSub(Person, Year). \
  livingAsOfSub(Person, Year) :- property(Person, 'died', Year2), Year2 >= Year. \
  livingAsOfSub(Person, Year) :- not(property(Person, 'died', _)). \
''')

gremlin> g.V().as('p').pixy(pt, 'livingAsOf($, ?)', 1950) \
    .select(['p'], {it.name + ', born ' + it.born + (it.died ? ', died ' + it.died : '') })
gremlin>pt=pt.extend(“”)\
生活年限(人,年):-财产(人,“出生”,第1年),第1年=<年,生活年限(人,年)\
居住时间(人,年):-财产(人,“死亡”,第2年),第2年>=年\
居住时间(人,年):-非(财产(人,“死亡”和)\
''')
gremlin>g.V().as('p').pixy(pt,'livingsof($,?)',1950)\
.select(['p'],{it.name+',born'+it.born+(it.died?',died'+it.died:''))
更新2014-08-22:
关于db特定的实现,使用Cassandra支持的Titan,将“开始”和“停止”字段存储为一个集合并具有单一的友谊关系边缘可能是有意义的。我想从多个友谊边缘收回,因为它可能会增加不必要的复杂性,但某些数据库和查询模式可能会使用该模式执行得更好。有了Titan Cassandra,您可能会发现将第一个开始和最后一个停止的案例单独复制为字段,并有另一个集合字段,正如我前面提到的,它只存在于友谊停止和重新开始的案例中。这取决于您对数据库的选择以及您的查询模式。因此,正如您在评论中所写,测试是一种方式。

您的建议非常恰当。你为什么认为这不好?这正是图形数据库处理得很好而RDMS处理得很低的地方。@I.K.谢谢。我只是想知道是否有更好的方法,因为(I)我的建议假设三个关系中的两个是时间戳(是默认情况吗?是选项吗?)和(ii)存储的信息是冗余的,因为当前状态可以由最后一个事件推断(例如,如果最后一个事件是start/stop,那么Bob与Tom是/不是朋友),这可能是一种不好的做法……是的,我理解您对“is friends with”冗余的担忧,正如我所想到的那样。但是,我当时认为,通过该关系检索当前的“friends”状态可能会更快(就查询性能而言)而不是做一些日期查询。我建议的是进行实验:将引用“is friends with”关系的查询与使用其他关系的查询进行时间比较,以获得当前的友谊状态。我认为这里没有任何最佳实践。相反,我认为您采用的是“最佳方法”服务于您的问题领域。希望它能有所帮助。很好的建议是对两种方法进行时间比较,@I.K。这将提供客观的数据来管理性能和无数据冗余之间的权衡。很好的建议,我喜欢将“开始”和“停止”作为属性重构为单一类型的关系(“朋友”)的想法在保留整个友谊历史记录的同时,可能还存在一个关于性能的问题(即,由于查询将有一个关于“停止”属性存在的条件,因此查找X的朋友的速度有多快)。测试会告诉我们答案。我在结尾添加了另一段。当谈到“字段”、“字段集”和“设置字段”时,你是指边缘属性吗?作为一个集合,如列表或数组,[]如在js speak中。发布得有点太早了,是不是更清楚了?Cassandra有这样一种数据类型。因此存储在Titan Cassandra中会更有效,但在查询方面,它取决于您的模式。