Prácticas recomendadas para optimizar las consultas de gráficos de Spanner

En este documento se describen las prácticas recomendadas para optimizar el rendimiento de las consultas de gráficos de Spanner, que incluyen las siguientes optimizaciones:

  • Evita un análisis completo de la tabla de entrada para buscar nodos y aristas.
  • Reduce la cantidad de datos que la consulta necesita leer del almacenamiento.
  • Reduce el tamaño de los datos intermedios.

Empezar por los nodos de menor cardinalidad

Escribe el recorrido de la ruta de forma que empiece por los nodos de menor cardinalidad. Este enfoque mantiene el conjunto de resultados intermedio pequeño y acelera la ejecución de las consultas.

Por ejemplo, las siguientes consultas tienen la misma semántica:

  • Recorrido por el borde hacia delante:

    GRAPH FinGraph
    MATCH (p:Person {name:"Alex"})-[:Owns]->(a:Account {is_blocked: true})
    RETURN p.id AS person_id, a.id AS account_id;
    
  • Recorrido de aristas inversas:

    GRAPH FinGraph
    MATCH (a:Account {is_blocked:true})<-[:Owns]-(p:Person {name: "Alex"})
    RETURN p.id AS person_id, a.id AS account_id;
    

Si hay menos personas con el nombre Alex que cuentas bloqueadas, te recomendamos que escribas esta consulta en el recorrido de borde hacia delante.

Empezar por nodos de cardinalidad inferior es especialmente importante para el recorrido de rutas de longitud variable. En el siguiente ejemplo se muestra la forma recomendada de encontrar cuentas que estén a tres transferencias de una cuenta determinada.

GRAPH FinGraph
MATCH (:Account {id: 7})-[:Transfers]->{1,3}(a:Account)
RETURN a.id;

Especificar todas las etiquetas de forma predeterminada

Spanner Graph infiere los nodos y las etiquetas de aristas que cumplen los requisitos si se omiten las etiquetas. Te recomendamos que especifiques etiquetas para todos los nodos y aristas siempre que sea posible, ya que esta inferencia no siempre se puede realizar y puede provocar que se analicen más etiquetas de las necesarias.

Una sola instrucción MATCH

En el siguiente ejemplo se buscan cuentas vinculadas por un máximo de 3 transferencias desde la cuenta indicada:

GRAPH FinGraph
MATCH (src:Account {id: 7})-[:Transfers]->{1,3}(dst:Account)
RETURN dst.id;

En las instrucciones MATCH

Especifica etiquetas en nodos y aristas cuando hagan referencia al mismo elemento, pero estén en MATCH diferentes.

En el siguiente ejemplo se muestra este enfoque recomendado:

GRAPH FinGraph
MATCH (acct:Account {id: 7})-[:Transfers]->{1,3}(other_acct:Account)
RETURN acct, COUNT(DISTINCT other_acct) AS related_accts
GROUP BY acct

NEXT

MATCH (acct:Account)<-[:Owns]-(p:Person)
RETURN p.id AS person, acct.id AS acct, related_accts;

Usar IS_FIRST para optimizar consultas

Puedes usar la función IS_FIRST para mejorar el rendimiento de las consultas muestreando aristas y limitando los recorridos en los gráficos. Esta función ayuda a gestionar nodos de alta cardinalidad y a optimizar las consultas de varios saltos.

Si el tamaño de muestra especificado es demasiado pequeño, es posible que la consulta no devuelva ningún dato. Por este motivo, es posible que tengas que probar con distintos tamaños de muestra para encontrar el equilibrio óptimo entre los datos devueltos y el rendimiento de las consultas.

En estos ejemplos de IS_FIRST se usa FinGraph, un gráfico financiero con Account nodos y Transfers aristas para las transferencias de dinero. Para crear el FinGraph y usarlo para ejecutar las consultas de ejemplo, consulta Configurar y consultar Spanner Graph.

Limitar las aristas recorridas para mejorar el rendimiento de las consultas

Cuando consultas gráficos, algunos nodos pueden tener un número significativamente mayor de aristas entrantes o salientes en comparación con otros nodos. Estos nodos de alta cardinalidad a veces se denominan supernodos o nodos centrales. Los supernodos pueden provocar problemas de rendimiento porque los recorridos a través de ellos pueden implicar el procesamiento de grandes cantidades de datos, lo que provoca un sesgo de datos y tiempos de ejecución largos.

Para optimizar una consulta de un gráfico con supernodos, usa la función IS_FIRST en una cláusula FILTER para limitar el número de aristas que atraviesa la consulta desde un nodo. Como las cuentas de FinGraph pueden tener un número de transacciones significativamente mayor que otras, puede usar IS_FIRST para evitar una consulta ineficiente. Esta técnica es especialmente útil cuando no necesitas una enumeración completa de todas las conexiones de un supernodo.

La siguiente consulta busca cuentas (a2) que reciben transferencias directa o indirectamente de cuentas bloqueadas (a1). La consulta usa IS_FIRST para evitar que el rendimiento sea lento cuando una cuenta tiene muchas transferencias, ya que limita el número de aristas Transfers que se deben tener en cuenta para cada Account.

GRAPH FinGraph
MATCH
(a1:Account {is_blocked: true})
-[e:Transfers WHERE e IN
  {
    MATCH -[selected_e:Transfers]->
    FILTER IS_FIRST(@max_transfers_per_account) OVER (
      PARTITION BY SOURCE_NODE_ID(selected_e)
      ORDER BY selected_e.create_time DESC)
    RETURN selected_e
  }
]->{1,5}
(a2:Account)
RETURN a1.id AS src_id, a2.id AS dst_id;

En este ejemplo se usa lo siguiente:

  • @max_transfers_per_account: parámetro de consulta que especifica el número máximo de aristas Transfers que se deben tener en cuenta en cada cuenta (a1).

  • PARTITION BY SOURCE_NODE_ID(selected_e): asegura que el límite de IS_FIRST se aplique de forma independiente a cada cuenta (a1).

  • ORDER BY selected_e.create_time DESC: especifica que se devuelven las transferencias más recientes.

Muestrear nodos intermedios para optimizar las consultas de varios saltos

También puedes mejorar la eficiencia de las consultas usando IS_FIRST para muestrear nodos intermedios en consultas de varios saltos. Esta técnica mejora la eficiencia al limitar el número de rutas que la consulta tiene en cuenta para cada nodo intermedio. Para ello, divide una consulta de varios saltos en varias instrucciones MATCH separadas por NEXT y aplica IS_FIRST en el punto medio en el que quieras tomar muestras:

GRAPH FinGraph
MATCH (a1:Account {is_blocked: true})-[e1:Transfers]->(a2:Account)
FILTER IS_FIRST(1) OVER (PARTITION BY a2)
RETURN a1, a2

NEXT

MATCH (a2)-[e2:Transfers]->(a3:Account)
RETURN a1.id AS src_id, a2.id AS mid_id, a3.id AS dst_id;

Para entender cómo IS_FIRST optimiza esta consulta, sigue estos pasos:

  • La cláusula FILTER IS_FIRST(1) OVER (PARTITION BY a2) se aplica en la primera instrucción MATCH.

  • En cada nodo de cuenta intermedio (a2), IS_FIRST solo tiene en cuenta la primera arista Transfers entrante (e1), lo que reduce el número de rutas que se deben explorar en la segunda instrucción MATCH.

  • La eficiencia general de la consulta de dos saltos mejora porque el segundo MATCH no procesa datos innecesarios, sobre todo cuando a2 tiene muchas transferencias entrantes.

Siguientes pasos