Descripción general de la consulta de gráficos

En este documento, se proporciona una descripción general del lenguaje de consultas de gráficos (GQL) y cómo escribir consultas de gráficos para BigQuery Graph. Puedes ejecutar consultas de grafos para encontrar patrones, recorrer relaciones y obtener estadísticas a partir de tu grafo de propiedad. En los ejemplos de este documento, se hace referencia a un gráfico llamado FinGraph, que muestra las relaciones entre las personas, las cuentas que poseen y las transferencias entre cuentas. Para obtener información sobre la definición del gráfico, consulta el ejemplo de FinGraph.

Estructura de la consulta

Una consulta de gráfico consta del nombre del gráfico, seguido de una o más instrucciones de consulta lineales. Cada consulta lineal contiene una o más sentencias, que te permiten trabajar con datos de grafos para encontrar coincidencias de patrones, definir variables, filtrar y transformar datos intermedios, y devolver resultados. Ejecutas una consulta de gráfico de la misma manera que ejecutas una consulta SQL en BigQuery.

Ejemplo de estructura de consulta de grafo.
Ejemplo de la estructura de una consulta de gráfico.

Coincidencia de patrones de grafos

La coincidencia de patrones de gráficos encuentra patrones específicos dentro de tu gráfico. Los patrones más básicos son los patrones de elementos, como los patrones de nodos que coinciden con nodos y los patrones de aristas que coinciden con aristas.

Patrones de nodos

Un patrón de nodo coincide con los nodos de tu gráfico. Este patrón contiene paréntesis coincidentes, que pueden incluir de forma opcional una variable de patrón de gráfico, una expresión de etiqueta y filtros de propiedad.

Cómo encontrar todos los nodos

La siguiente consulta devuelve todos los nodos del grafo. La variable n, una variable de patrón de grafo, se vincula a los nodos coincidentes. En este caso, el patrón de nodo coincide con todos los nodos del gráfico.

GRAPH graph_db.FinGraph
MATCH (n)
RETURN LABELS(n) AS label, n.id;

Esta consulta devuelve label y id:

label id
Account 7
Account 16
Account 20
Person 1
Person 2
Person 3

Cómo encontrar todos los nodos con una etiqueta específica

La siguiente consulta coincide con todos los nodos del grafo que tienen la etiqueta Person. La consulta devuelve la etiqueta y algunas propiedades de los nodos coincidentes.

GRAPH graph_db.FinGraph
MATCH (p:Person)
RETURN LABELS(p) AS label, p.id, p.name;

Esta consulta devuelve las siguientes propiedades de los nodos coincidentes:

label id name
Person 1 Alex
Person 2 Dana
Person 3 Lee

Cómo encontrar todos los nodos que coinciden con una expresión de etiqueta

Puedes crear una expresión de etiqueta con uno o más operadores lógicos. Por ejemplo, la siguiente consulta coincide con todos los nodos del grafo que tienen la etiqueta Person o Account. La variable de patrón de gráfico n expone todas las propiedades de los nodos con la etiqueta Person o Account.

GRAPH graph_db.FinGraph
MATCH (n:Person|Account)
RETURN LABELS(n) AS label, n.id, n.birthday, n.create_time;

Ten en cuenta lo siguiente en los resultados de esta búsqueda:

  • Todos los nodos tienen la propiedad id.
  • Los nodos que coinciden con la etiqueta Account tienen la propiedad create_time, pero no la propiedad birthday. La propiedad birthday es NULL para estos nodos.
  • Los nodos que coinciden con la etiqueta Person tienen la propiedad birthday, pero no la propiedad create_time. La propiedad create_time es NULL para estos nodos.
label id birthday create_time
Account 7 NULL 2020-01-10T14:22:20.222Z
Account 16 NULL 2020-01-28T01:55:09.206Z
Account 20 NULL 2020-02-18T13:44:20.655Z
Person 1 1991-12-21T08:00:00Z NULL
Person 2 1980-10-31T08:00:00Z NULL
Person 3 1986-12-07T08:00:00Z NULL

Encuentra todos los nodos que coinciden con la expresión de etiqueta y el filtro de propiedad

La siguiente consulta coincide con todos los nodos del gráfico que tienen la etiqueta Person y la propiedad id igual a 1:

GRAPH graph_db.FinGraph
MATCH (p:Person {id: 1})
RETURN LABELS(p) AS label, p.id, p.name, p.birthday;

