2014-12-18 2 views
0

Я пытаюсь найти эффективный способ получить набор значений свойств для предков узла. Рассмотрим следующий тривиальный настройка:Получить набор значений свойств для всех предков

CREATE 
(a {id:'a'}), (b {id:'b'}), (c {id:'c'}), (d {id:'d', age:10}), 
(b)-[:HAS_PARENT]->(a), 
(c)-[:HAS_PARENT]->(a), 
(d)-[:HAS_PARENT]->(b), 
(d)-[:HAS_PARENT]->(c) 

Я хотел бы получить набор с идентификатором d и все ид вдоль любого пути между d и a наряду с некоторыми другими свойствами d.

Я придумал это:

MATCH (d {id:'d'}) 
OPTIONAL MATCH path=(d)-[:HAS_PARENT*]->() 
RETURN d.age as age, 
(REDUCE(o = [], r IN (collect (extract (n in nodes(path) | n.id))) | o + r)) AS closure 

который не совсем работает, потому что не хранит значения в closure уникальной и также кажется невероятно неэффективным. Если я уйду с этого согласования маршрута и вместо этого просто проецировать идентификатор d, а затем выполнить одну и ту же обходе себя с Java API:

for (Path path: graphDb.traversalDescription() 
       .depthFirst() 
       .relationships(RealtionshipNames.HAS_PARENT, Direction.OUTGOING) 
       .uniqueness(Uniqueness.NODE_GLOBAL) 
       .traverse(graphDb.getNodeById(nodeId))) { 
    ids.add((String)path.endNode().getProperty("id")) 
} 

задача завершает в секундах, даже с моим большим набором данных (100k узлы, 200k отношения). С моим запросом Cypher он никогда не завершается.

Есть ли способ объединить это все в единый, эффективный запрос Cypher или мне лучше делать некоторую пост-обработку с помощью Java API?

+0

Что именно должен вернуть запрос? Это ('d', ['b', 'a']) и ('d', ['c', 'a'])? Или ('d', ['b', 'c', 'a'])? Или что-то другое? – zaboco

+0

@zaboco он должен вернуть набор ('d', 'c', 'b', 'a'). – condit

ответ

2

Если вы хотите только идентификаторы материнской компании на данный момент:

MATCH (d {id:'d'}) 
OPTIONAL MATCH path=(d)-[:HAS_PARENT*]->(p) 
WHERE NOT (p)-[:HAS_PARENT]->() 
RETURN d.age, d.id, collect(NODES(path)) 

WHERE NOT (p)-[:HAS_PARENT]->() является только вернуть пути через все пути к первому предку, а не промежуточные пути.

Это вернет вам строку для каждого пути через дерево от d до предка предка, что я не думаю, что именно вы хотите. Вы могли бы связать его с UNWIND, чтобы вытащить уникальные идентификаторы в коллекцию, используя оператор WITH.

Если все, что вы хотите это идентификаторы, не имеющие реальной заботы о путях, вы можете использовать:

MATCH (d { id:'d' }) 
OPTIONAL MATCH path=(d)-[:HAS_PARENT*]->(p) 
RETURN d.id, d.age, COLLECT(DISTINCT p.id) 

Если вам нужна голова в коллекции, то измените последнюю строку на:

RETURN d.id, d.age, d+ COLLECT(DISTINCT p.id) 
+0

Спасибо. Последнее - именно то, что я ищу. Отлично работает для меньшего запроса, но когда я запрашиваю весь набор данных, он до сих пор не завершен. Любые мысли о производительности? – condit

+0

Вы должны использовать ярлык, например. ': Node' для ваших элементов дерева. А затем создайте индекс для: Node (id), который затем используется cypher. Или используйте 'MATCH (d) WHERE id (d) = {node_id}' –