Primera versión del grafo de nuestro modelo. He intentado añadir el máximo de información posible, de manera que nos sirva a modo de especificación. Iré añadiendo cosas que falten y corrigiendo errores sobre este mismo grafo. Aunque sería muy interesante encontrar una buena herramienta para especificar el grafo de manera más formal (Gephi es muy inestable. Probaré Neoclipse).
Grafo (descargar para ver mejor)
Los nodos representan tipos de nodos (excepto el nodo "root", que es único). El título de los nodos, que actuaría a modo de "node_type" es opcional. Realmente, puedes inferir el tipo de nodo que es por sus relaciones adyacentes. No obstante, si nos facilitase la implementación y la navegación, podríamos añadir el "node_type" en todos los nodos.
Neo4j sólo permite primitivos y Strings como valor de las propiedades (
http://docs.neo4j.org/chunked/milestone/graphdb-neo4j-properties.html), tendremos que apañarnos. En esta primera versión he intentado adaptar todos los tipos de datos de la especificación GedcomX a Neo4j. Los tipos que más problemas pueden darnos son las fechas y la longitud/latitud.
Las propiedades de los nodos obligatorias son las marcadas con "(1)". Las relaciones son direccionales y tienen marcada su frecuencia:
- (*) 0 o más
- (+) 1 o más
- (1) 1 obligatoria
Lo que menos me convence del grafo diseñado es el nodo "CONCLUSION" y sus relaciones:
- IS_PERSON
- IS_RELATION
- etc.
Puede acabar siendo difícil de mantener la integridad del grafo con esta técnica, probablemente sea mejor añadir las propiedades y relaciones del nodo "CONCLUSION" a cada uno de sus "subnodos".
El nodo apuntado por el nodo en rojo, puede ser substituido por una relación con propiedades, ya que la relación con "PERSON" es obligatoria.
He preparado un script Cypher de Neo4j muy pequeño y simple con unas instancias. Puede ser cargado en el servidor web de Neo4j:
// agent
create n = {id:"A1", phones:["23242452","53454353"]};
// agent->address
start n = node:node_auto_index(id="A1") create a={city:"Salt Lake City"}, n -[:HAS_ADDRESS]-> a;
// agent->name
start n = node:node_auto_index(id="A1") create a={value:"Family History Library"}, n -[:HAS_NAME]-> a;
// root to agent
start n = node(0), a = node:node_auto_index(id="A1") create n-[:HAS_AGENT]->a;
// source
create n = {id:"SOURCE1"}, c = {value:"citation"}, n-[:HAS_CITATION]->c;
// root to source
start n = node(0), a = node:node_auto_index(id="SOURCE1") create n-[:HAS_SOURCE]->a;
// person1
start root = node(0) create n ={id:"PERSON1"}, p , c, b= {type:"http://gedcomx.org/Birth"}, pl={original:"New York"}, n-[:IS_PERSON]->p-[:HAS_FACT]->b-[:PLACE]->pl, root-[:HAS_CONCLUSION]->c-[:IS_FACT]->b;
// person2
create n ={id:"PERSON2",gender:"http://gedcomx.org/Female"}, p , n-[:IS_PERSON]->p;
// root to conclusion
start n = node(0), p1 = node:node_auto_index(id="PERSON1"), p2 = node:node_auto_index(id="PERSON2") create n-[:HAS_CONCLUSION]->p1, n-[:HAS_CONCLUSION]->p2;
// relationship
start c1 = node:node_auto_index(id="PERSON1"), c2 = node:node_auto_index(id="PERSON2") match p1<-[:IS_PERSON]-c1, p2<-[:IS_PERSON]-c2 create n = {id:"FAMILY1-PERSON1-PERSON2"}, r = {type:"http://gedcomx.org/Couple"}, n-[:IS_RELATIONSHIP]->r-[:PERSON1]->p1,r-[:PERSON2]->p2;
// root to conclusion
start n = node(0), a = node:node_auto_index(id="FAMILY1-PERSON1-PERSON2") create n-[:HAS_CONCLUSION]->a;