Práticas recomendadas para ajustar consultas do Spanner Graph

Este documento descreve as práticas recomendadas para ajustar a performance de consultas de gráficos do Spanner, incluindo as seguintes otimizações:

  • Evite uma verificação completa da tabela de entrada para nós e arestas.
  • Reduza a quantidade de dados que a consulta precisa ler do armazenamento.
  • Reduza o tamanho dos dados intermediários.

Começar com nós de baixa cardinalidade

Escreva a travessia de caminho para que ela comece com os nós de baixa cardinalidade. Essa abordagem mantém o conjunto de resultados intermediários pequeno e acelera a execução da consulta.

Por exemplo, as consultas a seguir têm a mesma semântica:

  • Transversalidade de borda para frente:

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

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

Supondo que haja menos pessoas com o nome Alex do que contas bloqueadas, recomendamos que você escreva essa consulta na travessia de borda direta.

Começar com nós de baixa cardinalidade é especialmente importante para o percurso de caminho de comprimento variável. O exemplo a seguir mostra a maneira recomendada de encontrar contas que estão a três transferências de uma determinada conta.

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

Especificar todos os rótulos por padrão

O Spanner Graph deduz os nós qualificados e os rótulos de arestas se eles forem omitidos. Recomendamos que você especifique rótulos para todos os nós e arestas sempre que possível, porque essa inferência nem sempre é possível e pode fazer com que mais rótulos do que o necessário sejam verificados.

Uma única instrução MATCH

O exemplo a seguir encontra contas vinculadas por no máximo três transferências da conta especificada:

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

Em instruções MATCH

Especifique rótulos em nós e arestas quando eles se referirem ao mesmo elemento, mas estiverem em instruções MATCH diferentes.

O exemplo a seguir mostra essa abordagem recomendada:

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 o IS_FIRST para otimizar consultas

Você pode usar a função IS_FIRST para melhorar o desempenho da consulta ao fazer amostragem de arestas e limitar travessias em gráficos. Essa função ajuda a processar nós de alta cardinalidade e otimizar consultas de vários saltos.

Se o tamanho da amostra especificado for muito pequeno, a consulta poderá não retornar dados. Por isso, talvez seja necessário testar diferentes tamanhos de amostra para encontrar o equilíbrio ideal entre dados retornados e melhoria na performance da consulta.

Estes exemplos de IS_FIRST usam FinGraph, um gráfico financeiro com nós Account e arestas Transfers para transferências de dinheiro. Para criar o FinGraph e usá-lo para executar as consultas de exemplo, consulte Configurar e consultar o Spanner Graph.

Limitar as arestas percorridas para melhorar o desempenho da consulta

Ao consultar gráficos, alguns nós podem ter um número significativamente maior de arestas de entrada ou saída em comparação com outros nós. Esses nós de alta cardinalidade às vezes são chamados de supernós ou nós de hub. Os supernós podem causar problemas de desempenho porque as travessias por eles podem envolver o processamento de grandes quantidades de dados, o que leva a distorções de dados e longos tempos de execução.

Para otimizar uma consulta de um gráfico com supernós, use a função IS_FIRST em uma cláusula FILTER para limitar o número de arestas que a consulta atravessa de um nó. Como as contas no FinGraph podem ter um número significativamente maior de transações do que outras, use o IS_FIRST para evitar uma consulta ineficiente. Essa técnica é especialmente útil quando você não precisa de uma enumeração completa de todas as conexões de um supernó.

A consulta a seguir encontra contas (a2) que recebem transferências direta ou indiretamente de contas bloqueadas (a1). Ela usa IS_FIRST para evitar lentidão quando uma conta tem muitas transferências, limitando o número de arestas Transfers a serem consideradas 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;

Este exemplo usa o seguinte:

  • @max_transfers_per_account: um parâmetro de consulta que especifica o número máximo de arestas Transfers a serem consideradas para cada conta (a1).

  • PARTITION BY SOURCE_NODE_ID(selected_e): garante que o limite de IS_FIRST seja aplicado de forma independente a cada conta (a1).

  • ORDER BY selected_e.create_time DESC: especifica que as transferências mais recentes serão retornadas.

Faça amostragem de nós intermediários para otimizar consultas de vários saltos

Também é possível melhorar a eficiência da consulta usando o IS_FIRST para amostrar nós intermediários em consultas de várias etapas. Essa técnica melhora a eficiência ao limitar o número de caminhos que a consulta considera para cada nó intermediário. Para fazer isso, divida uma consulta de várias etapas em várias instruções MATCH separadas por NEXT e aplique IS_FIRST no ponto médio em que você precisa fazer a amostragem:

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 como o IS_FIRST otimiza essa consulta:

  • A cláusula FILTER IS_FIRST(1) OVER (PARTITION BY a2) é aplicada na primeira instrução MATCH.

  • Para cada nó de conta intermediário (a2), IS_FIRST considera apenas a primeira aresta Transfers de entrada (e1), reduzindo o número de caminhos a serem explorados na segunda instrução MATCH.

  • A eficiência geral da consulta de dois hops é melhorada porque o segundo MATCH não processa dados desnecessários, especialmente quando a2 tem muitas transferências de entrada.

A seguir