2016-08-01 20 views
1

我在neo4j中有一個圖,看起來像this。我想把它變成類似this的東西。Neo4j:遍歷兒童並基於屬性創建兒童之間的有序關係

廣義的問題:

你如何遍歷孩子按照一定的順序(例如按日期順序),在給定的順序創建孩子之間的關係?

具體問題:

每個(:人)可具有多個(:診斷)節點,和多個(:診斷)節點可以共享相同的(:概念)。標記爲「條件」的節點是(:概念)節點。 (:診斷)節點表示一個人的診斷的發生,因此沒有兩個人共享(:診斷)節點。然而,多個人可以被診斷爲具有相同類型的診斷,並且診斷類型(例如II型糖尿病,動脈瘤等)由(:Concept)節點描述。

我想根據(:診斷)節點的時間順序創建(:概念)節點之間的關係路徑,並且我只想包括第一次每個(:概念)被診斷。

到目前爲止,我已經取得了新關係(:人)和(:概念)是這樣的:

(:Person {person_id: <some_number>})-[:DIAGNOSED_WITH {start_date: yyyy/mm/dd}]->(:Concept) 

我一直在測試的東西出來一(:人)。我這樣做有以下CYPHER查詢:

match (p:Person {person_id: "12345"})--(c:ConditionOccurrence)--(con:Concept) WITH 
    p.person_id as people, con.concept_id as concepts, min(c.condition_start_date) as 
    start_date ORDER BY start_date, concepts 
MATCH (p1:Person {person_id: people}) 
MATCH (c2:Concept {concept_id: concepts}) 
MERGE (p1)-[:DIAGNOSED_WITH {start_date: start_date}]->(c2) 

現在我想創造之間的關係:[:DIAGNOSED_WITH]關係基礎上的開始日期(概念)節點。它應該是這個樣子:

(concept 1)-[:NEXT {person_id: #}]->(concept 2)-[:NEXT {person_id: #})]->(concept 3)... 

我想對所有的集合使用UNWIND [:DIAGNOSED_WITH]對於給定的關係(:人),但我不認爲我很瞭解UNWIND作品與WITH

下面的查詢,似乎剛剛繪製所有的關係

match (p:Person {person_id: "12345"})-[d:DIAGNOSED_WITH]->(c:Concept) WITH 
    p.person_id AS person_id, d AS diagnoses ORDER BY d.start_date 
WITH collect(diagnoses) as ordered_diagnoses, person_id as person_id 
UNWIND ordered_diagnoses as diagnosis 
MATCH (:Person {person_id: person_id})-[diagnosis]->(c1:Concept) 
MATCH (:Person {person_id: person_id})-[d2:DIAGNOSED_WITH]->(c2:Concept) WHERE 
    d2.start_date >= diagnosis.start_date AND d2 <> diagnosis 
WITH min(d2.start_date) AS min_start_date2, diagnosis, person_id, c1 
MATCH (:Person {person_id: person_id})-[:DIAGNOSED_WITH {start_date: 
    min_start_date2}]->(c2:Concept) 
MERGE (c1)-[:NEXT {person_id: person_id, start_date1: diagnosis.start_date, 
    start_date2: min_start_date2}]->(c2) 

我還嘗試了「觸」的方法,我都要經過:(:概念),在診斷上相同的開始日期由節點關係,我已經遇到過接觸的人,但代碼不工作,我想無論是由於我缺乏的UNWINDWITH理解方式:

match (p:Person {person_id: "2851389"})-[d:DIAGNOSED_WITH]->(c:Concept) WITH 
    p.person_id AS person_id, d AS diagnoses ORDER BY d.start_date 
WITH collect(diagnoses) as ordered_diagnoses, person_id as person_id 
UNWIND ordered_diagnoses as diagnosis 
MATCH (:Person {person_id: person_id})-[diagnosis]->(c1:Concept) 
SET diagnosis.touched = TRUE 
WITH person_id, c1, diagnosis 
MATCH (:Person {person_id: person_id})-[d2:DIAGNOSED_WITH {touched: FALSE}]-> 
    (c2:Concept) WHERE d2.start_date >= diagnosis.start_date 
SET d2.touched = TRUE 
WITH min(d2.start_date) as min_start_date2, person_id, c1, diagnosis 
MATCH (:Person {person_id: person_id})-[:DIAGNOSED_WITH {start_date: 
    min_start_date2}]->(c2:Concept) 
MERGE (c1)-[:NEXT {person_id: person_id, start_date1: diagnosis.start_date, 
    start_date2: min_start_date2}]->(c2) 

請幫幫忙!謝謝!

回答

1

我決定停止在cypher中進行黑客攻擊,只是在python中使用py2neo包進行攻擊。更直接。下面是如果你有興趣的代碼:

#!/usr/bin/env python 

from py2neo import authenticate, Graph 
from py2neo import Node, Relationship 

authenticate("localhost:7474", "neo4j", "neo3j") 
# default uri for local Neo4j instance 
graphdb = Graph('http://localhost:7474/db/data') 

def set_NEXT_rels(person_id): 
    concepts = graphdb.run("MATCH (p:Person {person_id: \""+person_id+"\"})-[d:DIAGNOSED_WITH]->(c:Concept) RETURN c.concept_id, d.start_date ORDER BY d.start_date, c.concept_name").data() 
    for i in range(0, len(concepts)-1): 
     d = graphdb.run("MATCH (p:Person {person_id: \""+person_id+"\"})-[d1:DIAGNOSED_WITH {start_date: \""+concepts[i]['d.start_date']+"\"}]->(c1:Concept {concept_id: \""+concepts[i]['c.concept_id']+"\"}) MATCH (p:Person {person_id: \""+person_id+"\"})-[d2:DIAGNOSED_WITH {start_date: \""+concepts[i+1]['d.start_date']+"\"}]->(c2:Concept {concept_id: \""+concepts[i+1]['c.concept_id']+"\"}) MERGE (c1)-[:NEXT {person_id: \""+person_id+"\", start_date_d1: d1.start_date, start_date_d2: d2.start_date}]->(c2)").data() 

def process_conditions_by_person(): 
    people = graphdb.run("MATCH (p:Person) RETURN p.person_id").data() 
    for person in people: 
     set_NEXT_rels(person['p.person_id']) 

def main(): 
    process_conditions_by_person() 

if __name__ == "__main__": 
    main() 
1

APOC Procedures library有什麼可以幫助您在這裏。具體來說,在助手部分的集合函數子部分下,有一個過程apoc.coll.pairs([list]),它將獲取一個列表並輸出一個子列表對列表。最後一對將是列表中與null匹配的最後一個元素,所以如果我們的目標是連接節點,我們應該放棄這一點。

下面是使用的例子:

WITH [1, 2, 3, 4, 5] AS stuff 
CALL apoc.coll.pairs(stuff) YIELD value 
WITH value[0..size(value)-1] AS numbers 
RETURN numbers 

這將輸出:[[1, 2], [2, 3], [3, 4], [4, 5]]

所以在使用此連接的節點方面,你會讓你的查詢搜索你感興趣的節點,根據需要對它們進行排序,將它們收集到一個列表中,調用pairs()APOC過程,然後使用FOREACH創建每對之間的關​​系。

編輯

,因爲我的回答有些變化APOC:

1)apoc.coll.pairs()現在是一個函數,而不是一個程序(不需要使用電話或產量,您現在可以使用它

2)apoc.nodes.link()是一個接收節點集合並在它們之間創建給定類型關係的過程(因此您不必在foreach中自己創建關係),並且通常是鏈接節點的首選方式。