Criar um gráfico com uma visualização SQL

Saiba como criar um gráfico usando visualizações SQL. Este documento fornece instruções detalhadas e exemplos de código para definir visualizações e usá-las para definir tabelas de nós e de bordas. Confira exemplos com exemplos de código que demonstram casos de uso para criar gráficos com visualizações. Para saber mais sobre como usar visualizações para criar um gráfico de propriedades, incluindo benefícios e considerações, consulte Visão geral dos gráficos criados com base em visualizações SQL.

Antes de começar

Para criar um gráfico, você precisa:

  1. Verifique se o ambiente do Spanner Graph está configurado.

  2. Saiba como funcionam os esquemas do Spanner Graph.

Criar um gráfico usando visualizações

Para criar um gráfico usando visualizações:

  1. Defina as visualizações do gráfico. Por padrão, as visualizações precisam seguir um dos padrões de visualização compatíveis para garantir a exclusividade do elemento. Se as visualizações usarem consultas que não seguem esses padrões, desative a validação de exclusividade de chave na etapa 4. Para mais informações, consulte Criar uma visualização.

  2. Use as visualizações nas cláusulas NODE TABLES e EDGE TABLES da instrução CREATE PROPERTY GRAPH para criar um gráfico.

  3. Inclua a cláusula KEY na instrução CREATE PROPERTY GRAPH. A cláusula KEY especifica as colunas da visualização de origem que identificam exclusivamente cada elemento do gráfico.

  4. Opcional: se as visualizações usarem consultas SQL arbitrárias que não seguem os padrões de exclusividade compatíveis, adicione a cláusula OPTIONS (validate_element_key_uniqueness = false) à instrução CREATE PROPERTY GRAPH. Verifique se as colunas da cláusula KEY produzem valores exclusivos para cada linha de nó ou aresta:

    CREATE PROPERTY GRAPH MyGraph
      NODE TABLES (
        CustomerViewTrusted KEY(id)
      ) OPTIONS (validate_element_key_uniqueness = false);
    

    Para mais informações, consulte Validação de chave desativada (qualquer consulta SQL).

  5. Opcional: se as visualizações chamarem uma função remota ou tiverem outras colunas voláteis, adicione a cláusula OPTIONS (allow_view_with_volatile_column = true) à instrução CREATE PROPERTY GRAPH:

    CREATE PROPERTY GRAPH MyGraph
      NODE TABLES (
        AccountRemoteUdfView KEY(account_id)
      ) OPTIONS (allow_view_with_volatile_column = true);
    

    Para mais informações, consulte Ativar colunas voláteis quando as visualizações usam funções remotas.

Exemplo: criar um gráfico usando visualizações

Este exemplo cria as seguintes visualizações nas tabelas Customer e Account: AsiaCustomer, AsiaBankAccount e AsiaAccountsOwnership. Em seguida, o exemplo usa essas visualizações para criar o seguinte em um gráfico:

  • Crie a tabela de nós Customer usando a visualização AsiaCustomer.

  • Crie a tabela de nós Account usando a visualização AsiaBankAccount.

  • Crie a tabela de borda Owns usando a visualização AsiaAccountsOwnership. Essa borda conecta nós Customer a nós Account.

Etapa 1: criar as tabelas

Primeiro, crie as tabelas de dados. O código a seguir cria as tabelas Customer e Account.

CREATE TABLE Customer (
  customer_id INT64 NOT NULL,
  name STRING(MAX),
  address_continent STRING(MAX),
  address_country STRING(MAX),
) PRIMARY KEY(customer_id);

CREATE TABLE Account (
  account_id INT64 NOT NULL,
  customer_id INT64 NOT NULL,
  account_type STRING(MAX),
  balance INT64,
  create_time TIMESTAMP,
  address_continent STRING(MAX),
  address_country STRING(MAX),
  CONSTRAINT FK_CustomerId FOREIGN KEY (customer_id)
    REFERENCES Customer (customer_id)
) PRIMARY KEY(account_id);

Etapa 2: criar as visualizações

