El lenguaje de consulta Cypher se desarrollΓ³ originalmente especΓficamente para el DBMS grΓ‘fico Neo4j . El objetivo de Cypher es proporcionar un lenguaje de consulta de base de datos grΓ‘fica legible por humanos similar a SQL. Hoy, Cypher es compatible con varios DBMS de grΓ‘ficos. OpenCypher fue creado para estandarizar Cypher.
Los conceptos bΓ‘sicos para trabajar con Neo4j DBMS se describen en el artΓculo Conceptos bΓ‘sicos para trabajar con Neo4j en un navegador .
Para familiarizarse con Cypher, considere un ejemplo de un Γ‘rbol genealΓ³gico tomado del clΓ‘sico libro de texto Prolog por I. Bratko. Este ejemplo mostrarΓ‘ cΓ³mo agregar nodos y enlaces a un grΓ‘fico, cΓ³mo asignarles etiquetas y atributos y cΓ³mo hacer preguntas.

Entonces, tengamos un Γ‘rbol genealΓ³gico que se muestra en la imagen a continuaciΓ³n.

Veamos cΓ³mo formar el grΓ‘fico correspondiente en Cypher:
CREATE (pam:Person {name: "Pam"}), (tom:Person {name: "Tom"}), (kate:Person {name: "Kate"}), (mary:Person {name: "Mary"}), (bob:Person {name: "Bob"}), (liz:Person {name: "Liz"}), (dick:Person {name: "Dick"}), (ann:Person {name: "Ann"}), (pat:Person {name: "Pat"}), (jack:Person {name: "Jack"}), (jim:Person {name: "Jim"}), (joli:Person {name: "Joli"}), (pam)-[:PARENT]->(bob), (tom)-[:PARENT]->(bob), (tom)-[:PARENT]->(liz), (kate)-[:PARENT]->(liz), (mary)-[:PARENT]->(ann), (bob)-[:PARENT]->(ann), (bob)-[:PARENT]->(pat), (dick)-[:PARENT]->(jim), (ann)-[:PARENT]->(jim), (pat)-[:PARENT]->(joli), (jack)-[:PARENT]->(joli)
Una solicitud CREATE para agregar datos a un DBMS grΓ‘fico consta de dos partes: agregar nodos y agregar enlaces entre ellos. A cada nodo que se agregarΓ‘ se le asigna un nombre dentro del marco de esta solicitud, que luego se utiliza para crear enlaces. Los nodos y las comunicaciones pueden almacenar documentos. En nuestro caso, los nodos contienen documentos con los campos de nombre, y los enlaces de documentos no contienen. TambiΓ©n se pueden etiquetar nodos y enlaces. En nuestro caso, a los nodos se les asigna la etiqueta Persona y los enlaces son PADRES. La etiqueta en las solicitudes se resalta con dos puntos antes de su nombre.
Entonces, Neo4j nos dijo que: Added 12 labels, created 12 nodes, set 12 properties, created 11 relationships, completed after 9 ms.
Veamos que tenemos:
MATCH (p:Person) RETURN p

Nadie nos prohΓbe editar la apariencia del grΓ‘fico resultante:

ΒΏQuΓ© se puede hacer con esto? Puede verificar que, por ejemplo, Pam es
Padre de Bob:
MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Bob"}) RETURN ans
Obtenemos el subgrafo correspondiente:

Sin embargo, esto no es exactamente lo que necesitamos. Cambiar la solicitud:
MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Bob"}) RETURN ans IS NOT NULL
Ahora en respuesta nos hacemos true
. Y si preguntamos:
MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Liz"}) RETURN ans IS NOT NULL
No obtendremos nada ... AquΓ debe agregar la palabra OPTIONAL
, luego si
el resultado estarΓ‘ vacΓo, luego se devolverΓ‘ false
:
OPTIONAL MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Liz"}) RETURN ans IS NOT NULL
Ahora obtenemos la respuesta esperada false
.
A continuaciΓ³n, puede ver quiΓ©n es el padre para quiΓ©n:
MATCH (p1:Person)-[:PARENT]->(p2:Person) RETURN p1, p2
Abra la pestaΓ±a de resultados con Text
y vea una tabla con dos columnas:
βββββββββββββββββ€ββββββββββββββββ β"p1" β"p2" β βββββββββββββββββͺββββββββββββββββ‘ β{"name":"Pam"} β{"name":"Bob"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Tom"} β{"name":"Bob"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Tom"} β{"name":"Liz"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Kate"}β{"name":"Liz"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Mary"}β{"name":"Ann"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Bob"} β{"name":"Ann"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Bob"} β{"name":"Pat"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Dick"}β{"name":"Jim"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Ann"} β{"name":"Jim"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Pat"} β{"name":"Joli"}β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Jack"}β{"name":"Joli"}β βββββββββββββββββ΄ββββββββββββββββ
ΒΏQuΓ© mΓ‘s podemos aprender? Por ejemplo, quiΓ©n es el padre de un miembro especΓfico del gΓ©nero, por ejemplo, para Bob:
MATCH (parent:Person)-[:PARENT]->(:Person {name: "Bob"}) RETURN parent.name
βββββββββββββββ β"parent.name"β βββββββββββββββ‘ β"Tom" β βββββββββββββββ€ β"Pam" β βββββββββββββββ
AquΓ, como respuesta, no solicitamos el nodo completo, sino solo su atributo especΓfico.
TambiΓ©n podemos averiguar quiΓ©nes son los hijos de Bob:
MATCH (:Person {name: "Bob"})-[:PARENT]->(child:Person) RETURN child.name
ββββββββββββββ β"child.name"β ββββββββββββββ‘ β"Ann" β ββββββββββββββ€ β"Pat" β ββββββββββββββ
TambiΓ©n podemos preguntar quiΓ©n tiene hijos:
MATCH (parent:Person)-[:PARENT]->(:Person) RETURN parent.name
βββββββββββββββ β"parent.name"β βββββββββββββββ‘ β"Pam" β βββββββββββββββ€ β"Tom" β βββββββββββββββ€ β"Tom" β βββββββββββββββ€ β"Kate" β βββββββββββββββ€ β"Mary" β βββββββββββββββ€ β"Bob" β βββββββββββββββ€ β"Bob" β βββββββββββββββ€ β"Dick" β βββββββββββββββ€ β"Ann" β βββββββββββββββ€ β"Pat" β βββββββββββββββ€ β"Jack" β βββββββββββββββ
Hmm, Tom y Bob se encontraron dos veces, arrΓ©glenlo:
MATCH (parent:Person)-[:PARENT]->(:Person) RETURN DISTINCT parent.name
Agregamos la palabra DISTINCT
al resultado devuelto de la consulta, lo que significa
similar a eso en SQL.
βββββββββββββββ β"parent.name"β βββββββββββββββ‘ β"Pam" β βββββββββββββββ€ β"Tom" β βββββββββββββββ€ β"Kate" β βββββββββββββββ€ β"Mary" β βββββββββββββββ€ β"Bob" β βββββββββββββββ€ β"Dick" β βββββββββββββββ€ β"Ann" β βββββββββββββββ€ β"Pat" β βββββββββββββββ€ β"Jack" β βββββββββββββββ
TambiΓ©n puede notar que Neo4j nos devuelve a los padres en el orden en que fueron ingresados ββen la solicitud CREATE
.
Ahora preguntemos quiΓ©n es abuelo o abuela:
MATCH (grandparent:Person)-[:PARENT]->()-[:PARENT]->(:Person) RETURN DISTINCT grandparent.name
Genial, eso es todo:
ββββββββββββββββββββ β"grandparent.name"β ββββββββββββββββββββ‘ β"Tom" β ββββββββββββββββββββ€ β"Pam" β ββββββββββββββββββββ€ β"Bob" β ββββββββββββββββββββ€ β"Mary" β ββββββββββββββββββββ
En la plantilla de consulta, utilizamos un nodo sin nombre intermedio ()
y dos relaciones de tipo PARENT
.
Ahora descubrimos quiΓ©n es el padre. El padre es un hombre que tiene un hijo. Por lo tanto, nos faltan datos sobre quiΓ©n es el hombre. En consecuencia, para determinar quiΓ©n es una madre, necesita saber quiΓ©n es una mujer. Agregue la informaciΓ³n relevante a nuestra base de datos. Para hacer esto, asignaremos las etiquetas Male
y Female
a los nodos existentes.
MATCH (p:Person) WHERE p.name IN ["Tom", "Dick", "Bob", "Jim", "Jack"] SET p:Male
MATCH (p:Person) WHERE p.name IN ["Pam", "Kate", "Mary", "Liz", "Ann", "Pat", "Joli"] SET p:Female
Expliquemos lo que hicimos aquΓ: seleccionamos todos los nodos etiquetados como Person
, los verificamos
la propiedad de name
acuerdo con la lista dada especificada entre corchetes, y asignΓ³ a los nodos correspondientes la etiqueta Male
o Female
respectivamente.
Comprobar:
MATCH (p:Person) WHERE p:Male RETURN p.name
ββββββββββ β"p.name"β ββββββββββ‘ β"Tom" β ββββββββββ€ β"Bob" β ββββββββββ€ β"Dick" β ββββββββββ€ β"Jack" β ββββββββββ€ β"Jim" β ββββββββββ
MATCH (p:Person) WHERE p:Female RETURN p.name
ββββββββββ β"p.name"β ββββββββββ‘ β"Pam" β ββββββββββ€ β"Kate" β ββββββββββ€ β"Mary" β ββββββββββ€ β"Liz" β ββββββββββ€ β"Ann" β ββββββββββ€ β"Pat" β ββββββββββ€ β"Joli" β ββββββββββ
Solicitamos todos los nodos etiquetados como Person
, que tambiΓ©n tienen una etiqueta de Male
o Female
, respectivamente. Pero podrΓamos hacer que nuestras solicitudes sean un poco diferentes:
MATCH (p:Person:Male) RETURN p.name MATCH (p:Person:Female) RETURN p.name
Echemos un vistazo a nuestro grΓ‘fico nuevamente:

Neo4j Browser pintΓ³ los nodos en dos colores diferentes segΓΊn las marcas de Male y
Hembra
Ok, ahora podemos consultar a todos los padres de la base de datos:
MATCH (p:Person:Male)-[:PARENT]->(:Person) RETURN DISTINCT p.name
ββββββββββ β"p.name"β ββββββββββ‘ β"Tom" β ββββββββββ€ β"Bob" β ββββββββββ€ β"Dick" β ββββββββββ€ β"Jack" β ββββββββββ
Y madres:
MATCH (p:Person:Female)-[:PARENT]->(:Person) RETURN DISTINCT p.name
ββββββββββ β"p.name"β ββββββββββ‘ β"Pam" β ββββββββββ€ β"Kate" β ββββββββββ€ β"Mary" β ββββββββββ€ β"Ann" β ββββββββββ€ β"Pat" β ββββββββββ
Ahora formulemos una relaciΓ³n de hermano y hermana. X es hermano de Y,
si Γ©l es un hombre, y para X e Y hay al menos un padre comΓΊn. Del mismo modo para
relaciΓ³n hermana
Actitud del hermano en Cypher:
MATCH (brother:Person:Male)<-[:PARENT]-()-[:PARENT]->(p:Person) RETURN brother.name, p.name
ββββββββββββββββ€βββββββββ β"brother.name"β"p.name"β ββββββββββββββββͺβββββββββ‘ β"Bob" β"Liz" β ββββββββββββββββ΄βββββββββ
Actitud de hermana en Cypher:
MATCH (sister:Person:Female)<-[:PARENT]-()-[:PARENT]->(p:Person) RETURN sister.name, p.name
βββββββββββββββ€βββββββββ β"sister.name"β"p.name"β βββββββββββββββͺβββββββββ‘ β"Liz" β"Bob" β βββββββββββββββΌβββββββββ€ β"Ann" β"Pat" β βββββββββββββββΌβββββββββ€ β"Pat" β"Ann" β βββββββββββββββ΄βββββββββ
Entonces, podemos averiguar quiΓ©n es el padre y quiΓ©n es el abuelo o la abuela. ΒΏPero quΓ© hay de los ancestros mΓ‘s distantes? ΒΏCon bisabuelos, bisabuelos, etc.? No escribiremos una regla correspondiente para cada caso, y serΓ‘ cada vez mΓ‘s problemΓ‘tico. De hecho, todo es simple: X es un ancestro de Y si es un ancestro de un padre Y. Cypher proporciona un patrΓ³n *
que le permite requerir una secuencia de relaciones de cualquier longitud:
MATCH (p:Person)-[*]->(s:Person) RETURN DISTINCT p.name, s.name
Realmente hay un problema en esto: serΓ‘ cualquier conexiΓ³n. Agregue una referencia al enlace PARENT
:
MATCH (p:Person)-[:PARENT*]->(s:Person) RETURN DISTINCT p.name, s.name
Para no aumentar la longitud del artΓculo, encontramos a todos los antepasados ββde Joli
:
MATCH (p:Person)-[:PARENT*]->(:Person {name: "Joli"}) RETURN DISTINCT p.name
ββββββββββ β"p.name"β ββββββββββ‘ β"Jack" β ββββββββββ€ β"Pat" β ββββββββββ€ β"Bob" β ββββββββββ€ β"Pam" β ββββββββββ€ β"Tom" β ββββββββββ
Considere una regla mΓ‘s compleja para descubrir quiΓ©n estΓ‘ relacionado con quiΓ©n.
Primero, los parientes son antepasados ββy descendientes, por ejemplo, un hijo y una madre, abuela y nieto. En segundo lugar, los parientes son hermanos y hermanas, incluidos primos, primos segundos, etc., lo que en tΓ©rminos de antepasados ββsignifica que tienen un antepasado comΓΊn. Y en tercer lugar, los familiares que tienen descendientes comunes, por ejemplo, marido y mujer, se consideran familiares.
En Cypher, debe usar UNION
para muchos patrones:
MATCH (r1:Person)-[:PARENT*]-(r2:Person) RETURN DISTINCT r1.name, r2.name UNION MATCH (r1:Person)<-[:PARENT*]-(:Person)-[:PARENT*]->(r2:Person) RETURN DISTINCT r1.name, r2.name UNION MATCH (r1:Person)-[:PARENT*]->(:Person)<-[:PARENT*]-(r2:Person) RETURN DISTINCT r1.name, r2.name
AquΓ, en la primera regla, se usan conexiones, cuya direcciΓ³n no nos importa. Tal conexiΓ³n se indica sin una flecha, solo un guiΓ³n -
. La segunda y tercera regla estΓ‘n escritas de una manera obvia y familiar.
No presentaremos el resultado de la consulta total aquΓ, solo diremos que los pares de familiares encontrados son 132, lo que es consistente con el valor calculado como el nΓΊmero de pares ordenados de 12. TambiΓ©n podrΓamos especificar esta consulta reemplazando la apariciΓ³n de la variable r1
o r2
con (:Person {name: "Liz"})
por ejemplo, sin embargo, en nuestro caso esto no tiene mucho sentido, ya que todas las personas en nuestra base de datos son obviamente familiares.
Esto concluye nuestra discusiΓ³n sobre la identificaciΓ³n de relaciones entre personas en nuestra base de datos.
Por ΓΊltimo, considere cΓ³mo eliminar nodos y enlaces.
Para eliminar a todas nuestras personas, puede ejecutar la solicitud:
MATCH (p:Person) DELETE p
Sin embargo, Neo4j nos dirΓ‘ que no puede eliminar nodos que tienen enlaces.
Por lo tanto, primero eliminamos los enlaces y luego repetimos la eliminaciΓ³n de nodos:
MATCH (p1:Person)-[r]->(p2:Person) DELETE r
Lo que hemos hecho ahora: comparΓ³ a dos personas entre las cuales hay una conexiΓ³n, nombrΓ³ esta conexiΓ³n como r
y luego la eliminΓ³.
ConclusiΓ³n
El artΓculo muestra cΓ³mo usar las capacidades del lenguaje de consulta Cypher usando un ejemplo simple de un grΓ‘fico social. En particular, examinamos cΓ³mo agregar nodos y enlaces con una consulta, cΓ³mo buscar datos relacionados, incluso con enlaces indirectos, y cΓ³mo asignar etiquetas a los nodos. Puede encontrar mΓ‘s informaciΓ³n sobre Cypher en los enlaces a continuaciΓ³n. Un buen punto de partida es la "Neo4j Cypher Refcard".
Neo4j estΓ‘ lejos de ser el ΓΊnico grΓ‘fico DBMS. Entre los otros mΓ‘s populares se encuentran Cayley , Dgraph con lenguaje de consulta GraphQL, ArangoDB y OrientDB multimodelos . De particular interΓ©s puede ser Blazegraph con soporte para RDF y SPARQL.
Referencias
Bibliografia
- Robinson Jan, Weber Jim, Eifrem Emil. Graficar bases de datos. Nuevas caracterΓsticas
para trabajar con datos relacionados / por. del ingles - 2da ed. - M .: DMK-Press,
2016 - 256 s. - Bratko I.ProgramaciΓ³n en lenguaje Prolog para inteligencia artificial:
trans. del ingles - M.: Mir, 1990 .-- 560 p.: Ill.
EpΓlogo
El autor del artΓculo conoce solo dos empresas (ambas de San Petersburgo) que utilizan DBMS de grΓ‘ficos para sus productos. Pero me gustarΓa saber cuΓ‘ntas empresas de lectores de este artΓculo los usan en su desarrollo. Por lo tanto, propongo participar en la encuesta. Escriba tambiΓ©n sobre su experiencia en los comentarios, serΓ‘ muy interesante saberlo.