El resultado es similar al siguiente:

label id name birthday
Person 1 Alex 1991-12-21T08:00:00Z

Puedes usar la cláusula WHERE para formar condiciones de filtrado más complejas en etiquetas y propiedades.

La siguiente consulta usa la cláusula WHERE para filtrar los nodos en los que la propiedad birthday es anterior a 1990-01-10:

GRAPH graph_db.FinGraph
MATCH (p:Person WHERE p.birthday < '1990-01-10')
RETURN LABELS(p) AS label, p.name, p.birthday;

El resultado es similar al siguiente:

label name birthday
Person Dana 1980-10-31T08:00:00Z
Person Lee 1986-12-07T08:00:00Z

Patrones de borde

Un patrón de borde coincide con los bordes o las relaciones entre los nodos. Los patrones de borde se incluyen entre corchetes ([]) y contienen símbolos como -, -> o <- para indicar direcciones. Un patrón de borde puede incluir, de forma opcional, una variable de patrón de grafo para vincularla a los bordes coincidentes.

Encuentra todas las aristas con etiquetas coincidentes

Esta consulta devuelve todas las aristas del grafo con la etiqueta Transfers. La consulta vincula la variable del patrón de grafo e a las aristas coincidentes.

GRAPH graph_db.FinGraph
MATCH -[e:Transfers]->
RETURN e.Id as src_account, e.order_number;

El resultado es similar al siguiente:

src_account order_number
7 304330008004315
7 304120005529714
16 103650009791820
20 304120005529714
20 302290001255747

Encuentra todas las aristas que coinciden con la expresión de etiqueta y el filtro de propiedad.

El patrón de borde de la siguiente consulta usa una expresión de etiqueta y un filtro de propiedad para encontrar todos los bordes etiquetados como Transfers que coinciden con un número de pedido especificado:

GRAPH graph_db.FinGraph
MATCH -[e:Transfers {order_number: "304120005529714"}]->
RETURN e.Id AS src_account, e.order_number;

El resultado es similar al siguiente:

src_account order_number
7 304120005529714
20 304120005529714

Encuentra todos los bordes con cualquier patrón de borde de dirección.

Puedes usar el patrón de borde any direction (-[]-) en una consulta para hacer coincidir bordes en cualquier dirección. La siguiente consulta encuentra todas las transferencias con una cuenta bloqueada:

GRAPH graph_db.FinGraph
MATCH (account:Account)-[transfer:Transfers]-(:Account {is_blocked:true})
RETURN transfer.order_number, transfer.amount;

El resultado es similar al siguiente:

order_number amount
304330008004315 300
304120005529714 100
103650009791820 300
302290001255747 200

Patrones de ruta de acceso

Un patrón de ruta de acceso se compila a partir de patrones de nodos y aristas alternados.

Cómo encontrar todas las rutas desde un nodo específico con un patrón de ruta

La siguiente consulta encuentra todas las transferencias a una cuenta iniciadas desde una cuenta propiedad de Person con id igual a 2.

Cada resultado coincidente representa una ruta desde un nodo Person cuando id es igual a 2 a través de un nodo Account conectado con una arista Owns, hacia otro nodo Account con una arista Transfers.

GRAPH graph_db.FinGraph
MATCH
  (p:Person {id: 2})-[:Owns]->(account:Account)-[t:Transfers]->
  (to_account:Account)
RETURN
  p.id AS sender_id, account.id AS from_id, to_account.id AS to_id;

El resultado es similar al siguiente:

sender_id from_id to_id
2 20 7
2 20 16

Patrones de ruta de acceso cuantificados

Un patrón cuantificado repite un patrón dentro de un rango especificado.

Coincide con un patrón de borde cuantificado

Para encontrar rutas de longitud variable, puedes aplicar un cuantificador a un patrón de borde. La siguiente consulta muestra esto buscando cuentas de destino que estén a una o tres transferencias de una fuente Account con un valor de id de 7.

La consulta aplica el cuantificador {1, 3} al patrón de borde -[e:Transfers]->. Esto indica a la búsqueda que debe coincidir con las rutas que repiten el patrón de borde Transfers una, dos o tres veces. La cláusula WHERE se usa para excluir la cuenta de origen de los resultados. La función ARRAY_LENGTH se usa para acceder a e de group variable.

