2016-08-01 6 views
1

У меня есть график в neo4j, который выглядит как this. Я хочу сделать это как-то вроде this.Neo4j: перемещать детей и создавать упорядоченные отношения между детьми на основе имущества

Обобщенная задача:

Как вы траверс детей в определенном порядке (например, заказ по дате) и создать отношения между детьми в этом заданном порядке?

Конкретная проблема:

Каждый (: Человек) может иметь несколько (Диагностика) узлов, а также несколько (Диагностика) узлы могут совместно использовать один и тот же (: Концепция). Узлами, отмеченными как «Условие», являются (: Concept) узлы. (: Диагноз) узлы представляют собой появление диагноза для человека, поэтому ни один из двух человек не разделяет (: Диагноз) узлы. Тем не менее, многие люди могут быть диагностированы с одинаковым диагнозом, а тип диагноза (например, диабет типа II, аневризма и т. Д.) Описывается узлами (: Concept).

Я хочу создать путь отношений между узлами (: Concept), основанный на хронологическом порядке узлов (: Diagnosis), и я хочу включить только первый раз, когда диагностируется каждый (: Концепция).

До сих пор я сделал новые отношения между (: Person) и (: Concept), как это:

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

Я тестировал вещи с одной (: Person). Я сделал это с помощью следующего запроса шифровальщика:

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] соотношений для данного (: Person), но я не думаю, что я вполне понимаю, как 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) 

Я также попробовал «сенсорный» подход, когда я иду через отношения и сенсорные те, которые я уже столкнулся, но этот код не работают так, как я хочу, либо из-за мое отсутствие понимания UNWIND и WITH:

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]), которая будет принимать список и выводит список пар подписок.Последняя пара будет последним элементом в списке в паре с нулевым значением, поэтому мы должны отказаться от этого, если наша цель - подключить узлы.

Вот пример использования:

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]]

Так что в плане использования этого для соединения узлов, вы бы сделать ваш поиск запроса для узлов, которые вам интересны , сортируйте их по мере необходимости, COLLECT() в список, вызовите процедуру PAR() APOC, затем используйте FOREACH для создания отношения между каждой парой.

EDIT

Некоторые изменения АПБО с момента моего ответа:.

1) apoc.coll.pairs() является функцией сейчас, а не процедура (нет необходимости использовать ВЫЗОВ или УРОЖАЯ, вы можете использовать его встроенный

2) apoc.nodes.link() - это процедура, которая берет набор узлов и создает отношения между ними определенного типа (так что вам не нужно создавать отношения самостоятельно в foreach) и, как правило, предпочтительный способ связывания ваших узлов.