图数据库中的层次结构属性

时间:2018-06-25 12:48:28

标签: database-design neo4j nosql cypher graph-databases

我开始使用neo4j。 在我的图形数据库中,我有节点Person(请看下面的“ John”),其标签为:Name(字符串),Food(正整数)。每个Person通过具有值的关系Person与其他isFriendTo连接。 我仅使用图数据库来查找两个人之间的最短加权路径。

此外,每天我都要检查图中的每个节点,如果食物的价值低于100,我会采取一些措施。

现在,在进行一些改进之后,属性Food不足以容纳我的项目。因此,我必须将其拆分为其他三个更具体的属性(正整数):VegetablesMeatCereals。如果这三个值之和小于100,则我必须采取与以前相同的操作。 我以前的情况是“约翰”,我可以将设计发展到的唯一选择是“弗雷德”还是“保罗”?

enter image description here

我可以通过哪种方式设计它?除了neo4j之外,我是否还应该使用MongoDB之类的东西来表示层次结构?

删除属性Food并添加三个新属性对我来说似乎是一个坏习惯。我必须在其他地方保存该3表示“食物” ...如果将来我会添加其他类型的食物呢?在哪里存储要检查的值100必须来自MeatVegetablesCereals的知识? 拥有这样的东西可以解决我的疑问,因为我可以对food中的所有项求和:

{
  "name": "Lucas",
  "food": {
    "meat": 40,
    "vegetables": 30,
    "cereals": 0
  }
}

(我不需要遍历从FoodVegetablesPerson的连接。只需要检查肉类,蔬菜和谷物的总和是较小还是较大100。)

2 个答案:

答案 0 :(得分:1)

似乎您对术语labelproperty感到困惑。

根据您的图表,Person似乎是所有节点共享的 label ,而Name/Food//Meat/Vegetables/Cererals似乎是节点 properties的名称

如果我的理解是正确的,那么有很多方法可以处理多种食物类型,并获得每人总计。以下是几个示例。

  1. 这是一种方法。您可以为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'})
    

    使用此数据模型,可以找到包含100单位以上食物的所有Person

    MATCH (p:Person)-[r:HAS_FOOD]->()
    WITH p, SUM(r.amount) AS total
    WHERE total > 100
    RETURN p;
    
  2. 这是另一种方法(可能会加快搜索速度)。由于neo4j属性不能具有映射值(与您在问题底部附近的JSON中显示的值相反),因此每个Person节点都可以具有amountfood数组,如下所示:

    (:Person {Name: 'Fred', amount: [50, 100], food: ['Meat','Vegetables']})
    

    使用此数据模型,可以找到包含100单位以上食物的所有Person

    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]];
    
  3. 因此,这是解决您的问题的第三种方法,并且对于执行食品加工而言要好得多。每个“人”节点都可以将食物量直接存储为属性,例如:

    (: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;
    

答案 1 :(得分:0)

在Neo4j上,标签就像标签一样,没有技术层次,并且一个节点可以有很多标签。

但是从业务的角度来看,如果您想说FoodVegetablesMeatCereals的父级,那就没有问题了。您将具有业务/语义层次。

因此,从我的观点来看,在您的情况下,我只会在标签为Food的节点上添加新标签