在 Neo4j 中建模航空公司航班

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

如果您参加过我教过的任何 Neo4j 数据建模课程 ,您一定听过我大约一百万次说“您的模型取决于您的数据和您的查询”。让我们通过研究如何在 Neo4j 中为航空公司航班数据建模来更深入地了解这意味着什么。

那么我们的数据是什么?机场和它们之间的航班。让我们以此开始我们的模型:

马上这个模型感觉有点不对劲。航班的概念表示为一种关系,但如果我们想将客户或员工连接到航班,或者说由于天气或任何类型的问题航班改道到另一个机场,我们不能。考虑到我们为数据设想的一些查询,航班实际上应该是一个实例或一个事件,因此是一个节点,所以让我们试试这个模型:

您之前可能已经在 Nicole White 图形学家 Mahesh Lal Neo4j Graph Data Modeling 一 书中看到过这个模型。

这不是一个坏模型,但我们会有非常密集的节点。想想像亚特兰大、北京、迪拜、伦敦希思罗机场,甚至我当地的芝加哥奥黑尔机场这样的主要枢纽。这些将是非常庞大的节点,如果不检查多个属性就无法快速过滤路由,这会大大减慢我们的遍历速度。

让我们使用查询来指导我们的模型。当用户尝试预订航班时,他们知道自己从哪里出发、想去哪里以及想在哪一天飞行。因此,让我们重新构想我们的模型以引入天数的概念。有多种方法可以在图中对日期和时间进行建模,但我们的查询告诉我们应该设法将遍历限制在一个小的子图中,因此我们将创建节点来标识我们想要的子图。每个机场都有 365 个 AirportDay 节点,因此我们最多可以提前一年预订和安排航班。

我们增加了几天,但我们的模型并没有真正改善我们的查询。我们仍在检查所有 AirportDay 节点上的日期属性。我们可以将 date 属性移动到 HAS_DAY 关系中,以避免从机场开始时一直遍历到 AirportDay 节点,但还有另一种方法:

我们使用日期作为实际的关系类型,因此我们可以从 Airport 节点开始,通过关系类型快速跳转到 AirportDay 节点,而无需检查 365 关系的日期属性。这是设计模型时需要理解的一个重要概念。遍历需要做的工作越少,它就会越快。检查几百个关系属性比遍历单个关系类型的代价更高。然而,这引出了一个问题“为什么要从 Airport 开始,而我们可以从 AirportDay 开始”?的确:

我们可以使用像“ORD-1441065600”这样的键通过索引快速到达 2015 年 9 月 1 日的芝加哥奥黑尔机场,并在那里开始我们的遍历。密钥由我们的出发机场代码和我们航班当天的 linux 纪元时间 表示组成。我认为这与我们在遍历中找到起点一样好。现在让我们开始考虑我们的遍历何时结束。这当然是在我们找到到达预定目的地的航班后。然而,对于当前模型,为了检查我们是否到达目的地,我们必须检查机场飞往当天的每一个航班,这对性能不利。想象一下,您要穿越主要枢纽,寻找一站或两站的飞行路径,那将是非常痛苦的。这就是使用 Neo4j 的最佳部分所在……您必须发挥 创意

所以让我们尝试 一些疯狂的事情 。我们知道机场每天可能有几千个航班,但很少有机场有超过 200 个目的地,所以让我们为每个 AirportDay 添加 Destination 节点。我们每天可能有 100 个航班从芝加哥飞往亚特兰大,但我们应该只需检查一次目的地。如果我们找不到我们想要的目的地,我们可以立即停止遍历这个 AirportDay 节点并尝试不同的路线。我们不必检查我们在多站遍历中遇到的每个 AirportDay 节点的所有航班。大多数时候,我们会提前预订航班,但其他需要预订航班的旅客是那些错过航班、错过转机、不得不处理航班取消或计划发生任何此类变化的旅客。我很想将 destinations 设置为数组属性并在那里检查,但我将其保留为节点,因为该模型具有额外的好处,即如果从芝加哥到亚特兰大的所有航班都因天气而延迟或取消,我们可以只编辑 Destination节点并影响它们。让查询指导您的模型。所以我们的模型现在是:

我喜欢这个模型,但也许我们可以做得更好一点。只要有可能,飞行常客往往会预订他们最喜欢的航空公司的航班,以赚取飞行里程或积分。通常人们倾向于乘坐他们到达那里所乘坐的同一家航空公司的返程路线。所以让我们采用我们之前看到的“日期作为关系类型”的想法并尝试“航空公司作为关系类型”:

有了这个新模型,我们可以从 AirportDay 开始,检查 Destinations 以查看是否可以立即使用直达或直达航班。如果没有,我们可以查看一跳的路线,并快速检查那些 AirportDays 的 Destination 节点,看看它们是否可以从我们的跳转到达我们的目的地。如果用户愿意进行两程飞行,我们可以用同样的方式检查。我们可以按照首选航空公司的顺序查看航班,甚至可以将我们的行程限制在我们选择的航空公司。

我认为这是一个很好的模型,但也许你可以想出一个更好的模型。考虑一下,如果你这样做了,请告诉我。如果您想查看其他行业和用例的许多不同模型,请务必查看 GraphGists Collection

在即将发布的帖子中,我将向您介绍 Neo4j Traversal API ,我们将构建一个航班搜索查询引擎。订阅我的博客或 在推特上关注我 ,以便在发布时收到通知。

提出正确的模型并像我们上面所做的那样迭代各种场景是我们可以在 Neo4j 技术训练营 中帮助您的事情之一。为期一周的计划,我们会到现场帮助您构建概念证明,这样您就可以确信您的 Neo4j 项目会取得成功。因此,如果您对将图形数据库添加到您的下一个项目犹豫不决,那么我们来谈谈吧。进行投资。给我们一周的时间,我们会让您走上正确的道路。