A linguagem de consulta Cypher foi originalmente desenvolvida especificamente para o DBMS grรกfico Neo4j . O objetivo do Cypher รฉ fornecer uma linguagem de consulta de banco de dados SQL legรญvel por humanos para bancos de dados de grรกficos. Hoje, o Cypher รฉ suportado por vรกrios DBMSs de grรกficos. O OpenCypher foi criado para padronizar o Cypher.
As noรงรตes bรกsicas de trabalho com o DBMS do Neo4j sรฃo descritas no artigo Noรงรตes bรกsicas de trabalho com o Neo4j em um navegador .
Para se familiarizar com Cypher, considere um exemplo de uma รกrvore genealรณgica emprestada do clรกssico livro de Prolog de I. Bratko. Este exemplo mostra como adicionar nรณs e links a um grรกfico, como atribuir rรณtulos e atributos a eles e como fazer perguntas.

Entรฃo, vamos ter uma รกrvore genealรณgica mostrada na figura abaixo.

Vamos ver como formar o grรกfico correspondente no 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)
Uma solicitaรงรฃo CREATE para adicionar dados a um DBMS grรกfico consiste em duas partes: adicionando nรณs e adicionando links entre eles. Cada nรณ a ser adicionado recebe um nome na estrutura desta solicitaรงรฃo, que รฉ usada para criar links. Nรณs e comunicaรงรตes podem armazenar documentos. No nosso caso, os nรณs contรชm documentos com os campos de nome e os links do documento nรฃo. Tambรฉm nรณs e links podem ser rotulados. No nosso caso, os nรณs recebem o rรณtulo Pessoa e os links sรฃo PAI. O rรณtulo nas solicitaรงรตes รฉ destacado por dois pontos antes do nome.
Portanto, o Neo4j nos disse que: Added 12 labels, created 12 nodes, set 12 properties, created 11 relationships, completed after 9 ms.
Vamos ver o que temos:
MATCH (p:Person) RETURN p

Ninguรฉm nos proรญbe de editar a aparรชncia do grรกfico resultante:

O que pode ser feito com isso? Vocรช pode verificar se, por exemplo, Pam รฉ
Pai de Bob:
MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Bob"}) RETURN ans
Obtemos o subgrรกfico correspondente:

