图数据库中的层次结构 属性
hierarchy property in graph database
我开始使用 neo4j。
在我的图形数据库中,我有节点 Person
(请看下面的 "John"),带有标签:Name
(字符串)、Food
(正整数)。每个 Person
通过关系 isFriendTo
与其他 Person
相连,具有一个值。
我使用图数据库只是为了找到两个人之间的最短加权路径。
此外,我每天都会检查图中的每个节点,如果食物低于 100,我就会采取一些措施。
现在,经过一些改进,属性 Food
对我的项目来说已经不够用了。所以我必须将其拆分为其他三个更具体的 属性(正整数):Vegetables
、Meat
和 Cereals
。如果三者之和低于 100,我必须采取与之前相同的行动。
我以前的情况是 "John",我可以将我的设计发展到的唯一选择是 "Fred" 或 "Paul"?
我可以用什么方式设计这个?除了 neo4j 之外,我还应该使用 MongoDB 之类的东西来表示层次结构吗?
删除 属性 食物并添加三个新属性对我来说似乎是一种不好的做法。我必须在其他地方保存这 3 意味着 "food"... 如果将来我会添加其他类型的食物呢?我在哪里存储要检查的值 100 必须来自 Meat
、Vegetables
和 Cereals
之和的知识?
有了这样的东西,将解决我的疑问,因为我可以对 food
:
中的所有项目求和
{
"name": "Lucas",
"food": {
"meat": 40,
"vegetables": 30,
"cereals": 0
}
}
(我不需要遍历Food
和Vegetables
到Person
的连接。只需要检查Meat,Veg。和Cereals的总和较小或大于 100。)
在Neo4j上,标签就像标签一样,没有技术层次,一个节点可以有很多标签。
但是如果你想说Food
是Vegetables
、Meat
和Cereals
的父级,从你的业务角度来说,是没有问题的。您将拥有 business/semantic 层次结构。
所以从我的 POV 来看,在你的情况下,我只会在你的节点上添加标签为 Food
的新标签
根据您的图表,Person
似乎是您所有节点共享的 label,而 Name/Food//Meat/Vegetables/Cererals
似乎是节点的名称 属性.
如果我的理解是正确的,那么有很多方法可以处理多种食物类型的数量,并获得每人的总数。下面是几个例子。
这是一种方法。您可以为 unique 食物类型节点引入 Food
标签:
(:Food {type: 'Meat'}), (:Food {type: 'Vegetable'}), etc.
并且每个 Person
节点可以与每个相关的 Food 节点具有 HAS_FOOD
关系(具有 amount
属性)(而不是在内部存储食物类型属性):
(john:Person {Name: 'John'})-[:HAS_FOOD {amount: 140}]->(meat:Food {type: 'Meat'})
使用此数据模型,查找所有 Person
的食物超过 100 单位:
MATCH (p:Person)-[r:HAS_FOOD]->()
WITH p, SUM(r.amount) AS total
WHERE total > 100
RETURN p;
这是另一种方法(可能会加快搜索速度)。由于 neo4j 属性 不能有地图值(与您在问题底部附近的 JSON 中显示的相反),每个 Person
节点可以有 amount
和 food
数组,像这样:
(:Person {Name: 'Fred', amount: [50, 100], food: ['Meat','Vegetables']})
使用此数据模型,查找所有 Person
的食物超过 100 单位:
MATCH (p:Person)
WHERE REDUCE(s = 0, a IN p.amount | s + a) > 100
RETURN p;
[更新]
但是,使用第二种方法进行食品加工(这里是双关语)可能更麻烦且效率更低。例如,这是获取 Fred
:
肉类数量的一种方法
MATCH (p:Person {Name: 'Fred'})
RETURN [i IN RANGE(0, SIZE(p.food)-1) WHERE p.food[i] = 'Meat' | p.amount[i]][0] AS meatAmt;
然后,将 Fred
的肉类数量设置为 123:
MATCH (p:Person {Name: 'Fred'})
SET p.amount = [i IN RANGE(0, SIZE(p.food)-1) | CASE WHEN p.food[i] = 'Meat' THEN 123 ELSE p.amount[i]];
因此,这是解决您的问题并且更适合执行食品加工的第三种方法。每个 Person 节点都可以将食物数量直接存储为属性,如下所示:
(:Person {Name: 'Fred', Meat: 50, Vegetables: 100, foodNames: ['Meat', 'Vegetables']})
使用此数据模型,foodNames
数组允许您按名称遍历食物属性。因此,要找到所有食物量超过 100 单位的人:
MATCH (p:Person)
WHERE REDUCE(s = 0, n IN p.foodNames | s + p[n]) > 100
RETURN p;
并且,要获得 Fred
的肉类数量:
MATCH (p:Person {Name: 'Fred'})
RETURN p.Meat AS meatAmt;
要将 Fred
的肉类数量设置为 123:
MATCH (p:Person {Name: 'Fred'})
SET p.Meat = 123;
我开始使用 neo4j。
在我的图形数据库中,我有节点 Person
(请看下面的 "John"),带有标签:Name
(字符串)、Food
(正整数)。每个 Person
通过关系 isFriendTo
与其他 Person
相连,具有一个值。
我使用图数据库只是为了找到两个人之间的最短加权路径。
此外,我每天都会检查图中的每个节点,如果食物低于 100,我就会采取一些措施。
现在,经过一些改进,属性 Food
对我的项目来说已经不够用了。所以我必须将其拆分为其他三个更具体的 属性(正整数):Vegetables
、Meat
和 Cereals
。如果三者之和低于 100,我必须采取与之前相同的行动。
我以前的情况是 "John",我可以将我的设计发展到的唯一选择是 "Fred" 或 "Paul"?
我可以用什么方式设计这个?除了 neo4j 之外,我还应该使用 MongoDB 之类的东西来表示层次结构吗?
删除 属性 食物并添加三个新属性对我来说似乎是一种不好的做法。我必须在其他地方保存这 3 意味着 "food"... 如果将来我会添加其他类型的食物呢?我在哪里存储要检查的值 100 必须来自 Meat
、Vegetables
和 Cereals
之和的知识?
有了这样的东西,将解决我的疑问,因为我可以对 food
:
{
"name": "Lucas",
"food": {
"meat": 40,
"vegetables": 30,
"cereals": 0
}
}
(我不需要遍历Food
和Vegetables
到Person
的连接。只需要检查Meat,Veg。和Cereals的总和较小或大于 100。)
在Neo4j上,标签就像标签一样,没有技术层次,一个节点可以有很多标签。
但是如果你想说Food
是Vegetables
、Meat
和Cereals
的父级,从你的业务角度来说,是没有问题的。您将拥有 business/semantic 层次结构。
所以从我的 POV 来看,在你的情况下,我只会在你的节点上添加标签为 Food
根据您的图表,Person
似乎是您所有节点共享的 label,而 Name/Food//Meat/Vegetables/Cererals
似乎是节点的名称 属性.
如果我的理解是正确的,那么有很多方法可以处理多种食物类型的数量,并获得每人的总数。下面是几个例子。
这是一种方法。您可以为 unique 食物类型节点引入
Food
标签:(:Food {type: 'Meat'}), (:Food {type: 'Vegetable'}), etc.
并且每个
Person
节点可以与每个相关的 Food 节点具有HAS_FOOD
关系(具有amount
属性)(而不是在内部存储食物类型属性):(john:Person {Name: 'John'})-[:HAS_FOOD {amount: 140}]->(meat:Food {type: 'Meat'})
使用此数据模型,查找所有
Person
的食物超过 100 单位:MATCH (p:Person)-[r:HAS_FOOD]->() WITH p, SUM(r.amount) AS total WHERE total > 100 RETURN p;
这是另一种方法(可能会加快搜索速度)。由于 neo4j 属性 不能有地图值(与您在问题底部附近的 JSON 中显示的相反),每个
Person
节点可以有amount
和food
数组,像这样:(:Person {Name: 'Fred', amount: [50, 100], food: ['Meat','Vegetables']})
使用此数据模型,查找所有
Person
的食物超过 100 单位:MATCH (p:Person) WHERE REDUCE(s = 0, a IN p.amount | s + a) > 100 RETURN p;
[更新]
但是,使用第二种方法进行食品加工(这里是双关语)可能更麻烦且效率更低。例如,这是获取
肉类数量的一种方法Fred
:MATCH (p:Person {Name: 'Fred'}) RETURN [i IN RANGE(0, SIZE(p.food)-1) WHERE p.food[i] = 'Meat' | p.amount[i]][0] AS meatAmt;
然后,将
Fred
的肉类数量设置为 123:MATCH (p:Person {Name: 'Fred'}) SET p.amount = [i IN RANGE(0, SIZE(p.food)-1) | CASE WHEN p.food[i] = 'Meat' THEN 123 ELSE p.amount[i]];
因此,这是解决您的问题并且更适合执行食品加工的第三种方法。每个 Person 节点都可以将食物数量直接存储为属性,如下所示:
(:Person {Name: 'Fred', Meat: 50, Vegetables: 100, foodNames: ['Meat', 'Vegetables']})
使用此数据模型,
foodNames
数组允许您按名称遍历食物属性。因此,要找到所有食物量超过 100 单位的人:MATCH (p:Person) WHERE REDUCE(s = 0, n IN p.foodNames | s + p[n]) > 100 RETURN p;
并且,要获得
Fred
的肉类数量:MATCH (p:Person {Name: 'Fred'}) RETURN p.Meat AS meatAmt;
要将
Fred
的肉类数量设置为 123:MATCH (p:Person {Name: 'Fred'}) SET p.Meat = 123;