Descripción general de las consultas de gráficos

BigQuery Graph te permite escribir consultas de grafos para hacer coincidir patrones de nodos, bordes y rutas, y recorrer relaciones con el Graph Query Language (GQL). Los ejemplos de este documento hacen referencia a un grafo 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 grafo consiste en el nombre del grafo, seguido de una o más instrucciones de consulta lineales. Cada consulta lineal contiene una o más declaraciones, 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 grafo de la misma manera que ejecutas una consulta en SQL en BigQuery.

Estructura de consulta de grafo de ejemplo.
Ejemplo de la estructura de una consulta de grafo.

Coincidencia de patrones de grafos

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

Patrones de nodos

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

Encuentra 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 grafo.

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

Busca 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 que coinciden.

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 que coinciden:

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

Busca todos los nodos que coincidan 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 grafo 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 consulta:

  • Todos los nodos tienen la propiedad id.
  • Los nodos que coinciden con la etiqueta Account tienen la propiedad create_time, pero no tienen 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 propiedades

La siguiente consulta coincide con todos los nodos del grafo 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.

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

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

Encuentra todos los bordes con etiquetas que coincidan

Esta consulta devuelve todas las aristas del grafo con la etiqueta Transfers. La consulta vincula la variable de 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 todos los bordes que coincidan con la expresión de etiqueta y el filtro de propiedad

El patrón de arista en la siguiente consulta usa una expresión de etiqueta y un filtro de propiedad para encontrar todas las aristas etiquetadas como Transfers que coincidan 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 arista any direction (-[]-) en una consulta para que coincida con las aristas en cualquier dirección. La siguiente consulta busca 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 crea a partir de patrones de nodos y bordes alternados.

Encuentra todas las rutas de acceso desde un nodo específico con un patrón de ruta de acceso

La siguiente consulta busca todas las transferencias a una cuenta iniciadas desde una cuenta que pertenece a Person con id igual a 2.

Cada resultado coincidente representa una ruta de acceso desde un nodo Person cuando id es igual a 2 a través de un nodo Account conectado con un borde Owns, en otro nodo Account con un borde 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.

Cómo hacer coincidir un patrón de arista cuantificado

Para encontrar rutas de acceso de una longitud variable, puedes aplicar un cuantificador a un patrón de arista. En la siguiente consulta, se demuestra esto encontrando cuentas de destino que están a una o tres transferencias de un Account de origen 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 consulta que busque coincidencias con rutas de acceso que repitan 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 al e 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 de acceso que coincidan con el patrón entre los mismos nodos de origen y destino, y la consulta las devuelve todas.

Haz coincidir un patrón de ruta de acceso cuantificado

En la siguiente consulta, se encuentran rutas de acceso entre nodos Account con uno o dos bordes 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 las 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 grafo 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 de gráfico coincidentes.

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

Variable de grupo de acceso

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

  • Como una variable de patrón de grafo vinculada a un solo borde en la cláusula WHERE e.amount > 100 cuando está dentro del patrón cuantificado.
  • Como una variable de grupo vinculada a un array de elementos de arista en ARRAY_LENGTH(e) en la sentencia RETURN cuando está fuera del patrón cuantificado.
  • Como una variable de grupo vinculada a un array de elementos de borde, que se agrega por SUM(e.amount) 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 de acceso

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

Coincidencia con ANY

En la siguiente consulta, se encuentran todas las cuentas únicas accesibles que están a una o dos Transfers de un nodo Account determinado.

El prefijo de búsqueda de ruta ANY garantiza que la consulta devuelva solo 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 Account de origen, la consulta devuelve solo 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, seleccionados de aquellos con la cantidad mínima 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 uno a 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 de acceso ANY CHEAPEST garantiza que, para cada par de cuentas de origen y destino, la consulta devuelva solo una ruta de acceso con el costo de procesamiento total mínimo.

En la siguiente consulta, se 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 los bordes Transfers. La búsqueda considera rutas de acceso con uno a 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 grafos

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

Coincidencia con un patrón de grafo

La siguiente consulta identifica las cuentas intermediarias y sus propietarios involucrados en importes de transacciones que superan los 200, a través de los 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 grafo:

  • El primer patrón encuentra rutas en las que la transferencia se produce de una cuenta a una cuenta bloqueada con una cuenta intermedia.
  • El segundo patrón encuentra rutas de acceso de una cuenta a 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 de igualdad 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 sentencias de grafo para formar una sentencia de consulta lineal. Las declaraciones se ejecutan en el mismo orden en que aparecen en la consulta.

  • Cada sentencia toma como entrada el resultado de la sentencia anterior. La entrada está vacía para la primera sentencia.

  • El resultado de la última sentencia es el resultado final.

Por ejemplo, puedes usar declaraciones de consulta lineales para encontrar la transferencia máxima a una cuenta bloqueada. La siguiente consulta busca la cuenta y su propietario con la transferencia saliente más grande 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 sentencia. 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 es propietario owner
{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 que coinciden. Puede acceder a variables de patrones de grafos y, además, incluir expresiones y otras cláusulas, como ORDER BY y GROUP BY.

BigQuery Graph no admite la devolución de elementos de grafo como resultados de consultas. Para devolver todo el elemento del grafo, usa la función TO_JSON.

Devuelve elementos de grafo 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"}}

Redacta consultas más grandes con la palabra clave NEXT

Puedes encadenar varias sentencias de consulta lineal de grafo con la palabra clave NEXT. La primera sentencia recibe una entrada vacía, y el resultado de cada sentencia subsiguiente se convierte en la entrada de la siguiente.

En el siguiente ejemplo, se encuentra el propietario de la cuenta con la mayor cantidad de transferencias entrantes encadenando varias declaraciones lineales de grafo. Puedes usar la misma variable, por ejemplo, account, para hacer referencia al mismo elemento del grafo en varias declaraciones 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 sentencias de consulta lineales con operadores de conjuntos.

Funciones y expresiones

Puedes usar todas las funciones de GoogleSQL (tanto las funciones agregadas como las escalares), los operadores y las expresiones condicionales 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 grafo:

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 que está anidada en otra consulta. Las siguientes reglas se aplican a las subconsultas dentro de las consultas de grafo:

  • Una subconsulta se encierra entre un par de llaves {}.
  • Una subconsulta comienza con una cláusula GRAPH para especificar el grafo en el alcance. No es necesario que el grafo especificado sea el mismo que el que se usa en la consulta externa.
  • Una variable de patrón de grafo 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

En la siguiente consulta, se ilustra el uso de la subconsulta VALUE. La subconsulta se encierra 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 parametrizadas.

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

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

Consulta gráficos y tablas juntos

Puedes combinar consultas de grafos y consultas en SQL con el operador GRAPH_TABLE.

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

Por ejemplo, puedes crear una tabla CreditReports y, luego, 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 calificaciones crediticias.

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?