GRAPH graph_db.FinGraph
MATCH (src:Account {id: 7})-[e:Transfers]->{1, 3}(dst:Account)
WHERE src != dst
RETURN src.id AS src_account_id, ARRAY_LENGTH(e) AS path_length, dst.id AS dst_account_id;

El resultado es similar al siguiente:

src_account_id path_length dst_account_id
7 1 16
7 1 16
7 3 16
7 3 16
7 2 20
7 2 20

Algunas filas de los resultados se repiten. Esto se debe a que pueden existir varias rutas que coincidan con el patrón entre los mismos nodos de origen y destino, y la consulta devuelve todas ellas.

Cómo hacer coincidir un patrón de ruta de acceso cuantificado

La siguiente consulta encuentra rutas entre nodos Account con una o dos aristas Transfers a través de cuentas intermedias que están bloqueadas.

El patrón de ruta de acceso entre paréntesis se cuantifica, y su cláusula WHERE especifica condiciones para el patrón repetido.

GRAPH graph_db.FinGraph
MATCH
  (src:Account)
  ((a:Account)-[:Transfers]->(b:Account {is_blocked:true}) WHERE a != b){1,2}
    -[:Transfers]->(dst:Account)
RETURN src.id AS src_account_id, dst.id AS dst_account_id;

El resultado es similar al siguiente:

src_account_id dst_account_id
7 20
7 20
20 20

Variables de grupo

Una variable de patrón de gráfico declarada en un patrón cuantificado se convierte en una variable de grupo cuando se accede a ella fuera de ese patrón. Luego, se vincula a un array de elementos del gráfico coincidentes.

Puedes acceder a una variable de grupo como un array. Sus elementos de gráfico se conservan en el orden en que aparecen a lo largo de las rutas coincidentes. Puedes agregar una variable de grupo con la agregación horizontal.

Variable del grupo de acceso

En el siguiente ejemplo, se accede a la variable e de la siguiente manera:

  • Como una variable de patrón de gráfico vinculada a un solo borde en la cláusula WHEREe.amount > 100 cuando se encuentra dentro del patrón cuantificado.
  • Como una variable de grupo vinculada a un array de elementos de borde en ARRAY_LENGTH(e) en la instrucción RETURN cuando está fuera del patrón cuantificado.
  • Es una variable de grupo vinculada a un array de elementos de borde, que SUM(e.amount) agrega fuera del patrón cuantificado. Este es un ejemplo de agregación horizontal.
GRAPH graph_db.FinGraph
MATCH
  (src:Account {id: 7})-[e:Transfers WHERE e.amount > 100]->{0,2}
  (dst:Account)
WHERE src.id != dst.id
LET total_amount = SUM(e.amount)
RETURN
  src.id AS src_account_id, ARRAY_LENGTH(e) AS path_length,
  total_amount, dst.id AS dst_account_id;

El resultado es similar al siguiente:

src_account_id path_length total_amount dst_account_id
7 1 300 16
7 2 600 20

Prefijos de búsqueda de rutas

Para limitar las rutas coincidentes dentro de los grupos que comparten nodos de origen y destino, puedes usar el prefijo de búsqueda de ruta ANY, ANY SHORTEST o ANY CHEAPEST. Solo puedes aplicar estos prefijos antes de un patrón de ruta completo y no puedes aplicarlos dentro de paréntesis.

Coincidencia con ANY

La siguiente consulta encuentra todas las cuentas únicas a las que se puede acceder y que están a uno o dos nodos Transfers de distancia de un nodo Account determinado.

El prefijo de búsqueda de ruta ANY garantiza que la consulta solo devuelva una ruta entre un par único de nodos src y dst Account. En el siguiente ejemplo, aunque puedes llegar al nodo Account con {id: 16} en dos rutas de acceso diferentes desde el nodo de origen Account, la consulta solo devuelve una ruta de acceso.

GRAPH graph_db.FinGraph
MATCH ANY (src:Account {id: 7})-[e:Transfers]->{1,2}(dst:Account)
LET ids_in_path = ARRAY_CONCAT(ARRAY_AGG(e.Id), [dst.Id])
RETURN src.id AS src_account_id, dst.id AS dst_account_id, ids_in_path;

El resultado es similar al siguiente:

src_account_id dst_account_id ids_in_path
7 16 7,16
7 20 7,16,20

