Cómo trabajar con rutas

En esta página, se describe cómo trabajar con rutas de grafos en Spanner Graph.

En las bases de datos de gráficos, el tipo de datos de ruta de gráfico representa una secuencia de nodos intercalados con aristas y muestra cómo se relacionan estos nodos y aristas. Para obtener más información sobre el tipo de datos de ruta, consulta Tipo de ruta de gráfico.

Con el lenguaje de Spanner Graph (GQL), puedes construir rutas de gráficos y realizar consultas sobre ellas. Los ejemplos de este documento usan el mismo esquema de Spanner Graph que se encuentra en la página Configurar y consultar Spanner Graph.

Cómo construir una ruta de gráfico

Puedes construir una ruta de gráfico creando una variable de ruta en un patrón de gráfico o con la función PATH.

Recomendamos construir una ruta de gráfico con la variable de ruta. El formato para crear una variable de ruta es el siguiente:

MATCH p = PATH_PATTERN

Para obtener más información, consulta Patrón de gráfico.

Ejemplo

En el siguiente ejemplo, la consulta busca patrones de transferencias de dinero entre cuentas dentro de 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, ...}, ...}, ...]

El resultado indica que la búsqueda encontró el patrón Account -> Transfers -> Account en la base de datos.

Cómo consultar una ruta de gráfico

Puedes usar las siguientes funciones específicas de la ruta para consultar una ruta del gráfico. Para obtener información más general sobre las consultas de Spanner Graph, consulta Descripción general de las consultas.

EDGES

La función EDGES devuelve todas las aristas en una ruta de acceso del gráfico. Para obtener información detallada sobre la semántica, consulta EDGES.

Ejemplo

Esta consulta encuentra una ruta entre dos cuentas que pasa por una cuenta intermedia. Devuelve la cantidad del segundo borde Transfers en la ruta, que podría estar entre src y mid o entre mid y 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

La función NODES devuelve todos los nodos en una ruta de acceso del gráfico. Para obtener información detallada sobre la semántica, consulta NODES.

Ejemplo

Esta consulta busca la ruta del gráfico de dos transferencias y, luego, muestra una lista en formato JSON que representa la ruta.

GRAPH FinGraph
MATCH p = (src:Account)-[t:Transfers]->{2}(dst:Account)
RETURN TO_JSON(NODES(p)) AS nodes;

Resultado

