Prácticas recomendadas para las consultas de grafos

Puedes optimizar el rendimiento de las consultas de BigQuery Graph estructurando tus consultas de Graph Query Language (GQL) para minimizar los datos analizados y los resultados intermedios.

Inicia el recorrido de la ruta desde los nodos de cardinalidad baja

Para mantener pequeños los conjuntos de resultados intermedios y acelerar la ejecución de las consultas, escribe tus consultas de grafo de modo que el recorrido de la ruta comience desde nodos de cardinalidad más baja, independientemente de la dirección del recorrido de la ruta. Las siguientes sentencias MATCH usan filtros de propiedades para reducir la cantidad de posibles nodos de inicio en lugar de calcular todas las coincidencias y, luego, filtrar:

MATCH (p:Person {id: 10})-[own:Owns]->(a:Account)
MATCH (a:Account WHERE balance > 10)<-[own:Owns]-(p:Person)

Esto es especialmente importante para las consultas de rutas cuantificadas:

MATCH (p:Person {id: 10})-[own:Owns]->{1,3}(a:Account)

Usa la sintaxis ANY o ANY SHORTEST para las verificaciones de conectividad

Las consultas de ruta cuantificadas pueden devolver rutas duplicadas entre los nodos de origen y los nodos de destino. Si tu objetivo es verificar la conectividad y no necesitas todas las rutas posibles, usa ANY o ANY SHORTEST para reducir los cálculos redundantes y mejorar la eficiencia de la búsqueda de rutas. Por ejemplo, la siguiente sentencia MATCH usa ANY SHORTEST para mantener solo una ruta de acceso entre cada par de nodos:

MATCH ANY SHORTEST (a1:Account)-[t:Transfers]->{1,3}(a2:Account)

Usa el recorrido de ruta direccional

Los esquemas de BigQuery Graph son direccionales, lo que significa que cada arista tiene un nodo de origen y un nodo de destino. Aunque la sintaxis de la consulta de grafo permite el recorrido de rutas en cualquier dirección (por ejemplo, -[edge]-), recomendamos usar el recorrido de rutas direccional (por ejemplo, -[edge]-> o <-[edge]-) para obtener un mejor rendimiento. Cualquier recorrido de ruta de dirección puede causar pérdida de rendimiento.

La siguiente sentencia MATCH usa el recorrido de ruta de cualquier dirección:

-- Avoid.
MATCH (a1:Account {id: 7})-[t:Transfers]-(a2:Account)

En su lugar, combina dos recorridos direccionales con UNION ALL:

MATCH (a1:Account {id: 7})-[t:Transfers]->(a2:Account)
...
UNION ALL
...
MATCH (a1:Account  {id: 7})<-[t:Transfers]-(a2:Account)

Especifica etiquetas de forma explícita

Si se omiten las etiquetas de nodo o de borde en una consulta, BigQuery Graph enumera todas las etiquetas de nodo y de borde que cumplen con los requisitos. Esta enumeración puede hacer que se analicen más etiquetas de las necesarias. Para evitar esto, especifica etiquetas para todos los nodos y bordes de tu consulta siempre que sea posible.

Por ejemplo, en la siguiente consulta, se especifican las etiquetas Account y Transfers:

GRAPH graph_db.FinGraph
MATCH (a1:Account)-[t:Transfers]->(a2:Account)
RETURN COUNT(*) AS num_transfers;

Evita omitir etiquetas, ya que podría analizar otras relaciones innecesarias entre nodos. En la siguiente consulta, a1 puede representar una cuenta o una persona, y t puede representar una transferencia o la propiedad de una cuenta.

GRAPH graph_db.FinGraph
MATCH (a1)-[t]->(a2)
RETURN COUNT(*) AS num_transfers;

Prefiere una sola sentencia MATCH

BigQuery Graph te permite incluir varias declaraciones MATCH en una sola consulta de grafo. Estas declaraciones están conectadas por variables declaradas varias veces que representan el mismo nodo o borde. Sin embargo, usar varias instrucciones MATCH puede disminuir los beneficios de cardinalidad en las instrucciones. Cuando sea posible, usa una sola sentencia MATCH para obtener un mejor rendimiento.

Por ejemplo, las siguientes consultas son equivalentes, pero la primera tiene un mejor rendimiento porque usa una sola sentencia MATCH:

-- Preferred syntax.
GRAPH graph_db.FinGraph
MATCH
  (p:Person {id: 1})-[o:Owns]->
  (a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;
-- Avoid this syntax.
GRAPH graph_db.FinGraph
MATCH (p:Person {id: 1})-[o:Owns]->(a:Account)
MATCH (a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;

Limita las aristas recorridas desde nodos de alta cardinalidad

Cuando consultas grafos, algunos nodos pueden tener una cantidad 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 causar problemas de rendimiento, ya que los recorridos a través de ellos pueden implicar el procesamiento de grandes cantidades de datos, lo que genera un sesgo de datos y tiempos de ejecución prolongados.

Para optimizar una consulta de un grafo con supernodos, usa la función ROW_NUMBER() dentro de una cláusula FILTER o WHERE en MATCH para limitar la cantidad de aristas que la consulta recorre desde o hacia un nodo. Esta técnica es especialmente útil cuando no necesitas una enumeración completa de todas las conexiones desde o hacia un supernodo.

Por ejemplo, si algunas cuentas de FinGraph tienen una gran cantidad de transacciones, puedes usar ROW_NUMBER() para limitar la cantidad de bordes de Transfers que se deben considerar para cada Account y evitar una consulta ineficiente:

GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers WHERE e1 IN {
  GRAPH graph_db.FinGraph
  -- Sample 5 edges per source node
  MATCH -[selected_e:Transfers]->
    FILTER ROW_NUMBER() OVER (
      PARTITION BY SOURCE_NODE_ID(selected_e)) < 5
    RETURN selected_e
}]->{1,3}(a2:Account)
RETURN COUNT(*) AS cnt;

Muestrea nodos o bordes intermedios en consultas de varios saltos

También puedes mejorar la eficiencia de las consultas con ROW_NUMBER() para muestrear nodos intermedios en consultas de varios saltos. Esta técnica mejora la eficiencia, ya que limita la cantidad de rutas que la consulta considera para cada nodo intermedio. Para ello, divide una consulta de varios saltos en varias declaraciones MATCH separadas por NEXT y aplica ROW_NUMBER() en el punto medio en el que necesites tomar muestras:

GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers]->(a2:Account)
-- Sample 5 destination nodes per a1 source node
FILTER ROW_NUMBER() OVER (PARTITION BY ELEMENT_ID(a1)) < 5
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;

¿Qué sigue?