Coincidencia con ANY SHORTEST

El prefijo de búsqueda de ruta de acceso ANY SHORTEST devuelve una sola ruta de acceso para cada par de nodos de origen y destino, seleccionada entre las que tienen la menor cantidad de aristas.

Por ejemplo, la siguiente consulta encuentra una de las rutas más cortas entre un nodo Account con un valor id de 7 y un nodo Account con un valor id de 20. La consulta considera rutas de acceso con entre uno y tres bordes Transfers.

GRAPH graph_db.FinGraph
MATCH ANY SHORTEST (src:Account {id: 7})-[e:Transfers]->{1, 3}(dst:Account {id: 20})
RETURN src.id AS src_account_id, dst.id AS dst_account_id, ARRAY_LENGTH(e) AS path_length;

El resultado es similar al siguiente:

src_account_id dst_account_id path_length
7 20 2

Coincidencia con ANY CHEAPEST

El prefijo de búsqueda de ruta ANY CHEAPEST garantiza que, para cada par de cuentas de origen y destino, la consulta devuelva solo una ruta con el costo de procesamiento total mínimo.

La siguiente consulta encuentra una ruta con el costo de procesamiento total mínimo entre los nodos Account. Este costo se basa en la suma de la propiedad amount de las aristas Transfers. La búsqueda considera rutas con entre uno y tres bordes de Transfers.

GRAPH graph_db.FinGraph
MATCH ANY CHEAPEST (src:Account)-[e:Transfers COST e.amount]->{1,3}(dst:Account)
LET total_cost = sum(e.amount)
RETURN src.id AS src_account_id, dst.id AS dst_account_id, total_cost;

El resultado es similar al siguiente:

src_account_id dst_account_id total_cost
7 7 900
7 16 100
7 20 400
16 7 800
16 16 500
16 20 300
20 7 500
20 16 200
20 20 500

Patrones de gráficos

Un patrón de gráfico consta de uno o más patrones de ruta de acceso, separados por una coma (,). Los patrones de gráfico pueden contener una cláusula WHERE, que te permite acceder a todas las variables del patrón de gráfico en los patrones de ruta de acceso para formar condiciones de filtrado. Cada patrón de ruta genera una colección de rutas.

Coincidencia con un patrón de gráfico

La siguiente consulta identifica las cuentas intermediarias y sus propietarios involucrados en transacciones con importes superiores a USD 200, a través de las cuales se transfieren fondos de una cuenta de origen a una cuenta bloqueada.

Los siguientes patrones de ruta de acceso forman el patrón de gráfico:

  • El primer patrón encuentra rutas en las que la transferencia se produce de una cuenta a una cuenta bloqueada a través de una cuenta intermedia.
  • El segundo patrón encuentra rutas de acceso desde una cuenta hasta la persona propietaria.

La variable interm actúa como un vínculo común entre los dos patrones de ruta de acceso, lo que requiere que interm haga referencia al mismo nodo de elemento en ambos patrones de ruta de acceso. Esto crea una operación de unión equitativa basada en la variable interm.

GRAPH graph_db.FinGraph
MATCH
  (src:Account)-[t1:Transfers]->(interm:Account)-[t2:Transfers]->(dst:Account),
  (interm)<-[:Owns]-(p:Person)
WHERE dst.is_blocked = TRUE AND t1.amount > 200 AND t2.amount > 200
RETURN
  src.id AS src_account_id, dst.id AS dst_account_id,
  interm.id AS interm_account_id, p.id AS owner_id;

El resultado es similar al siguiente:

src_account_id dst_account_id interm_account_id owner_id
20 16 7 1

Sentencias de consulta lineales

Puedes encadenar varias instrucciones de gráfico para formar una instrucción de consulta lineal. Las instrucciones se ejecutan en el mismo orden en que aparecen en la consulta.

  • Cada instrucción toma la salida de la instrucción anterior como entrada. La entrada está vacía para la primera instrucción.

  • El resultado de la última instrucción es el resultado final.

Por ejemplo, puedes usar instrucciones de consulta lineales para encontrar la transferencia máxima a una cuenta bloqueada. La siguiente consulta busca la cuenta y su propietario con la mayor transferencia saliente a una cuenta bloqueada.