nodos
[{"identifier": "...", "properties": {"id": 16}, ...}, {"identifier": "...", "properties": {"id": 20, ...}, ...]

PATH_FIRST

La función PATH_FIRST encuentra el primer nodo en una ruta de gráfico. Para obtener información detallada sobre la semántica, consulta PATH_FIRST.

Ejemplo

Esta consulta encuentra el primer nodo en una ruta de grafo de dos transferencias. Devuelve la etiqueta del nodo Account y el apodo de la cuenta.

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

La función PATH_LAST encuentra el último nodo en una ruta de acceso del gráfico. Para obtener información detallada sobre la semántica, consulta PATH_LAST.

Ejemplo

Esta consulta encuentra el último nodo en una ruta de grafo de dos transferencias. Devuelve la etiqueta del nodo Account y el apodo de la cuenta.

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

La función PATH_LENGTH encuentra la cantidad de aristas en una ruta de gráfico. Para obtener información detallada sobre la semántica, consulta PATH_LENGTH.

Ejemplo

Esta consulta busca la cantidad de aristas en una ruta de grafo que contiene de una a tres transferencias.

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

La función IS_ACYCLIC verifica si una ruta de gráfico tiene nodos repetidos. Devuelve TRUE si se encuentra una repetición; de lo contrario, devuelve FALSE. Para obtener información detallada sobre la semántica, consulta IS_ACYCLIC.

Ejemplo

Esta consulta verifica si esta ruta del gráfico tiene nodos 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 y 7
TRUE 20,7,16
TRUE 20,7,16
FALSO 16,20,16
TRUE 7, 16 y 20
TRUE 7, 16 y 20
FALSO 20,16,20

IS_TRAIL

La función IS_TRAIL verifica si una ruta de gráfico tiene aristas repetidas. Devuelve TRUE si se encuentra una repetición; de lo contrario, devuelve FALSE. Para obtener información detallada sobre la semántica, consulta IS_TRAIL.

Ejemplo

Esta consulta verifica si esta ruta de acceso del gráfico tiene aristas 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 y 20
TRUE 7, 16 y 20

Modos de ruta

En Spanner Graph, el comportamiento predeterminado es devolver todas las rutas, incluidas las que tienen nodos y aristas repetidos. Puedes usar los siguientes modos de ruta para incluir o excluir rutas que tienen nodos y aristas repetidos. Para obtener información detallada sobre la semántica, consulta la documentación del modo de ruta.

WALK

El modo de ruta de acceso WALK devuelve todas las rutas de acceso, incluidas las que tienen nodos y bordes repetidos. WALK es el modo de ruta predeterminado.

Ejemplo

En la siguiente consulta, se muestra el uso del modo de ruta de acceso WALK en un patrón de ruta de acceso cuantificado. El primer camino en los resultados tiene bordes repetidos.

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 y 20
7, 16 y 20

ACYCLIC

El modo de ruta ACYCLIC filtra las rutas que tienen nodos repetidos.

Ejemplo

En la siguiente consulta, se muestra el uso del modo de ruta de acceso ACYCLIC en un patrón de ruta de acceso cuantificado. Se filtra la ruta con nodos src y dst iguales.

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 y 7
20,7,16
20,7,16
7, 16 y 20
7, 16 y 20

TRAIL

El modo de ruta TRAIL filtra las rutas que tienen bordes repetidos.

Ejemplo

En la siguiente consulta, se muestra el uso del modo de ruta de acceso TRAIL en un patrón de ruta de acceso cuantificado. Se filtran las rutas con bordes repetidos.

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 y 20
7, 16 y 20

Prefijo de búsqueda de ruta de acceso

Puedes usar un prefijo de búsqueda de ruta de acceso para restringir un patrón de ruta de acceso y devolver la ruta de acceso más corta desde cada partición de datos. Para obtener información detallada sobre la semántica, consulta Prefijo de búsqueda de ruta.

ANY SHORTEST

El prefijo de búsqueda de ruta ANY SHORTEST devuelve la ruta más corta (la ruta con la menor cantidad de aristas) que coincide con el patrón de cada partición de datos. Si hay más de una ruta más corta por partición, devuelve cualquiera de ellas.

Ejemplo

La siguiente consulta coincide con cualquier ruta 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

Reglas de conversión

Para obtener más información, consulta las reglas de conversión de GRAPH_PATH.

Ejemplo de caso de uso

En el siguiente ejemplo de caso de uso, verás que todas las cuentas se enrutaron a través de una a tres cuentas, desde el ID de cuenta 20.

GRAPH FinGraph
MATCH p = (start:Account {id: 20})-[:Transfers]->{1,3}(dst:Account)
RETURN DISTINCT dst.id AS dst;

Resultado

DST
7
16
20

Sin embargo, una búsqueda que devuelve el ID de la cuenta 20 podría ser demasiado amplia porque comienza con el ID de la cuenta 20. Para mostrar resultados más específicos, puedes forzar tu búsqueda para que muestre solo rutas de grafos acíclicos sin nodos repetidos. Para ello, puedes hacer lo siguiente:

  • Usa MATCH p = ACYCLIC <path_pattern>.
  • Aplica un filtro IS_ACYCLIC(p) en tu búsqueda

En la siguiente consulta, se 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;

Resultado

DST
7
16

Si quieres saber la primera cuenta a través de la cual se transfiere el dinero, puedes ejecutar la siguiente 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;

Esta consulta es poco convencional porque introduce una nueva variable dentro de la ruta cuantificada con nexts para obtener el resultado. Con las variables de ruta de acceso, puedes simplificar la 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;

Si usas NODES(p), se devuelven todos los nodos a lo largo de la ruta. Como la primera cuenta de nodo se especifica como start, la siguiente (en el primer desplazamiento) es la primera cuenta a través de la cual se transfiere el dinero.

Resultado

DST unique_starts
7 16, 7

Las rutas son más útiles cuando hay varias rutas cuantificadas. Puedes agregar una restricción que indique que las rutas encontradas desde start deben pasar por el ID de la cuenta 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;

Aunque la instrucción MATCH cambió, el resto de la consulta no necesita cambiar. Sin usar variables de ruta, hay casos en los que Spanner no puede saber de forma estática qué ruta cuantificada debe inspeccionar.

Con una variable de ruta de acceso, puedes obtener la suma de todas las transferencias:

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;

Resultado

DST participating_neighbor_nodes transfer_amounts
16 7 600
16 7 800

¿Qué sigue?