最近的项目需要利用到图数据neo4j
,这篇主要针对航空公司的航班进行建模,根据所查询的目的合理构建一个关于航班的模型.
如果您访问过我所教过的Neo4j数据建模类,您一定听过我说“您的模型依赖于您的数据和查询”大约一百万次。让我们更深入地了解这意味着什么,看看如何在Neo4j中模拟航空公司的飞行数据。
那么我们的数据是什么呢?机场和航班数据。一开始我们的模型:
这个模型感觉有点偏离。航班的概念被表达为一种关系,但如果我们想把客户或员工与航班关联起来,或者说由于天气或任何问题,航班被改道到另一个机场,很明显由上面的模型是很难实现我们的需求的。考虑到我们对数据的一些查询,航班实际上应该是一个实例或事件,因此是一个node,所以让我们来试试这个模型:
你可能在Nicole White的graphgist或Mahesh Lal的Neo4j图数据建模书中看到过这个模型。
这不是一个坏的模型,但是我们会有非常密集的节点。想想亚特兰大、北京、迪拜、伦敦希斯罗机场,甚至是当地的芝加哥奥黑尔机场。这些将是非常大的节点,而且,若想使用少量的属性来过滤的话,很显然,没有一个快速的方法得到我们想要的数据,这将降低我们的遍历速度。
“您的模型依赖于您的数据和查询”,由查询的目的重新定义模型。当用户试图预订航班时,他们知道自己从哪里出发,想去哪里,想要飞行的是哪一天。因此,让我们引入天数的概念。在graph
中有多种方式来建模日期和时间,但是根据查询目的,我们应该找到一个方法使得我们的遍历限制在一个小的子图上,因此我们将创建节点来识别我们想要的子图。对每个机场增加日期,即每个机场都有365个日节点,这样我们就可以预定并提前一年预定航班。
我们添加了日节点,但是我们的模型并没有真正改善我们的查询。我们仍然需要检查所有的AirportDay
节点上的日期属性。我们可以将date属性移动到HAS_DAY
关系中,以避免在从机场开始时必须遍历到AirportDay
节点,但还有另一种方法:
我们将日期作为一个实际的关系类型,所以我们可以从一个机场节点开始,然后通过关系类型快速跳转到AirportDay
节点,而不必检查365个关系的日期属性。这是设计模型时要理解的一个重要概念。遍历的工作越少,它就会越快。检查几百个关系属性比遍历单个关系类型更昂贵。然而,这就引出了一个问题:“为什么要从机场出发,什么时候我们才能从机场出发?”事实上:
我们可以使用像“ORD-1441065600”这样的组合,通过索引快速定位到芝加哥O 'Hare机场并且日期为2015-01-09,并从那里开始遍历。很明显需要机场代码和航班飞行日期。现在我们开始考虑遍历何时结束。当然,一旦我们找到了到达目的地的航班时就结束。然而,用现有的模型来检查我们是否到达目的地,我们必须遍历每个航班的所有AirportDay
,这对性能没有好处。可以想象当某个航班的飞行路径通过主要的枢纽站一个或者两个,那么你的遍历将是相当痛苦的。
我们知道一个机场每天可能有几千个航班,但是很少有一个机场的所有航班目的地数超过200个,所以我们可以在每个机场增加航班的目的地节点。我们每天可能有100个从芝加哥到亚特兰大的航班,但是我们只需要遍历一次目的地。如果我们找不到我们想要的目的地,我们可以立即停止遍历这个AirportDay
,尝试不同的路线。如果具有多个停靠点,我们没必要去遍历每个AirportDay
的所有航班。大多数情况下,一般都是提前预定航班,但是那些错过航班、错过转机、航班取消或计计划改变的旅客需要预定航班。尝试让目的地节点包含一个数组属性,仅仅是为了检查,,但我把它作为一个节点,是因为这个模型有一个额外的好处,如果所有航班从芝加哥到亚特兰大因天气延误或取消,我们可以编辑目标节点,从而对整个模型进行更新。我们的模型是:
我喜欢这个模型,但是也许我们可以做得更好一些。经常飞行的人无论何时更倾向于预订他们最喜欢的航空公司的航班,以赚取飞行里程或积分。通常情况下,人们会选择乘坐同一家航空公司的回程航班。因此,让我们以“约会为关系类型”的想法为例,并尝试“航空公司为关系类型”:
对于这个新模型,我们可以从 AirportDay出发,遍历目的地,看看是否有直达航班。如果不是,我们可以用跳跃的方式查看路线,并快速遍历这些AirportDays的目的地节点,看看它们是否能到达目的地。如果用户愿意进行两次跳跃,我们可以用同样的方式检查。我们可以查看我们首选的航班订单,甚至限制我们选择的航班。
来源:https://dzone.com/articles/modeling-airline-flights-in-neo4j