GRAPH graph_db.FinGraph
MATCH (src_account:Account)-[transfer:Transfers]->(dst_account:Account {is_blocked:true})
ORDER BY transfer.amount DESC
LIMIT 1
MATCH (src_account:Account)<-[owns:Owns]-(owner:Person)
RETURN src_account.id AS account_id, owner.name AS owner_name;

En la siguiente tabla, se ilustra este proceso mostrando los resultados intermedios que se pasan entre cada instrucción. Para mayor brevedad, solo se muestran algunas propiedades.

Afirmación Resultado intermedio (abreviado)
MATCH
  (src_account:Account)
    -[transfer:Transfers]->
  (dst_account:Account {is_blocked:true})
src_account transfer dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}
{id: 7} {amount: 100.0} {id: 16, is_blocked: true}
{id: 20} {amount: 200.0} {id: 16, is_blocked: true}

ORDER BY transfer.amount DESC
src_account transfer dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}
{id: 20} {amount: 200.0} {id: 16, is_blocked: true}
{id: 7} {amount: 100.0} {id: 16, is_blocked: true}

LIMIT 1
src_account transfer dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}

MATCH
  (src_account:Account)
    <-[owns:Owns]-
  (owner:Person)
src_account transfer dst_account owns propietario
{id: 7} {amount: 300.0} {id: 16, is_blocked: true} {person_id: 1, account_id: 7} {id: 1, name: Alex}
RETURN
  src_account.id AS account_id,
  owner.name AS owner_name
        
account_id owner_name
7 Alex

El resultado es similar al siguiente:

account_id owner_name
7 Alex

Sentencia return

La sentencia RETURN especifica qué se debe devolver de los patrones coincidentes. Puede acceder a variables de patrones de grafos y puede incluir expresiones y otras cláusulas, como ORDER BY y GROUP BY.

BigQuery Graph no admite la devolución de elementos del gráfico como resultados de la consulta. Para devolver todo el elemento del gráfico, usa la función TO_JSON.

Devuelve elementos del gráfico como JSON

GRAPH graph_db.FinGraph
MATCH (n:Account {id: 7})
-- Returning a graph element in the final results is NOT allowed. Instead, use
-- the TO_JSON function or explicitly return the graph element's properties.
RETURN TO_JSON(n) AS n;

El resultado es similar al siguiente:

n
{"identifier":"mUZpbkdyYXBoLkFjY291bnQAeJEO","kind":"node","labels":["Account"],"properties":{"create_time":"2020-01-10T14:22:20.222Z","id":7,"is_blocked":false,"nick_name":"Vacation Fund"}}

Cómo redactar búsquedas más grandes con la palabra clave NEXT

Puedes encadenar varias sentencias de consultas lineales de gráficos con la palabra clave NEXT. La primera instrucción recibe una entrada vacía, y la salida de cada instrucción subsiguiente se convierte en la entrada de la siguiente.

En el siguiente ejemplo, se busca el propietario de la cuenta con más transferencias entrantes encadenando varias instrucciones lineales del gráfico. Puedes usar la misma variable, por ejemplo, account, para hacer referencia al mismo elemento del gráfico en varias instrucciones lineales.

GRAPH graph_db.FinGraph
MATCH (:Account)-[:Transfers]->(account:Account)
RETURN account, COUNT(*) AS num_incoming_transfers
GROUP BY account
ORDER BY num_incoming_transfers DESC
LIMIT 1

NEXT

MATCH (account:Account)<-[:Owns]-(owner:Person)
RETURN account.id AS account_id, owner.name AS owner_name, num_incoming_transfers;

El resultado es similar al siguiente:

account_id owner_name num_incoming_transfers
16 Lee 3

También puedes combinar instrucciones de consultas lineales con operadores de conjuntos.

Funciones y expresiones

Puedes usar todas las funciones (tanto agregadas como escalares), los operadores y las expresiones condicionales de GoogleSQL en las consultas de grafos. BigQuery Graph también admite funciones de GQL y operadores de GQL que solo se pueden usar en consultas de grafos.

La siguiente consulta incluye una combinación de funciones y operadores de GQL y SQL dentro de una consulta de gráfico:

GRAPH graph_db.FinGraph
MATCH (person:Person)-[o:Owns]->(account:Account)
WHERE person IS SOURCE OF o
RETURN person, ARRAY_AGG(account.nick_name) AS accounts
GROUP BY person

NEXT