Em seguida, crie visualizações para transformar ou filtrar dados das tabelas. Essas visualizações filtram as tabelas para incluir apenas clientes e contas na Ásia. A menos que validate_element_key_uniqueness esteja definido como false, as visualizações usadas para criar elementos de gráfico precisam seguir padrões compatíveis para garantir que as linhas na visualização sejam exclusivas.

-- View for 'Customer' nodes, filtered for Asia
CREATE VIEW AsiaCustomer
  SQL SECURITY INVOKER AS
    SELECT customer.customer_id, customer.name
    FROM Customer customer
    WHERE LOWER(customer.address_continent) = "asia";

-- View for 'Account' nodes, filtered for Asia.
CREATE VIEW AsiaBankAccount
  SQL SECURITY INVOKER AS
    SELECT account.account_id, account.balance, account.account_type, account.create_time
    FROM Account account
    WHERE LOWER(account.address_continent) = "asia";

-- View for 'Owns' edges, connecting customers to accounts in Asia.
CREATE VIEW AsiaAccountsOwnership
  SQL SECURITY INVOKER AS
    SELECT account.customer_id, account.account_id
    FROM Account account
    WHERE LOWER(account.address_continent) = "asia";

Etapa 3: criar o gráfico de propriedades

Agora, crie o AsiaFinGraph usando as visualizações que você criou. A instrução CREATE PROPERTY GRAPH inclui a cláusula KEY para cada definição de elemento de gráfico para especificar colunas que identificam exclusivamente os elementos do gráfico.

CREATE PROPERTY GRAPH AsiaFinGraph
  NODE TABLES (
    AsiaCustomer AS Customer KEY(customer_id),
    AsiaBankAccount AS Account KEY(account_id)
  )
  EDGE TABLES (
    AsiaAccountsOwnership AS Owns
      KEY(customer_id, account_id)
      SOURCE KEY (customer_id) REFERENCES Customer (customer_id)
      DESTINATION KEY (account_id) REFERENCES Account (account_id)
  );

Exemplos de casos de uso

As visualizações SQL oferecem benefícios em relação ao uso de tabelas para elementos de gráfico de propriedades. Os exemplos a seguir demonstram alguns casos de uso para definir elementos de gráfico com visualizações em vez de tabelas.

Exemplo: aplicar controle de acesso granular a dados de gráfico

Para aplicar a segurança no nível da linha aos dados do gráfico, defina as tabelas de nós ou arestas usando visualizações de direitos do definidor. A visualização expõe um subconjunto permitido dos dados subjacentes ao gráfico

Por exemplo, para restringir o acesso ao gráfico apenas aos funcionários de um centro de custo de engenharia, crie uma visualização EngineerEmployeeView e conceda permissões SELECT na visualização a um papel engineering_data_reader usando a cláusula GRANT.

Quando você define uma tabela de nós de gráfico usando essa visualização, os usuários que executam consultas de gráfico com o papel engineering_data_reader só podem ver as linhas filtradas pela visualização, que incluem funcionários de engenharia.

-- The table containing all employee data.
CREATE TABLE Employee (
  id INT64 NOT NULL,
  cost_center STRING(MAX),
  job_title STRING(MAX),
  office STRING(MAX)
) PRIMARY KEY (id);

-- The definer's rights view that filters for engineering employees.
CREATE VIEW EngineerEmployeeView SQL SECURITY DEFINER AS
  SELECT e.id, e.cost_center, e.job_title, e.office
  FROM Employee e
  WHERE LOWER(e.cost_center) = "engineering";

-- The role that is granted to read the view.
CREATE ROLE engineering_data_reader;
GRANT SELECT ON VIEW EngineerEmployeeView TO ROLE engineering_data_reader;

-- The graph that uses definer's rights view.
CREATE PROPERTY GRAPH EngineeringGraph
  NODE TABLES (
    EngineerEmployeeView KEY(id)
  );

Exemplo: elementos de gráfico derivados de modelo

É possível usar visualizações para definir elementos de gráfico que exigem transformações de dados. Um benefício importante é que a visualização define a transformação, então não é necessário manter uma tabela separada para os dados derivados.

