Bancos de grafos
Quando os relacionamentos são o dado principal, como em redes sociais e detecção de fraude.
O problema: perguntas sobre caminhos
Algumas perguntas não são sobre os dados, e sim sobre as ligações entre eles:
- Quem são os amigos dos meus amigos que eu ainda não sigo?
- Esta conta nova usa o mesmo aparelho, o mesmo cartão ou o mesmo endereço de alguma conta já bloqueada por fraude, mesmo que indiretamente?
- Qual é a menor cadeia de indicações entre estas duas pessoas?
- Se este servidor cair, quais serviços param, direta ou indiretamente?
No modelo relacional, cada passo do caminho é uma junção. "Amigos de amigos" são duas junções da tabela consigo mesma; "a até cinco passos" são cinco, ou uma consulta recursiva. Um banco de grafos guarda as ligações como parte do dado: cada nó sabe quais são os vizinhos, e a consulta descreve o padrão do caminho.
Nós, arestas e Cypher
O grafo tem nós, com rótulos e propriedades, e arestas (relacionamentos), com tipo, direção e propriedades:
(:Pessoa {nome: "Ana"}) -[:SEGUE {desde: 2024}]-> (:Pessoa {nome: "Bia"})No Neo4j, a linguagem de consulta é o Cypher, que desenha o padrão com parênteses para os nós e setas para as arestas. Os amigos de amigos que eu ainda não sigo:
MATCH (eu:Pessoa {nome: "Ana"})-[:SEGUE]->(:Pessoa)-[:SEGUE]->(sugestao:Pessoa)
WHERE sugestao <> eu AND NOT (eu)-[:SEGUE]->(sugestao)
RETURN sugestao.nome, count(*) AS em_comum
ORDER BY em_comum DESCA ideia central do Neo4j é a adjacência sem índice: cada nó guarda referências diretas às suas arestas. Percorrer um passo custa o mesmo com mil ou com um bilhão de nós, porque não depende de buscar num índice a cada salto. Em 2024, a ISO publicou o GQL, um padrão de linguagem de consulta de grafos inspirado no Cypher.
Grafo ou recursão no PostgreSQL, medido
O senso comum diz que o banco relacional não aguenta consultas de grafos. Medimos o mesmo grafo, com 100 mil pessoas e 1 milhão de relações "segue", no Neo4j 5.26 e no PostgreSQL 18, com uma consulta recursiva e índices nas duas colunas da tabela de relações. Cada banco tinha 4 núcleos e 4 GB de memória.
Pessoas alcançáveis a partir de uma pessoa, a até N passos (tempos da segunda execução, com a consulta já planejada):
| Passos | Pessoas alcançadas | PostgreSQL | Neo4j |
|---|---|---|---|
| 4 | 9.787 | 11 ms | 6 ms |
| 5 | 44.230 | 61 ms | 33 ms |
| 6 | 49.999 | 248 ms | 160 ms |
| 7 | 49.999 | 513 ms | 171 ms |
Menor caminho entre duas pessoas (o resultado foi 5 passos nos dois bancos):
| Tempo | |
|---|---|
Neo4j, shortestPath | 1 ms |
| PostgreSQL, busca recursiva até 7 passos | 488 ms |
Até 4 ou 5 passos, a recursão do PostgreSQL ficou na mesma ordem de grandeza do Neo4j. Com a profundidade, a distância cresceu: três vezes a 7 passos. E no menor caminho, a diferença foi de quase 500 vezes. O Neo4j busca a partir das duas pontas e para assim que os caminhos se encontram; a consulta recursiva expande tudo até a profundidade máxima e só depois procura o destino.
Na primeira execução, o Neo4j levou entre 65 e 150 ms só para planejar cada consulta. Em produção, consultas parametrizadas reaproveitam o plano.
A explosão de caminhos
Num grafo em que cada pessoa segue 10 outras, há 10 caminhos de um passo, 100 de dois, um milhão de seis. Contar pessoas distintas é diferente de contar caminhos:
| A até 6 passos | Resultado | Tempo |
|---|---|---|
PostgreSQL, UNION (remove repetidos a cada nível) | 49.999 pessoas | 248 ms |
PostgreSQL, UNION ALL (todos os caminhos) | 1.111.111 caminhos | 815 ms |
Neo4j, com count(DISTINCT x) | 49.999 pessoas | 160 ms |
Neo4j, sem DISTINCT (todos os caminhos) | 1.111.100 caminhos | 602 ms |
Mais de um milhão de caminhos para chegar a 50 mil pessoas. Num grafo real, com pessoas que seguem centenas de outras, e sem limite de profundidade, essa conta não termina. Por isso, toda consulta de caminho variável precisa de um limite de profundidade (*1..4 no Cypher, WHERE d < 4 na recursão), e de remover os repetidos sempre que o que importa são os nós, e não os caminhos.
Onde os grafos brilham
| Uso | A pergunta de grafo |
|---|---|
| Detecção de fraude | Contas que compartilham aparelhos, cartões ou endereços com contas bloqueadas, a vários passos |
| Recomendação | Quem compra o que as pessoas parecidas comigo compram |
| Redes sociais | Amigos de amigos, influência, comunidades |
| Dependências | O que para se este componente cair; ciclos de dependência |
| Permissões por relação | O usuário é membro do time dono da pasta onde está o documento (o ReBAC do tópico de autorização) |
| Grafos de conhecimento | Entidades e relações para busca e para alimentar modelos de linguagem |
E os algoritmos: menor caminho, centralidade (quem é mais conectado), detecção de comunidades, similaridade. O Neo4j oferece esses algoritmos numa biblioteca própria (Graph Data Science).
Por que isso importa quando a IA escreve o código
Um assistente que modela relacionamentos costuma errar para um dos dois lados:
- Escolher um banco de grafos para dados que são tabelas com algumas chaves estrangeiras.
- Ou o contrário: encadear junções em código para caminhos de profundidade variável.
- Consultas de caminho variável sem limite de profundidade (
-[:SEGUE*]->). - Contar caminhos quando a pergunta é sobre nós, sem
DISTINCT. - Consultas Cypher montadas por concatenação de texto, em vez de parâmetros, abrindo espaço para injeção e impedindo o reaproveitamento do plano.
- Nós sem restrição de unicidade na propriedade usada para encontrá-los, gerando duplicatas com
CREATEem vez deMERGE.
O próximo nível compara quando usar um banco de grafos, como modelar e as alternativas.
Prompts para aprofundar
Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.
Bancos de grafos em cinco minutos
Explique em no máximo cinco minutos de leitura o que é um banco de grafos, para alguém que só usou bancos relacionais. Cubra só o essencial: nós, arestas e propriedades, como uma consulta Cypher descreve um caminho, por que percorrer ligações é rápido, a explosão de caminhos e quando o PostgreSQL com consultas recursivas basta. Use os exemplos de amigos de amigos e de detecção de fraude. No final, me faça três perguntas curtas para eu verificar se entendi, e corrija as minhas respostas.
Aprender Cypher pelos padrões
Quero aprender a escrever consultas Cypher. Aja como um mentor e vá por etapas, esperando a minha resposta em cada uma: 1. A sintaxe de nós, arestas, rótulos e propriedades num MATCH. 2. Filtros com WHERE, inclusive padrões negativos como NOT (a)-[:SEGUE]->(b). 3. Agregações com count, collect e ORDER BY. 4. Caminhos de comprimento variável, com limite de profundidade e DISTINCT. 5. MERGE, CREATE e restrições de unicidade. Em cada etapa, me dê um problema sobre um grafo de pessoas e compras, peça que eu escreva a consulta e corrija a minha resposta.
Grafo ou recursão no relacional
Quero entender quando um banco de grafos é mesmo melhor que o PostgreSQL com consultas recursivas. Explique: 1. Como uma consulta WITH RECURSIVE percorre um grafo guardado numa tabela de arestas. 2. A adjacência sem índice dos bancos de grafos e o que ela muda em cada passo. 3. Por que a profundidade e o menor caminho aumentam a diferença. 4. A explosão de caminhos, com UNION e UNION ALL na recursão, e DISTINCT no Cypher. 5. Extensões como Apache AGE. Depois me descreva quatro problemas e pergunte em qual eu usaria grafo e em qual a recursão.
Detecção de fraude com grafos
Quero entender como grafos ajudam a detectar fraude. Explique, com um exemplo de modelo: 1. Por que aparelhos, cartões, endereços e telefones viram nós, e não propriedades. 2. Como achar contas ligadas a uma conta bloqueada, a vários passos. 3. Como identificar anéis de contas que compartilham dados. 4. O problema dos supernós (um endereço de centro de distribuição usado por milhares). 5. Algoritmos de comunidades e centralidade aplicados à fraude. Depois me dê um cenário e peça que eu escreva a consulta que encontraria a fraude.