一般来说,您选择使用的任何方法都应该适合您的用例和查询。
在您的示例中,方法 2 使用一个 Matrix :Movie 节点,考虑到跟踪电影评级的用例,是非常好的设计。这与您可以在 Neo4j 中加载的电影图表中使用的方法相同。尝试一下,并注意,如果与 :Movie 的每一个关系都有多个单独的 :Movie 节点,则该图会很混乱且难以查询。
您会注意到,在方法 1 中,每个 Matrix :Movie 节点之间绝对没有什么不同。这是一个强有力的指标,表明您应该将事物建模为单个节点而不是多个节点。如果您对同一事物使用多个节点,则查询起来也更加困难,因为数据库不能再使用单个节点作为电影的起点,从而根据其中的关系获取数据。您对电影本身的查询也变得稍微复杂一些,因为您需要在按名称匹配电影时添加LIMIT 1,否则查询将匹配所有多部 Matrix 电影,可能有数千个或更多取决于有多少评级。
即使您可能用于此模型的其他一些查询将使用类似的 Cypher,甚至是相同的 Cypher 查询,您也会通过此数据模型不必要地影响数据库操作。考虑一个平均评分查询。对于单个 Matrix :Movie 节点,只需匹配单个 :Movie 节点(按索引或唯一名称),然后取其所有关系的平均值。使用多个 Matrix :Movie 节点,您的匹配将在数千个(或更多)冗余节点上匹配,并且对于所有这些节点,它需要拉动这些关系并将它们平均在一起。这是你不需要做的大量数据库点击。
另外,在将这种方法结合到其他用例时,请记住使用这种方法的难度。例如,考虑我们是否必须更改您的数据模型以包含演员和导演,类似于您可以在 neo4j 中导入的电影数据库。如果我们为每部电影的每一个评分都有多个节点,那么在创建演员和导演以及他们工作的电影之间的关系时,我们将使用哪个节点?使用这种数据模型,没有好的选择可以有效或清晰地对这种数据进行建模。
考虑到您的第二种情况,为每次事故创建一个新的 :Accident 节点是有意义的,其中包含每个节点中的事故详细信息。如果您的数据库中的两辆或多辆汽车涉及同一事故,那么使用同一个事故节点来表示事故,并将多辆汽车与它们所涉及的同一事故建立关系是有意义的。这样可以避免您复制有关同一事故实例的数据,并对事故参与者以及与事故相关的任何其他相关数据进行清晰的建模。您始终可以存储有关汽车与事故之间关系的特定汽车事故数据,例如遭受的损坏,以及是否发现汽车驾驶员有过错。
在这个数据模型中应该清楚的是应该有单独的 :Accident 节点(除非,如前所述,多辆汽车是同一事故),因为事故之间的数据会有所不同,并且需要您单独捕获它们节点。这与您的电影数据模型大不相同,在电影数据模型中,对同一部电影使用多个 :Movie 节点是没有意义的,因为数据都是相同的。
至于在关系中存储数据,这同样取决于您的数据模型,以及什么是最有意义的。对于评级,将评级存储在与电影的关系上对我来说看起来不错。
在某些情况下,您可以考虑创建中间节点来将数据存储在节点而不是关系上。考虑一个具有 :Person 和 :Company 节点的就业图。您可以简单地使用节点之间的 :WORKS_AT 关系对此进行建模,但您需要在该关系中存储有关就业的数据,例如hireDate、salary、jobTitle 等。这可能很好……但您总是可以将其提取到它自己的节点,一个 :Person 和一个 :Company 之间的 :Employment 节点来保存该数据。这可以让我们索引这些属性,从而更容易查询 :Company 的 :Persons,例如,如果数据是关于关系的,那么效率就不会那么高,因为你不能索引关系属性。
编辑
关于节点的基数,何时使用单个节点实例与多个节点实例,这通常在您回答“这对这个数据模型是否具有逻辑意义”和“这是否简单有效”的问题时得到最好的回答查询这些数据?”
您介绍的两个案例,对于 Matrix :Movie 节点和 :Accident 节点,每个都展示了相反的案例。
单个 Matrix :Movie 节点是有意义的,我认为找到需要多个 Matrix 节点副本的用例可能会很费力。
但是,如果您必须对 The Matrix 的电影放映进行建模,则可能需要一个 :Showing 节点,其中会有多个(每次和每个剧院),但它们都引用同一个 Matrix :Movie节点。这是同一部电影,但有多次放映。
对于 :Accidents,使用多个 :Accident 节点是有意义的,每个节点代表一个特定的事故实例。在许多情况下,只有一个 :Car 与单个 :Accident 节点相关联,即一名司机在不涉及其他司机的情况下撞上某物。在其他情况下,当它是多车碰撞时,那么几辆车都涉及到同一个 :Accident,因此您将拥有 :Accident 节点,其中包含时间、地点和详细信息,以及与该特定事故所涉及的 :Cars 的关系.
虽然可以对所有事故使用单个 :Accident 节点,并且拥有有关关系的详细信息,但您很快就会遇到一些可能需要进行的查询的问题。例如,你怎么知道哪些事故是多车事故,涉及哪些车?我们必须检查与单个 :Accident 节点的所有关系,即便如此,我们也必须执行额外的逻辑来找出关联。如果我们想订购 :Accidents by date 怎么办?我们不能在关系属性上使用索引,所以我们必须再次触及所有关系并检查它们的属性并对它们进行排序。如果我们想根据离事故最近的城市来指示位置,以便快速查找某些城市的事故怎么办?同样,我们不能在关系属性上使用索引来进行快速查找。如果我们已经有 :City 节点,我们无法在相关的 :City 节点和崩溃关系之间创建关系,您需要一个节点来实现。
我可以列出更多案例,但很明显,每次事故都需要多个 :Accident 节点(同样,为同一 :Accident 中涉及的 :Cars 共享节点)。
这是其中一种情况,即使您在考虑数据模型是否有意义时错过了它,考虑您想要进行的查询类型及其效率,也应该推动您采用更好的方法来建模您的数据...在这种情况下,使用多个 :Accident 节点。