Trabalhar com caminhos

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

A seguir