Trabalhar com caminhos

Nesta página, descrevemos como trabalhar com caminhos de gráficos no Spanner Graph.

Em bancos de dados de gráficos, o tipo de dados de caminho do gráfico representa uma sequência de nós intercalados com arestas e mostra como esses nós e arestas estão relacionados. Para saber mais sobre o tipo de dados de caminho, consulte Tipo de caminho do gráfico.

Com a linguagem do Spanner Graph (GQL), é possível construir caminhos de gráficos e realizar consultas neles. Os exemplos neste documento usam o mesmo esquema do Spanner Graph encontrado na página Configurar e consultar o Spanner Graph.

Construir um caminho de gráfico

É possível criar 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 construir 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})-[t:Transfers]->{2}(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

É possível usar as seguintes funções específicas de caminho para consultar um caminho de gráfico. Para mais informações 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 ver a semântica detalhada, consulte EDGES.

Exemplo

Essa consulta encontra um caminho entre duas contas que passam por uma conta intermediária. Ele retorna a quantidade da segunda borda 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 ver a 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)-[t:Transfers]->{2}(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 ver a 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 ver a 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ântica detalhada, 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 uma repetição for encontrada. Caso contrário, retorna FALSE. Para ver a semântica detalhada, consulte IS_ACYCLIC.

Exemplo

Essa consulta verifica se o caminho do gráfico tem nós repetidos.

GRAPH FinGraph
MATCH p = (src:Account)-[t:Transfers]->{2}(dst:Account)
RETURN IS_ACYCLIC(p) AS is_acyclic_path,
       ARRAY_TRANSFORM(NODES(p), n->n.id) AS account_ids;

Resultado

is_acyclic_path account_ids
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 uma repetição for encontrada. Caso contrário, retorna FALSE. Para ver a 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)-[t:Transfers]->{3}(dst:Account)
WHERE src.id < dst.id
RETURN IS_TRAIL(p) AS is_trail_path,
       ARRAY_TRANSFORM(t, t->t.id) AS transfer_ids

Resultado

is_trail_path transfer_ids
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 aqueles com nós e arestas repetidos. Você pode usar os seguintes modos de caminho para incluir ou excluir caminhos com nós e arestas repetidos. Para semântica detalhada, consulte a documentação do modo de caminho.

WALK

O modo de caminho WALK retorna todos os caminhos, incluindo aqueles 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 quantificado. O primeiro caminho nos resultados tem arestas repetidas.

GRAPH FinGraph
MATCH p = WALK (src:Account)-[t:Transfers]->{3}(dst:Account)
WHERE src.id < dst.id
RETURN ARRAY_TRANSFORM(t, t->t.id) AS transfer_ids

Resultado

transfer_ids
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 quantificado. O caminho com nós src e dst iguais é filtrado.

GRAPH FinGraph
MATCH p = ACYCLIC (src:Account)-[t:Transfers]->{2}(dst:Account)
RETURN ARRAY_TRANSFORM(NODES(p), n->n.id) AS account_ids

Resultado

account_ids
16,20,7
20,7,16
20,7,16
7,16,20
7,16,20

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 quantificado. Os caminhos com arestas repetidas são filtrados.

GRAPH FinGraph
MATCH p = TRAIL (src:Account)-[t:Transfers]->{3}(dst:Account)
WHERE src.id < dst.id
RETURN ARRAY_TRANSFORM(t, t->t.id) AS transfer_ids

Resultado

transfer_ids
7,16,20
7,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 ver a 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, retorne 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 {is_blocked:true})-[t:Transfers]->{1,4}(b:Account)
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 a seguir, você encontra todas as contas que foram encaminhadas por uma a três contas, 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 ao ID da conta 20 pode ser muito ampla porque começa com o ID da conta 20. Para mostrar resultados mais específicos, você pode forçar sua consulta a mostrar apenas caminhos de gráficos 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 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 receber 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;

Usar 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 em que o dinheiro é transferido.

Result

dst unique_starts
7 16, 7

Os caminhos são mais úteis quando há vários caminhos quantificados. Você pode adicionar uma restrição para que os caminhos encontrados em start passem 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 ser alterado. Sem usar variáveis de caminho, há casos em que não é possível para o Spanner saber estaticamente qual caminho quantificado inspecionar.

Usando uma variável de caminho, é possível 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