Remover o aninhamento de matrizes para modelar arestas

Por exemplo, é possível usar UNNEST em dados de uma coluna ARRAY (ou um campo de matriz em uma coluna JSON) para modelar vários relacionamentos de borda de uma única linha.

No exemplo de esquema de cadeia de suprimentos a seguir, uma tabela Parts armazena uma lista de subcomponentes em uma matriz dependent_parts. Uma visualização pode usar o operador UNNEST para transformar cada elemento dessa matriz em linhas distintas. Essa visualização pode servir como uma tabela de borda, permitindo modelar uma borda PartDependsOnPart para representar relações de dependência entre as partes.

-- Parts table with an ARRAY of dependent parts.
CREATE TABLE Parts (
  part_id INT64 NOT NULL,
  dependent_parts ARRAY<INT64>
) PRIMARY KEY (part_id);

-- A view that unnests the dependent_parts array.
-- GROUP BY ensures uniqueness for the graph element KEY.
CREATE VIEW PartDependsOnPart SQL SECURITY INVOKER AS
  SELECT p.part_id, dependent_part_id
  FROM Parts AS p,
    UNNEST(p.dependent_parts) AS dependent_part_id
  GROUP BY p.part_id, dependent_part_id;

-- Graph modeling the part dependency relationship.
CREATE PROPERTY GRAPH SupplyChainGraph
  NODE TABLES (
    Parts
  )
  EDGE TABLES (
    PartDependsOnPart KEY (part_id, dependent_part_id)
      SOURCE KEY (part_id) REFERENCES Parts(part_id)
      DESTINATION KEY (dependent_part_id) REFERENCES Parts(part_id)
  );

Calcular propriedades com funções remotas

Também é possível usar uma função remota em uma visualização para calcular propriedades derivadas de elementos de gráfico definindo allow_view_with_volatile_column = true na cláusula OPTIONS da instrução CREATE PROPERTY GRAPH. Para mais informações, consulte Ativar colunas voláteis quando as visualizações usam funções remotas.

-- Define a remote function.
CREATE FUNCTION rudf_identity_func(x INT64)
  RETURNS INT64 NOT DETERMINISTIC LANGUAGE REMOTE
  OPTIONS (
    endpoint = 'https://us-central1-project-id.cloudfunctions.net/my-func'
  );

-- Base table for accounts.
CREATE TABLE Account (
  account_id INT64 NOT NULL,
  balance INT64
) PRIMARY KEY (account_id);

-- View that computes a property using the remote function.
CREATE VIEW AccountRemoteUdfView SQL SECURITY INVOKER AS
  SELECT
    t.account_id,
    t.balance,
    rudf_identity_func(t.account_id) AS view_computed_prop
  FROM Account AS t;

-- Graph using the view requires allow_view_with_volatile_column = true.
CREATE PROPERTY GRAPH AccountViewRemoteUdfGraph
  NODE TABLES (
    AccountRemoteUdfView KEY (account_id)
      PROPERTIES (account_id, balance, view_computed_prop)
  )
  OPTIONS (allow_view_with_volatile_column = true);

Exemplo: transição de dados sem esquema

O gerenciamento de dados sem esquema permite criar uma definição de gráfico flexível sem tipos de nós e bordas predefinidos. Embora o gerenciamento de dados sem esquema ofereça flexibilidade, talvez seja necessário fazer a transição para uma estrutura mais formal à medida que os dados se tornam mais definidos. Uma estrutura mais formal expõe as relações de nós e bordas, os rótulos e as propriedades do gráfico no esquema, o que reduz a necessidade de exploração manual de dados para entender o esquema do gráfico.

