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 grafos, el tipo de datos de ruta de grafo 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 gráficos de Spanner (GQL), puedes crear rutas de gráficos y realizar consultas en 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.

Construir una ruta de gráfico

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

Te recomendamos que crees una ruta de gráfico mediante 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 Gráfico de patrones.

Ejemplo

En el siguiente ejemplo, la consulta busca patrones de transferencias de dinero entre cuentas 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 consulta ha encontrado el patrón Account -> Transfers -> Account en la base de datos.

Consultar una ruta de un gráfico

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

EDGES

La función EDGES devuelve todos los arcos de una ruta de un grafo. Para obtener información detallada sobre la semántica, consulta EDGES.

Ejemplo

Esta consulta busca una ruta entre dos cuentas que pasa por una cuenta intermedia. Devuelve la cantidad del segundo borde Transfers de la ruta, que puede 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 de una ruta de un 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, a continuación, devuelve una lista 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 busca el primer nodo de una ruta de gráfico. Para obtener información detallada sobre la semántica, consulta PATH_FIRST.

Ejemplo

Esta consulta busca el primer nodo de una ruta de gráfico 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 busca el último nodo de una ruta de un gráfico. Para obtener información detallada sobre la semántica, consulta PATH_LAST.

Ejemplo

Esta consulta busca el último nodo de una ruta de gráfico 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 busca el número de aristas de una ruta de un gráfico. Para obtener información detallada sobre la semántica, consulta PATH_LENGTH.

Ejemplo

Esta consulta busca el número de aristas de una ruta de gráfico que contiene entre una y 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 comprueba 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 comprueba si esta ruta de 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,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

La función IS_TRAIL comprueba si una ruta de un grafo 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 comprueba si esta ruta de 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,20
TRUE 7,16,20

Modos de ruta

En Spanner Graph, el comportamiento predeterminado es devolver todas las rutas, incluidas las rutas con nodos y aristas repetidos. Puede usar los siguientes modos de ruta para incluir o excluir rutas que tengan 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 WALK devuelve todas las rutas, incluidas las que tienen nodos y aristas repetidos. WALK es el modo de ruta predeterminado.

Ejemplo

La siguiente consulta muestra cómo se usa el modo de ruta WALK en un patrón de ruta cuantificado. El primer trayecto de los resultados tiene aristas 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

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

Ejemplo

La siguiente consulta muestra cómo se usa el modo de ruta ACYCLIC en un patrón de ruta cuantificado. La ruta con nodos src y dst iguales se filtra.

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

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

Ejemplo

La siguiente consulta muestra cómo se usa el modo de ruta TRAIL en un patrón de ruta cuantificado. Las rutas con aristas repetidas se filtran.

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

Prefijo de búsqueda de ruta

Puede usar un prefijo de búsqueda de ruta para restringir un patrón de ruta y que devuelva la ruta más corta de 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 el menor número de aristas) que coincide con el patrón de cada partición de datos. Si hay más de un camino más corto por partición, devuelve cualquiera de ellos.

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 práctico

En el siguiente ejemplo de caso práctico, todas las cuentas se han enrutado 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 consulta que devuelva el ID de cuenta 20 podría ser demasiado genérica, ya que empieza por el ID de cuenta 20. Para mostrar resultados más específicos, puedes forzar tu consulta para que solo muestre rutas de gráficos acíclicos sin nodos repetidos. Para ello, puede hacer lo siguiente:

  • Usa MATCH p = ACYCLIC <path_pattern>.
  • Aplicar un filtro IS_ACYCLIC(p) en la consulta

La siguiente consulta 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 que 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 no es habitual porque introduce una nueva variable en la ruta cuantificada mediante nexts para obtener el resultado. Con las variables de ruta, 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 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 dinero.

Resultado

dst unique_starts
7 16, 7

Las rutas son más útiles cuando hay varias rutas cuantificadas. Puedes añadir una restricción para que las rutas encontradas en start pasen por el ID de 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 ha cambiado, el resto de la consulta no tiene por qué hacerlo. Si no se usan variables de ruta, hay casos en los que Spanner no puede saber de forma estática qué ruta cuantificada debe inspeccionar.

Si usas una variable de ruta, 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

Siguientes pasos