свойство иерархии в базе данных графа - PullRequest
0 голосов
/ 25 июня 2018

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

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

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

enter image description here

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

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

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

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

Ответы [ 2 ]

0 голосов
/ 26 июня 2018

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

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

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

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

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

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

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

    С помощью этой модели данных можно найти все Person s с более чем 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']})
    

    С помощью этой модели данных можно найти все Person s с более чем 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;
    
0 голосов
/ 25 июня 2018

В Neo4j метки похожи на метки, технической иерархии нет, а узел может иметь много меток.

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

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

...