Esta página descreve como trabalhar com caminhos de gráfico no Spanner Graph.
Em bancos de dados de gráficos, o tipo de dados de caminho de gráfico representa uma sequência de nós entrelaçados com bordas e mostra como esses nós e bordas estão relacionados. Para saber mais sobre o tipo de dados de caminho, consulte Tipo de caminho do gráfico.
Com a Spanner Graph Language (GQL), é possível construir caminhos de gráfico e executar consultas neles. Os exemplos neste documento usam o mesmo esquema do Spanner Graph encontrado na página Configurar e consultar o Spanner Graph.
Criar um caminho de gráfico
É possível construir um caminho de gráfico criando uma variável de caminho em um padrão de gráfico ou
com a função PATH
.
Recomendamos criar um caminho de gráfico usando a variável de caminho. O formato para criar uma variável de caminho é:
MATCH p = PATH_PATTERN
Para mais informações, consulte Padrão de gráfico.
Exemplo
No exemplo a seguir, a consulta encontra padrões de transferências de dinheiro entre
contas em FinGraph
.
GRAPH FinGraph
MATCH p = (src:Account {id: 16})-[t1:Transfers]->(mid:Account)-[t2:Transfers]->
(dst:Account {id: 7})
RETURN TO_JSON(p) AS full_path;
Resultado
full_path |
---|
[{"identifier": ..., "properties": {"id": 16, ...}, ...}, {"identifier": ..., "properties": {"amount": 300.0, ...}, ...}, ...] |
O resultado indica que a consulta encontrou o padrão Account -> Transfers -> Account
no banco de dados.
Consultar um caminho de gráfico
Use as funções específicas de caminho a seguir para consultar um caminho de gráfico. Para informações mais gerais sobre consultas do Spanner Graph, consulte Visão geral das consultas.
EDGES
A função EDGES
retorna todas as arestas em um caminho de gráfico. Para semântica
detalhada, consulte EDGES
.
Exemplo
Essa consulta encontra um caminho entre duas contas que passam por uma conta intermediária.
Ela retorna o valor da segunda aresta Transfers
no caminho, que pode estar
entre src
e mid
ou entre mid
e dst
.
GRAPH FinGraph
MATCH p = (src:Account {id: 7})-[t1:Transfers]->{1,3}(mid:Account)-[t2:Transfers]->
{1,3}(dst:Account {id: 16})
LET second_edge = EDGES(p)[1]
RETURN DISTINCT src.id AS src, dst.id AS dst, second_edge.amount AS second_edge_amount;
Resultado
src | dst | second_edge_amount |
---|---|---|
7 | 16 | 300 |
NODES
A função NODES
retorna todos os nós em um caminho de gráfico. Para semântica
detalhada, consulte NODES
.
Exemplo
Essa consulta encontra o caminho do gráfico de duas transferências e retorna uma lista JSON que representa o caminho.
GRAPH FinGraph
MATCH p = (src:Account)-[t1:Transfers]->(mid:Account)-[t2:Transfers]->(dst:Account)
RETURN TO_JSON(NODES(p)) AS nodes;
Resultado
nós |
---|
[{"identifier": "...", "properties": {"id": 16}, ...}, {"identifier": "...", "properties": {"id": 20, ...}, ...] |
… |
PATH_FIRST
A função PATH_FIRST
encontra o primeiro nó em um caminho de gráfico. Para semântica
detalhada, consulte PATH_FIRST
.
Exemplo
Essa consulta encontra o primeiro nó em um caminho de gráfico de duas transferências. Ele retorna o
rótulo do nó Account
e o apelido da conta.
GRAPH FinGraph
MATCH p = -[:Transfers]->{1,3}(dst:Account{id: 7})
RETURN DISTINCT PATH_FIRST(p).id AS can_reach_target;
Resultado
can_reach_target |
---|
7 |
16 |
20 |
PATH_LAST
A função PATH_LAST
encontra o último nó em um caminho de gráfico. Para semântica
detalhada, consulte PATH_LAST
.
Exemplo
Essa consulta encontra o último nó em um caminho de gráfico de duas transferências. Ele retorna o
rótulo do nó Account
e o apelido da conta.
GRAPH FinGraph
MATCH p =(start:Account{id: 7})-[:Transfers]->{1,3}
RETURN DISTINCT PATH_LAST(p).id as can_reach_target;
Resultado
can_reach_target |
---|
7 |
16 |
20 |
PATH_LENGTH
A função PATH_LENGTH
encontra o número de arestas em um caminho de gráfico. Para
semânticas detalhadas, consulte PATH_LENGTH
.
Exemplo
Essa consulta encontra o número de arestas em um caminho de gráfico que contém de uma a três transferências.
GRAPH FinGraph
MATCH p = (src:Account)-[e:Transfers]->{1,3}(dst:Account)
RETURN PATH_LENGTH(p) AS num_transfers, COUNT(*) AS num_paths;
Resultado
num_transfers | num_paths |
---|---|
1 | 5 |
2 | 7 |
3 | 11 |
IS_ACYCLIC
A função IS_ACYCLIC
verifica se um caminho de gráfico tem nós repetidos. Ele retorna
TRUE
se a repetição for encontrada. Caso contrário, ele retorna FALSE
. Para semântica
detalhada, consulte IS_ACYCLIC
.
Exemplo
Essa consulta verifica se esse caminho de gráfico tem nós repetidos.
GRAPH FinGraph
MATCH p = (src:Account)-[t1:Transfers]->(mid:Account)-[t2:Transfers]->(dst:Account)
RETURN IS_ACYCLIC(p) AS is_acyclic_path, src.id AS source_account_id,
mid.id AS mid_account_id, dst.id AS dst_account_id;
Resultado
is_acyclic_path | source_account_id | mid_account_id | dst_account_id |
---|---|---|---|
TRUE | 16 | 20 | 7 |
TRUE | 20 | 7 | 16 |
TRUE | 20 | 7 | 16 |
FALSO | 16 | 20 | 16 |
TRUE | 7 | 16 | 20 |
TRUE | 7 | 16 | 20 |
FALSO | 20 | 16 | 20 |
IS_TRAIL
A função IS_TRAIL
verifica se um caminho de gráfico tem arestas repetidas. Ele retorna
TRUE
se a repetição for encontrada. Caso contrário, ele retorna FALSE
. Para semântica
detalhada, consulte IS_TRAIL
.
Exemplo
Essa consulta verifica se o caminho do gráfico tem arestas repetidas.
GRAPH FinGraph
MATCH p = (src:Account)-[t1:Transfers]->(mid1:Account)-[t2:Transfers]->
(mid2:Account)-[t3:Transfers]->(dst:Account)
WHERE src.id < dst.id
RETURN IS_TRAIL(p) AS is_trail_path, t1.id AS t1_id, t2.id AS t2_id, t3.id AS t3_id;
Resultado
is_trail_path | t1_id | t2_id | t3_id |
---|---|---|---|
FALSO | 16 | 20 | 16 |
TRUE | 7 | 16 | 20 |
TRUE | 7 | 16 | 20 |
Modos de caminho
No Spanner Graph, o comportamento padrão é retornar todos os caminhos, incluindo caminhos com nós e arestas repetidas. É possível usar os modos de caminho a seguir para incluir ou excluir caminhos com nós e arestas repetidos. Para semânticas detalhadas, consulte a documentação do Pathmode.
WALK
O modo de caminho WALK
retorna todos os caminhos, incluindo caminhos com nós e arestas
repetidos. WALK
é o modo de caminho padrão.
Exemplo
A consulta a seguir demonstra o uso do modo de caminho WALK
em um
padrão de caminho não quantificado. O primeiro caminho nos resultados usa a mesma borda
para t1
e t3
.
GRAPH FinGraph
MATCH p = WALK (src:Account)-[t1:Transfers]->(mid1:Account)-[t2:Transfers]->
(mid2:Account)-[t3:Transfers]->(dst:Account)
WHERE src.id < dst.id
RETURN t1.id AS transfer1_id, t2.id AS transfer2_id, t3.id AS transfer3_id;
Resultado
transfer1_id | transfer2_id | transfer3_id |
---|---|---|
16 | 20 | 16 |
7 | 16 | 20 |
7 | 16 | 20 |
ACYCLIC
O modo de caminho ACYCLIC
filtra caminhos com nós repetidos.
Exemplo
A consulta a seguir demonstra o uso do modo de caminho ACYCLIC
em um
padrão de caminho não quantificado.
O caminho com nós src
e dst
iguais é filtrado.
GRAPH FinGraph
MATCH p = ACYCLIC (src:Account)-[t1:Transfers]->(mid:Account)-[t2:Transfers]->(dst:Account)
RETURN src.id AS account1_id, mid.id AS account2_id, dst.id AS account3_id;
Resultado
account1_id | account2_id | account3_id |
---|---|---|
20 | 7 | 16 |
20 | 7 | 16 |
7 | 16 | 20 |
7 | 16 | 20 |
16 | 20 | 7 |
TRAIL
O modo de caminho TRAIL
filtra caminhos com arestas repetidas.
Exemplo
A consulta a seguir demonstra o uso do modo de caminho TRAIL
em um
padrão de caminho não quantificado. O caminho com bordas t1
e t3
iguais é
filtrado.
GRAPH FinGraph
MATCH p = TRAIL (src:Account)-[t1:Transfers]->(mid1:Account)-[t2:Transfers]->
(mid2:Account)-[t3:Transfers]->(dst:Account)
RETURN
t1.id AS transfer1_id, t2.id AS transfer2_id, t3.id AS transfer3_id;
Resultado
transfer1_id | transfer2_id | transfer3_id |
---|---|---|
16 | 20 | 7 |
16 | 20 | 7 |
20 | 7 | 16 |
20 | 7 | 16 |
7 | 16 | 20 |
7 | 16 | 20 |
7 | 16 | 20 |
7 | 16 | 20 |
20 | 16 | 20 |
Prefixo da pesquisa de caminho
É possível usar um prefixo de pesquisa de caminho para restringir um padrão de caminho e retornar o caminho mais curto de cada partição de dados. Para semântica detalhada, consulte Prefixo de pesquisa de caminho.
ANY SHORTEST
O prefixo de pesquisa de caminho ANY SHORTEST
retorna o caminho mais curto (o caminho com
o menor número de arestas) que corresponde ao padrão de cada partição de dados. Se
houver mais de um caminho mais curto por partição, ele retornará qualquer um deles.
Exemplo
A consulta a seguir corresponde a qualquer caminho entre cada par de [a, b]
.
GRAPH FinGraph
MATCH p = ANY SHORTEST (a:Account)-[t:Transfers]->{1,4}(b:Account)
WHERE a.is_blocked
LET total_amount = SUM(t.amount)
RETURN a.id AS account1_id, total_amount, b.id AS account2_id;
Resultado
account1_id | total_amount | account2_id |
---|---|---|
16 | 500 | 16 |
16 | 800 | 7 |
16 | 300 | 20 |
Regras de conversão
Para mais informações, consulte Regras de conversão de GRAPH_PATH.
Exemplo de caso de uso
No exemplo de caso de uso abaixo, todas as contas foram roteadas
por uma a três contas, a partir do ID da conta 20
.
GRAPH FinGraph
MATCH p = (start:Account {id: 20})-[:Transfers]->{1,3}(dst:Account)
RETURN DISTINCT dst.id AS dst;
Result
dst |
---|
7 |
16 |
20 |
No entanto, uma consulta que retorna para o ID da conta 20
pode ser muito ampla
porque começa com o ID da conta 20
. Para mostrar resultados mais específicos, é possível
forçar a consulta a mostrar apenas caminhos de gráfico acíclicos sem nós repetidos.
Para isso, você pode:
- Use
MATCH p = ACYCLIC <path_pattern>
; ou - Aplicar um filtro
IS_ACYCLIC(p)
na consulta
A consulta a seguir usa MATCH p = ACYCLIC PATH_PATTERN
:
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->{1,3}(dst:Account)
RETURN DISTINCT dst.id AS dst;
Result
dst |
---|
7 |
16 |
Se você quiser saber a primeira conta pela qual o dinheiro foi transferido, execute a seguinte consulta:
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})(-[:Transfers]->
(nexts:Account)){1,3}(dst:Account)
RETURN dst.id AS dst, ARRAY_AGG(DISTINCT nexts[0].id) AS unique_starts;
Essa consulta é não convencional porque introduz uma nova variável no caminho quantificado usando nexts
para gerar o resultado. Com as variáveis de caminho, é possível
simplificar a consulta:
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->{1,3}(dst:Account)
RETURN dst.id AS dst, ARRAY_AGG(DISTINCT NODES(p)[OFFSET(1)].id) AS unique_starts;
O uso de NODES(p)
retorna todos os nós ao longo do caminho. Como a primeira conta de nó
é especificada como start
, a próxima (no primeiro deslocamento) é a primeira
conta para a qual o dinheiro é transferido.
Result
dst | unique_starts |
---|---|
7 | 16, 7 |
Os caminhos são mais úteis quando há vários caminhos quantificados. É possível adicionar
uma restrição que os caminhos encontrados em start
precisam passar pelo ID da conta
7
:
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->
{1,3}(mid:Account {id: 7})-[:Transfers]->{1,3}(dst:Account)
RETURN dst.id AS dst,
ARRAY_AGG(DISTINCT NODES(p)[OFFSET(1)].id) AS unique_starts;
Embora a instrução MATCH
tenha mudado, o restante da consulta não precisa
mudar. Sem o uso de variáveis de caminho, há casos em que o Spanner não consegue saber estaticamente qual caminho quantificado inspecionar.
Usando uma variável de caminho, você pode receber a soma de todas as transferências:
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->
{1,3}(mid:Account {id: 7})-[:Transfers]->{1,3}(dst:Account)
LET all_transfers = EDGES(p)
LET transfer_amounts = SUM(all_transfers.amount)
RETURN dst.id AS dst,
ARRAY_AGG(DISTINCT NODES(p)[OFFSET(1)].id) AS participating_neighbor_nodes, transfer_amounts;
Result
dst | participating_neighbor_nodes | transfer_amounts |
---|---|---|
16 | 7 | 600 |
16 | 7 | 800 |