No entanto, isso nรฃo รฉ exatamente o que precisamos. Altere a solicitaรงรฃo:
MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Bob"}) RETURN ans IS NOT NULL
Agora, em resposta, nos tornamos true
. E se perguntarmos:
MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Liz"}) RETURN ans IS NOT NULL
Nรฃo receberemos nada ... Aqui vocรช precisa adicionar a palavra OPTIONAL
, se
o resultado estarรก vazio e false
serรก retornado:
OPTIONAL MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Liz"}) RETURN ans IS NOT NULL
Agora temos a resposta esperada false
.
Em seguida, vocรช pode ver quem รฉ o pai de quem:
MATCH (p1:Person)-[:PARENT]->(p2:Person) RETURN p1, p2
Abra a guia de resultados com Text
e veja uma tabela com duas colunas:
โโโโโโโโโโโโโโโโโคโโโโโโโโโโโโโโโโ โ"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"}โ โโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโ
O que mais podemos aprender? Por exemplo, quem รฉ o pai de um membro especรญfico do gรชnero, por exemplo, para Bob:
MATCH (parent:Person)-[:PARENT]->(:Person {name: "Bob"}) RETURN parent.name
โโโโโโโโโโโโโโโ โ"parent.name"โ โโโโโโโโโโโโโโโก โ"Tom" โ โโโโโโโโโโโโโโโค โ"Pam" โ โโโโโโโโโโโโโโโ
Aqui, como resposta, nรฃo solicitamos o nรณ inteiro, mas apenas seu atributo especรญfico.
Tambรฉm podemos descobrir quem sรฃo os filhos de Bob:
MATCH (:Person {name: "Bob"})-[:PARENT]->(child:Person) RETURN child.name
โโโโโโโโโโโโโโ โ"child.name"โ โโโโโโโโโโโโโโก โ"Ann" โ โโโโโโโโโโโโโโค โ"Pat" โ โโโโโโโโโโโโโโ
Tambรฉm podemos perguntar quem tem filhos:
MATCH (parent:Person)-[:PARENT]->(:Person) RETURN parent.name
โโโโโโโโโโโโโโโ โ"parent.name"โ โโโโโโโโโโโโโโโก โ"Pam" โ โโโโโโโโโโโโโโโค โ"Tom" โ โโโโโโโโโโโโโโโค โ"Tom" โ โโโโโโโโโโโโโโโค โ"Kate" โ โโโโโโโโโโโโโโโค โ"Mary" โ โโโโโโโโโโโโโโโค โ"Bob" โ โโโโโโโโโโโโโโโค โ"Bob" โ โโโโโโโโโโโโโโโค โ"Dick" โ โโโโโโโโโโโโโโโค โ"Ann" โ โโโโโโโโโโโโโโโค โ"Pat" โ โโโโโโโโโโโโโโโค โ"Jack" โ โโโโโโโโโโโโโโโ
Hmm, Tom e Bob se conheceram duas vezes, conserte:
MATCH (parent:Person)-[:PARENT]->(:Person) RETURN DISTINCT parent.name
Adicionamos a palavra DISTINCT
ao resultado de retorno da consulta, o que significa
semelhante ao do SQL.
โโโโโโโโโโโโโโโ โ"parent.name"โ โโโโโโโโโโโโโโโก โ"Pam" โ โโโโโโโโโโโโโโโค โ"Tom" โ โโโโโโโโโโโโโโโค โ"Kate" โ โโโโโโโโโโโโโโโค โ"Mary" โ โโโโโโโโโโโโโโโค โ"Bob" โ โโโโโโโโโโโโโโโค โ"Dick" โ โโโโโโโโโโโโโโโค โ"Ann" โ โโโโโโโโโโโโโโโค โ"Pat" โ โโโโโโโโโโโโโโโค โ"Jack" โ โโโโโโโโโโโโโโโ
Vocรช tambรฉm pode perceber que o Neo4j nos devolve os pais na ordem em que foram inseridos na solicitaรงรฃo CREATE
.
Vamos agora perguntar quem รฉ avรด ou avรณ:
MATCH (grandparent:Person)-[:PARENT]->()-[:PARENT]->(:Person) RETURN DISTINCT grandparent.name
รtimo, รฉ isso:
โโโโโโโโโโโโโโโโโโโโ โ"grandparent.name"โ โโโโโโโโโโโโโโโโโโโโก โ"Tom" โ โโโโโโโโโโโโโโโโโโโโค โ"Pam" โ โโโโโโโโโโโโโโโโโโโโค โ"Bob" โ โโโโโโโโโโโโโโโโโโโโค โ"Mary" โ โโโโโโโโโโโโโโโโโโโโ
No modelo de consulta, usamos um nรณ sem nome intermediรกrio ()
e duas relaรงรตes do tipo PARENT
.
Agora descobrimos quem รฉ o pai. O pai รฉ um homem que tem um filho. Assim, nos faltam dados sobre quem รฉ o homem. Assim, para determinar quem รฉ mรฃe, vocรช precisa saber quem รฉ mulher. Adicione as informaรงรตes relevantes ao nosso banco de dados. Para isso, atribuiremos os rรณtulos Male
e Female
aos nรณs 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
Vamos explicar o que fizemos aqui: selecionamos todos os nรณs rotulados como Person
, verificamos eles
a propriedade name
acordo com a lista especificada entre colchetes e atribuiu aos nรณs correspondentes o rรณtulo Male
ou Female
respectivamente.
Verifique:
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 os nรณs rotulados Person
, que tambรฉm possuem um rรณtulo Male
ou Female
, respectivamente. Mas poderรญamos tornar nossos pedidos um pouco diferentes:
MATCH (p:Person:Male) RETURN p.name MATCH (p:Person:Female) RETURN p.name
Vamos dar uma olhada no nosso grรกfico novamente:

O Neo4j Browser pintou os nรณs em duas cores diferentes, de acordo com as marcas Masculino e
Feminino
Ok, agora podemos consultar todos os pais do banco de dados:
MATCH (p:Person:Male)-[:PARENT]->(:Person) RETURN DISTINCT p.name
โโโโโโโโโโ โ"p.name"โ โโโโโโโโโโก โ"Tom" โ โโโโโโโโโโค โ"Bob" โ โโโโโโโโโโค โ"Dick" โ โโโโโโโโโโค โ"Jack" โ โโโโโโโโโโ
E mรฃes:
MATCH (p:Person:Female)-[:PARENT]->(:Person) RETURN DISTINCT p.name
โโโโโโโโโโ โ"p.name"โ โโโโโโโโโโก โ"Pam" โ โโโโโโโโโโค โ"Kate" โ โโโโโโโโโโค โ"Mary" โ โโโโโโโโโโค โ"Ann" โ โโโโโโโโโโค โ"Pat" โ โโโโโโโโโโ
Vamos agora formular um relacionamento de irmรฃo e irmรฃ. X รฉ irmรฃo de Y,
se ele รฉ homem, e para X e Y hรก pelo menos um pai em comum. Da mesma forma para
irmรฃ de relacionamento.
Atitude do irmรฃo em Cypher:
MATCH (brother:Person:Male)<-[:PARENT]-()-[:PARENT]->(p:Person) RETURN brother.name, p.name
โโโโโโโโโโโโโโโโคโโโโโโโโโ โ"brother.name"โ"p.name"โ โโโโโโโโโโโโโโโโชโโโโโโโโโก โ"Bob" โ"Liz" โ โโโโโโโโโโโโโโโโดโโโโโโโโโ
Atitude de irmรฃ em Cypher:
MATCH (sister:Person:Female)<-[:PARENT]-()-[:PARENT]->(p:Person) RETURN sister.name, p.name
โโโโโโโโโโโโโโโคโโโโโโโโโ โ"sister.name"โ"p.name"โ โโโโโโโโโโโโโโโชโโโโโโโโโก โ"Liz" โ"Bob" โ โโโโโโโโโโโโโโโผโโโโโโโโโค โ"Ann" โ"Pat" โ โโโโโโโโโโโโโโโผโโโโโโโโโค โ"Pat" โ"Ann" โ โโโโโโโโโโโโโโโดโโโโโโโโโ
Assim, podemos descobrir quem รฉ o pai e quem รฉ o avรด ou a avรณ. Mas e os ancestrais mais distantes? Com os bisavรดs, os bisavรณs ou assim por diante? Nรฃo escreveremos uma regra correspondente para cada um desses casos, e serรก sempre mais problemรกtica. De fato, tudo รฉ simples: X รฉ um ancestral para Y se for um ancestral para um pai Y. Cypher fornece um padrรฃo *
que permite exigir uma sequรชncia de relaรงรตes de qualquer tamanho:
MATCH (p:Person)-[*]->(s:Person) RETURN DISTINCT p.name, s.name
Existe realmente um problema nisso: serรฃo quaisquer conexรตes. Adicione uma referรชncia ao link PARENT
:
MATCH (p:Person)-[:PARENT*]->(s:Person) RETURN DISTINCT p.name, s.name
Para nรฃo aumentar o comprimento do artigo, encontramos todos os ancestrais de Joli
:
MATCH (p:Person)-[:PARENT*]->(:Person {name: "Joli"}) RETURN DISTINCT p.name
โโโโโโโโโโ โ"p.name"โ โโโโโโโโโโก โ"Jack" โ โโโโโโโโโโค โ"Pat" โ โโโโโโโโโโค โ"Bob" โ โโโโโโโโโโค โ"Pam" โ โโโโโโโโโโค โ"Tom" โ โโโโโโโโโโ
Considere uma regra mais complexa para descobrir quem estรก relacionado a quem.
Primeiro, parentes sรฃo ancestrais e descendentes, por exemplo, filho e mรฃe, avรณ e neto. Em segundo lugar, parentes sรฃo irmรฃos e irmรฃs, incluindo primos, primos em segundo grau e assim por diante, o que em termos de antepassados โโsignifica que eles tรชm um ancestral em comum. E em terceiro lugar, parentes que tรชm descendentes em comum, por exemplo, marido e mulher, sรฃo considerados parentes.
No Cypher, vocรช precisa usar o UNION
para muitos padrรตes:
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
Aqui, na primeira regra, as conexรตes sรฃo usadas, cuja direรงรฃo nรฃo importa para nรณs. Essa conexรฃo รฉ indicada sem uma seta, apenas um traรงo -
. A segunda e terceira regra sรฃo escritas de uma maneira รณbvia e familiar.
Nรฃo apresentaremos o resultado da consulta total aqui, apenas dizeremos que os pares de parentes encontrados sรฃo 132, o que รฉ consistente com o valor calculado como o nรบmero de pares ordenados de 12. Tambรฉm podemos especificar essa consulta substituindo a ocorrรชncia da variรกvel r1
ou r2
por (:Person {name: "Liz"})
por exemplo, no entanto, no nosso caso, isso nรฃo faz muito sentido, pois todas as pessoas em nosso banco de dados sรฃo obviamente parentes.
Isso conclui nossa discussรฃo sobre a identificaรงรฃo de relacionamentos entre pessoas em nosso banco de dados.
Por fim, considere como remover nรณs e links.
Para excluir todas as nossas pessoas, vocรช pode executar a solicitaรงรฃo:
MATCH (p:Person) DELETE p
No entanto, o Neo4j nos dirรก que vocรช nรฃo pode excluir nรณs que possuem links.
Portanto, primeiro excluรญmos os links e depois repetimos a remoรงรฃo dos nรณs:
MATCH (p1:Person)-[r]->(p2:Person) DELETE r
O que fizemos agora: comparou duas pessoas entre as quais hรก uma conexรฃo, nomeou essa conexรฃo como r
depois a excluiu.
Conclusรฃo
O artigo mostra como usar os recursos da linguagem de consulta Cypher usando um exemplo simples de um grรกfico social. Em particular, examinamos como adicionar nรณs e links com uma consulta, como procurar dados relacionados, inclusive com links indiretos, e como atribuir rรณtulos aos nรณs. Mais informaรงรตes sobre o Cypher podem ser encontradas nos links abaixo. Um bom ponto de partida รฉ o "Neo4j Cypher Refcard".
O Neo4j estรก longe de ser o รบnico grรกfico DBMS. Entre os outros mais populares estรฃo Cayley , Dgraph com linguagem de consulta GraphQL, multi-modelo ArangoDB e OrientDB . De particular interesse pode ser o Blazegraph, com suporte para RDF e SPARQL.
Referรชncias
Bibliografia
- Robinson Jan, Weber Jim, Eifrem Emil. Bases de dados de grรกficos. Novos recursos
por trabalhar com dados relacionados / Por. do inglรชs - 2ยช ed. - M.: DMK-Press,
2016 - 256 s. - Bratko I. Programaรงรฃo em linguagem Prolog para inteligรชncia artificial:
trans. do inglรชs - M .: Mir, 1990 - 560 p .: doente.
Posfรกcio
O autor do artigo conhece apenas duas empresas (ambas de Sรฃo Petersburgo) que usam DBMSs grรกficos para seus produtos. Mas eu gostaria de saber quantas empresas de leitores deste artigo as utilizam em seu desenvolvimento. Portanto, proponho participar da pesquisa. Escreva tambรฉm sobre sua experiรชncia nos comentรกrios, serรก muito interessante saber.