Предпочитать узел через прямое соединение по длинному пути - PullRequest
0 голосов
/ 26 марта 2020

Моя графовая модель должна позволять наследовать атрибуты от родителя к дочернему элементу и переопределять такие унаследованные атрибуты на дочернем элементе. Атрибуты - это узлы, связанные с отношением HAS.

CREATE (parent:Node {id: "P"})-[:HAS {inherited: true}]->(:Attribute:Name {value: "Indirect Name"})
CREATE (parent)-[:HAS]->(:Attribute:Other {value: "Other Attribute"})

CREATE (c1:Node {id: "C1"})-[:HAS]->(:Attribute:Name {value: "Direct Name"})
CREATE (c1)-[:BELONGS_TO]->(parent)
CREATE (c2:Node {id: "C2"})-[:BELONGS_TO]->(parent)

В этом примере мы имеем C1-[:BELONGS_TO]->P и C2-[:BELONGS_TO]->P. P определил атрибут Name, который наследуется, и атрибут Other, который не наследуется. C1 переопределил атрибут Name, тогда как C2 наследует атрибут.

example graph

Теперь я хочу найти все соответствующие атрибуты, которые принадлежат к определенному узлу: непосредственно связанный атрибут имени для C1 и косвенный атрибут имени для C2. Атрибут "other" не следует рассматривать для C1 и C2, поскольку он не наследуется.

Чтобы получить все прямые и унаследованные атрибуты, я могу использовать этот запрос:

MATCH (c {id: "C1"})-[:HAS]->(directAttribute:Attribute), (c)-[]->(:Node)-[:HAS{inherited: true}]->(inheritedAttribute:Attribute) RETURN directAttribute, inheritedAttribute

Но это, очевидно, будет вернуть оба Name атрибута, один из C1 и наследуемый от P. Как мы можем «предпочесть» атрибуты, которые непосредственно привязаны к узлу, по сравнению с унаследованным, чтобы в этом случае только «прямой» атрибут имени возвращался запросом?

1 Ответ

2 голосов
/ 26 марта 2020

Использование меток узлов для различения guish между именами атрибутов довольно громоздко для вашего случая использования. Я бы предложил сделать имя атрибута именем свойства. Например, как name и other в следующем запросе на создание данных (вместе с foo, чтобы показать, как иметь несколько унаследованных атрибутов):

CREATE (parent:Node {id: "P"})-[:HAS {inherited: true}]->(:Attribute {name: "Indirect Name", foo: "Bar"})
CREATE (parent)-[:HAS]->(:Attribute {other: "Other Attribute"})

CREATE (c1:Node {id: "C1"})-[:HAS]->(:Attribute {name: "Direct Name"})
CREATE (c1)-[:BELONGS_TO]->(parent)
CREATE (c2:Node {id: "C2"})-[:BELONGS_TO]->(parent)

Затем вы можете использовать удобный APO C function apo c .map.merge для получения применимых атрибутов для Node (будьте осторожны, чтобы передать "прямые" атрибуты в качестве второго аргумента).

Например, если вы используете этот запрос для «C1»:

MATCH (c:Node {id: "C1"})
OPTIONAL MATCH (c)-[:HAS]->(da:Attribute)
OPTIONAL MATCH (c)-[:BELONGS_TO]->()-[:HAS {inherited: true}]->(ia:Attribute)
RETURN c, apoc.map.merge(ia, da) AS attrs

результат будет:

╒═══════════╤══════════════════════════════════╕
│"c"        │"attrs"                           │
╞═══════════╪══════════════════════════════════╡
│{"id":"C1"}│{"name":"Direct Name","foo":"Bar"}│
└───────────┴──────────────────────────────────┘

Тот же запрос для «C2» получает этот результат:

╒═══════════╤════════════════════════════════════╕
│"c"        │"attrs"                             │
╞═══════════╪════════════════════════════════════╡
│{"id":"C2"}│{"name":"Indirect Name","foo":"Bar"}│
└───────────┴────────────────────────────────────┘

Вы также можете использовать другой тип отношений (например, [:INHERITS]) вместо [:HAS {inherited: true}].

...