RETURN
  LABELS(person) AS labels,
  accounts,
  CONCAT(person.city, ", ", person.country) AS location,
  TO_JSON(person) AS person
LIMIT 1;

El resultado es similar al siguiente:

etiquetas cuentas ubicación person
Person ["Vacation Fund"] Adelaide, Australia {"identifier":"mUZpbkdyYXBoLlBlcnNvbgB4kQI=","kind":"node","labels":["Person"],"properties":{"birthday":"1991-12-21T08:00:00Z","city":"Adelaide","country":"Australia","id":1,"name":"Alex"}}

Subconsultas

Una subconsulta es una consulta anidada en otra consulta. Las siguientes reglas se aplican a las subconsultas dentro de las consultas de gráficos:

  • Una subconsulta se incluye entre un par de llaves {}.
  • Una subconsulta comienza con una cláusula GRAPH para especificar el gráfico en alcance. No es necesario que el gráfico especificado sea el mismo que el que se usa en la consulta externa.
  • Una variable de patrón de gráfico declarada fuera del alcance de la subconsulta no se puede volver a declarar dentro de la subconsulta, pero se puede hacer referencia a ella en expresiones o funciones dentro de la subconsulta.

Usa una subconsulta para encontrar la cantidad total de transferencias de cada cuenta

La siguiente consulta ilustra el uso de la subconsulta VALUE. La subconsulta se incluye entre llaves {} con el prefijo de la palabra clave VALUE. La consulta devuelve la cantidad total de transferencias iniciadas desde una cuenta.

GRAPH graph_db.FinGraph
MATCH (p:Person)-[:Owns]->(account:Account)
RETURN p.name, account.id AS account_id, VALUE {
  GRAPH graph_db.FinGraph
  MATCH (a:Account)-[transfer:Transfers]->(:Account)
  WHERE a = account
  RETURN COUNT(transfer) AS num_transfers
} AS num_transfers;

El resultado es similar al siguiente:

nombre account_id num_transfers
Alex 7 2
Dana 20 2
Lee 16 1

Para obtener una lista de las expresiones de subconsulta admitidas, consulta Subconsultas de BigQuery Graph.

Parámetros de consulta

Puedes consultar BigQuery Graph con parámetros. Para obtener más información, consulta la sintaxis y aprende a ejecutar consultas con parámetros.

La siguiente búsqueda coincide con los nodos Person que tienen un valor id que coincide con un parámetro de búsqueda:

GRAPH graph_db.FinGraph
MATCH (person:Person {id: @id})
RETURN person.name;

Consultar gráficos y tablas juntos

Puedes combinar consultas de gráficos y consultas de SQL con el operador GRAPH_TABLE.

El operador GRAPH_TABLE toma una consulta de gráfico lineal y devuelve su resultado en formato tabular, que se puede integrar en una consulta en SQL. Esta interoperabilidad te permite enriquecer los resultados de las consultas de gráficos con contenido que no es de gráficos y viceversa.

Por ejemplo, puedes crear una tabla CreditReports e insertar algunos informes de crédito, como se muestra en el siguiente ejemplo:

CREATE TABLE graph_db.CreditReports (
  person_id     INT64 NOT NULL,
  create_time   TIMESTAMP NOT NULL,
  score         INT64 NOT NULL,
  PRIMARY KEY (person_id, create_time) NOT ENFORCED
);
INSERT INTO graph_db.CreditReports (person_id, create_time, score)
VALUES
  (1,"2020-01-10 06:22:20.222", 700),
  (2,"2020-02-10 06:22:20.222", 800),
  (3,"2020-03-10 06:22:20.222", 750);

A continuación, puedes identificar personas específicas a través de la coincidencia de patrones de grafos en GRAPH_TABLE y unir los resultados de la consulta de grafos con la tabla CreditReports para recuperar las puntuaciones de crédito.

SELECT
  gt.person.id,
  credit.score AS latest_credit_score
FROM GRAPH_TABLE(
  graph_db.FinGraph
  MATCH (person:Person)-[:Owns]->(:Account)-[:Transfers]->(account:Account {is_blocked:true})
  RETURN DISTINCT person
) AS gt
JOIN graph_db.CreditReports AS credit
  ON gt.person.id = credit.person_id
ORDER BY credit.create_time;

El resultado es similar al siguiente:

person_id latest_credit_score
1 700
2 800

¿Qué sigue?