Свойство иерархии в базе данных графа

Я начинаю использовать neo4j. В моей базе данных графа у меня есть узлы Person (посмотрите на "Джона" ниже) с надписями: Name (Строка), Food (положительное число). каждый Person связано с другими Person через отношения isFriendTo, это имеет значение. Я использую граф DB только для того, чтобы найти кратчайший взвешенный путь между двумя людьми.

Кроме того, каждый день я проверяю каждый узел на графике, и если еда становится меньше 100, я предпринимаю некоторые действия.

Теперь, после некоторых улучшений, собственность Food больше не достаточно для моего проекта. Поэтому я должен разделить это на три других более специфических свойства (положительное целое число): Vegetables, Meat а также Cereals, Если сумма обоих трех меньше 100, я должен предпринять те же действия, что и раньше. Моя старая ситуация была как "Джон", единственные варианты, в которые я могу развить свой дизайн, это "Фред" или "Пол"?

Каким образом я могу спроектировать это? Должен ли я использовать в дополнение к neo4j что-то вроде MongoDB для представления иерархии?

Удаление свойства Food и добавление трех новых свойств кажется мне плохой практикой. Я должен спасти в другом месте, что эти 3 означают "еда"... и что если в будущем я добавлю другие виды продуктов? Где хранится информация о том, что значение 100 для проверки должно приходить из суммы Meat, Vegetables а также Cereals? Наличие чего-то подобного решит мои сомнения, потому что я могу суммировать все элементы внутри food:

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

(Мне не нужно проходить через Food а также Vegetables в Person, Просто нужно проверить, что сумма мяса, Вег. и зерновые меньше или больше 100.)

2 ответа

Решение

Похоже, вы путаете термины label и property.

Согласно вашей диаграмме, Person кажется метка, разделяемая всеми вашими узлами, и Name/Food//Meat/Vegetables/Cererals кажутся названиями свойств узлов.

Если мое понимание верно, то есть много подходов к обработке нескольких типов продуктов и получению общего количества на человека. Ниже приведено несколько примеров.

  1. Вот один из подходов. Вы могли бы представить Food этикетка для уникальных узлов типа пищи:

    (:Food {type: 'Meat'}), (:Food {type: 'Vegetable'}), etc.
    

    и каждый Person узел может иметь HAS_FOOD отношения (с amount свойство) к каждому соответствующему узлу Food (вместо внутреннего хранения свойств типа Food):

    (john:Person {Name: 'John'})-[:HAS_FOOD {amount: 140}]->(meat:Food {type: 'Meat'})
    

    С помощью этой модели данных, чтобы найти все Persons с более чем 100 единицами пищи:

    MATCH (p:Person)-[r:HAS_FOOD]->()
    WITH p, SUM(r.amount) AS total
    WHERE total > 100
    RETURN p;
    
  2. Вот другой подход (который, вероятно, приведет к более быстрому поиску). Так как свойство neo4j не может иметь значение карты (в отличие от того, что вы показываете в JSON в нижней части вашего вопроса), каждый Person узел может иметь amount а также food массивы, как это:

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

    С помощью этой модели данных, чтобы найти все Persons с более чем 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]];
    
  3. Итак, вот третий подход, который решает вашу проблему и гораздо лучше для обработки пищевых продуктов. Каждый узел 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 метки похожи на метки, технической иерархии нет, и узел может иметь много меток.

Но если вы хотите сказать, что Food является родителем Vegetables, Meat а также Cereals с точки зрения вашего бизнеса, нет никаких проблем. У вас будет бизнес / семантическая иерархия.

Так что из моего POV, в вашем случае я бы добавил только новые метки на ваших узлах с меткой Food

Другие вопросы по тегам