É possível usar visualizações para formalizar os tipos de nó e aresta sem migrar os dados subjacentes. Por exemplo, é possível fazer a transição de um modelo típico sem esquema que usa tabelas canônicas GraphNode e GraphEdge. Para fazer isso, crie visualizações que extraiam os dados das tabelas sem esquema:

  1. Defina uma visualização para cada tipo de nó e aresta que você quer formalizar (por exemplo, Person ou WorksFor). Na visualização, filtre os dados pelo rótulo (por exemplo, WHERE n_label = "person") e converta as propriedades da coluna JSON em tipos de dados específicos (por exemplo, STRING(prop.name) AS name).

  2. Defina um novo gráfico de propriedades em que NODE TABLES e EDGE TABLES referenciam as visualizações tipadas que você acabou de criar.

Um gráfico sem esquema oferece melhor desempenho do que um gráfico formalizado para algumas consultas (por exemplo, um padrão de caminho quantificado com vários tipos de borda). Se os metadados formalizados forem importantes para seu caso de uso, use as visualizações para fazer a transição de um grafo sem esquema para um esquema tipado. Também é possível usar um gráfico sem esquema para alguns casos de uso e um gráfico de esquema tipado para outros. Para mais informações, consulte Escolher um design de esquema com base em consultas de gráfico.

O exemplo a seguir demonstra o fluxo de trabalho para a transição de um gráfico sem esquema para um formalizado em quatro etapas:

  1. Defina as tabelas canônicas GraphNode e GraphEdge para o modelo sem esquema.

  2. Crie um gráfico inicial e flexível nessas tabelas sem esquema.

  3. Defina visualizações tipadas (Person, Company, WorksFor) que extraem e formalizam os dados das tabelas sem esquema.

  4. Crie o gráfico final fortemente tipado que usa essas visualizações como tabelas de nós e arestas.

-- 1. Create the canonical tables for a schemaless model.
CREATE TABLE GraphNode (
  id INT64 NOT NULL,
  label STRING(MAX) NOT NULL,
  properties JSON
) PRIMARY KEY (id);

CREATE TABLE GraphEdge (
  id INT64 NOT NULL,
  dest_id INT64 NOT NULL,
  edge_id INT64 NOT NULL,
  label STRING(MAX) NOT NULL,
  properties JSON
) PRIMARY KEY (id, dest_id, edge_id),
  INTERLEAVE IN PARENT GraphNode;

-- 2. Define a schemaless graph.
CREATE PROPERTY GRAPH FinGraph
  NODE TABLES (
    GraphNode
      DYNAMIC LABEL (label)
      DYNAMIC PROPERTIES (properties)
  )
  EDGE TABLES (
    GraphEdge
      SOURCE KEY (id) REFERENCES GraphNode(id)
      DESTINATION KEY (dest_id) REFERENCES GraphNode(id)
      DYNAMIC LABEL (label)
      DYNAMIC PROPERTIES (properties)
  );

-- 3. Define typed views that extract and formalize the data.
--    Convert JSON fields to primitive types (for example, INT64, STRING) to
--    ensure type safety.
CREATE VIEW Person SQL SECURITY INVOKER AS
  SELECT n.id, STRING(n.properties.name) AS name, INT64(n.properties.age) AS age
  FROM GraphNode n WHERE n.label = "person";

CREATE VIEW Company SQL SECURITY INVOKER AS
  SELECT n.id, STRING(n.properties.name) AS company_name, BOOL(n.properties.is_public) AS is_public
  FROM GraphNode n WHERE n.label = "company";

CREATE VIEW WorksFor SQL SECURITY INVOKER AS
  SELECT e.id AS person_id, e.dest_id AS company_id, e.edge_id AS edge_id, STRING(e.properties.since) AS since
  FROM GraphEdge e
  WHERE e.label = "worksfor";

-- 4. Create the final, formalized graph from the typed views.
CREATE PROPERTY GRAPH typed_formalized_graph
  NODE TABLES (
    Person KEY(id)
      PROPERTIES (name, age),
    Company KEY(id)
      PROPERTIES (company_name, is_public)
  )
  EDGE TABLES(
    WorksFor KEY(person_id, company_id, edge_id)
      SOURCE KEY (person_id) REFERENCES Person(id)
      DESTINATION KEY (company_id) REFERENCES Company(id)
      PROPERTIES (since)
  );

A seguir