Utilizza le misure
Questo documento mostra come definire ed eseguire query sulle misure nei grafici. Puoi utilizzare le misure per assicurarti che le aggregazioni vengano eseguite correttamente tra i join.
Panoramica
Una misura è una proprietà aggregata definita all'interno della clausola PROPERTIES di una tabella di nodi o archi. Le misure sono definite da un'espressione di misura, che viene creata utilizzando la parola chiave MEASURE intorno a uno dei seguenti elementi:
- un'espressione aggregata
- un'espressione che combina funzioni aggregate con operazioni scalari
- una misura derivata, ovvero una combinazione di misure racchiuse nella funzione
AGGdefinite nella stessa tabella degli elementi
Le misure supportano le seguenti funzioni aggregate:
SUMAVGCOUNTMINMAXAGG(per le misure derivate)
Tutte le funzioni aggregate, ad eccezione di AGG, supportano la parola chiave DISTINCT. Per saperne di più sull'espressione di misura supportata, consulta le informazioni sul tipo di misura.
Le misure definiscono la loro aggregazione in riferimento alla KEY della tabella dei nodi o degli archi su cui sono definite. Ciò significa che quando esegui una query su una misura, l'aggregazione viene eseguita correttamente anche se la tabella sottostante viene unita in modo da causare la duplicazione delle righe.
Non puoi fare riferimento a una proprietà definita da una misura in una query GQL. Invece, accedi alle misure chiamando la TVF GRAPH_EXPAND per eseguire query su una rappresentazione relazionale del tuo grafico. Per impostazione predefinita, GRAPH_EXPAND restituisce una rappresentazione tabulare appiattita del grafico con una colonna per proprietà. Puoi anche specificare flatten_results => FALSE per restituire una tabella gerarchica con colonne STRUCT nidificate. Se il grafico contiene più tabelle dei nodi principali, puoi specificare l'argomento start_node per scegliere quale tabella principale attraversare.
Questa funzione non accetta tutti i tipi di grafici. Per saperne di più su quali grafici formano un input valido, consulta le limitazioni di input.
Per eseguire query GQL, devi disporre di una prenotazione che utilizzi la versione Enterprise o Enterprise Plus.
Se utilizzi i prezzi on demand, puoi chiamare la funzione GRAPH_EXPAND per eseguire query SQL sul grafico.
Puoi chiamare la
funzione AGG
sull'output della TVF GRAPH_EXPAND per aggregare
le proprietà in base all'aggregazione definita nella
misura.
Definisci le misure
Puoi definire le misure all'interno della clausola PROPERTIES di una definizione di tabella dei nodi o degli archi utilizzando la parola chiave MEASURE() attorno a un'espressione di misura.
L'esempio seguente crea un set di dati denominato university e tabelle per college, dipartimenti e corsi:
CREATE SCHEMA IF NOT EXISTS university;
CREATE OR REPLACE TABLE university.College (
college_id INT64 PRIMARY KEY NOT ENFORCED,
college_name STRING
);
CREATE OR REPLACE TABLE university.Department (
dept_id INT64 PRIMARY KEY NOT ENFORCED,
dept_name STRING,
college_id INT64,
budget FLOAT64,
FOREIGN KEY (college_id) REFERENCES university.College(college_id) NOT ENFORCED
);
CREATE OR REPLACE TABLE university.Course (
course_id INT64 PRIMARY KEY NOT ENFORCED,
course_name STRING,
dept_id INT64,
credits INT64,
FOREIGN KEY (dept_id) REFERENCES university.Department(dept_id) NOT ENFORCED
);
INSERT INTO university.College (college_id, college_name)
VALUES (101, 'College of Engineering'),
(102, 'College of Arts');
INSERT INTO university.Department (dept_id, dept_name, college_id, budget)
VALUES (1001, 'Computer Science', 101, 500000),
(1002, 'Mechanical Engineering', 101, 400000),
(1003, 'Fine Arts', 102, 200000),
(1004, 'Research', 101, 50000);
INSERT INTO university.Course (course_id, course_name, dept_id, credits)
VALUES (1, 'Intro to CS', 1001, 3),
(2, 'Data Structures', 1001, 4),
(3, 'Thermodynamics', 1002, 3),
(4, 'Oil Painting', 1003, 2);
La seguente istruzione crea un grafico denominato SchoolGraph che definisce le misure sulle proprietà nei nodi Department e Course.
Devi fornire un alias per le proprietà definite da una misura.
CREATE OR REPLACE PROPERTY GRAPH university.SchoolGraph
NODE TABLES (
university.College
KEY(college_id)
PROPERTIES(college_id, college_name),
university.Department
KEY(dept_id)
PROPERTIES(dept_id, dept_name, college_id,
budget OPTIONS(description="Department budget in USD"),
MEASURE(SUM(budget)) AS total_budget,
MEASURE(SUM(budget) * 1.10) AS budget_with_overhead OPTIONS(
description="Total department budget including 10% overhead",
extensions=[("unit", "USD"), ("tier", "planning")]
)),
university.Course
KEY(course_id)
PROPERTIES(
course_id,
course_name,
credits,
dept_id,
MEASURE(AVG(credits)) AS avg_credits,
MEASURE(SUM(credits)) AS total_credits,
MEASURE(COUNT(course_id)) AS course_count,
MEASURE(COUNT(DISTINCT CASE WHEN credits >= 3 THEN course_id ELSE NULL END)) AS major_course_count,
MEASURE(SAFE_DIVIDE(AGG(total_credits), NULLIF(AGG(course_count), 0))) AS computed_avg_credits)
)
EDGE TABLES (
university.Department AS CollegeDept
SOURCE KEY (college_id) REFERENCES College (college_id)
DESTINATION KEY (dept_id) REFERENCES Department (dept_id),
university.Course AS DeptCourse
SOURCE KEY (dept_id) REFERENCES Department (dept_id)
DESTINATION KEY (course_id) REFERENCES Course (course_id)
);

La misura total_budget è definita come MEASURE(SUM(budget)). La misura blocca l'aggregazione su KEY, ovvero dept_id.
Misure derivate
Una misura derivata è una misura che fa riferimento ad altre misure definite nella stessa tabella degli elementi utilizzando la funzione AGG(). Questa funzionalità ti consente di creare gerarchie di misure riutilizzabili.
Ad esempio, in university.Course, la misura computed_avg_credits calcola il rapporto tra le misure total_credits e course_count:
MEASURE(SAFE_DIVIDE(AGG(total_credits), NULLIF(AGG(course_count), 0))) AS computed_avg_credits
Le misure derivate mantengono la proprietà di blocco della granularità della chiave della tabella degli elementi sottostante. Le dipendenze delle misure vengono risolte al tempo di compilazione del grafo. I riferimenti circolari tra le misure restituiscono un errore.
Informazioni sul conteggio eccessivo
Quando unisci le tabelle, i dati vengono ripetuti ogni volta che esiste una relazione uno-a-molti nei dati. Ad esempio, se unisci le tabelle Course, Department e College, un dipartimento con più corsi viene visualizzato in più righe nell'output:
SELECT
college_name,
dept_name,
course_name,
budget
FROM university.Course
LEFT JOIN university.Department
ON Course.dept_id = Department.dept_id
LEFT JOIN university.College
ON Department.college_id = College.college_id;
/*------------------------+------------------------+-----------------+----------+
| college_name | dept_name | course_name | budget |
+------------------------+------------------------+-----------------+----------+
| College of Engineering | Computer Science | Intro to CS | 500000.0 |
| College of Engineering | Computer Science | Data Structures | 500000.0 |
| College of Engineering | Mechanical Engineering | Thermodynamics | 400000.0 |
| College of Arts | Fine Arts | Oil Painting | 200000.0 |
+------------------------+------------------------+-----------------+----------*/
Se provi a calcolare il budget totale per college utilizzando SUM(budget),
il budget del dipartimento di informatica viene conteggiato due volte. Puoi evitare questo problema eseguendo query direttamente sulla tabella Department, ma questo approccio non funziona se vuoi calcolare più aggregazioni da tabelle diverse che contribuiscono ai dati uniti. La sezione seguente mostra come le misure risolvono questo problema.
Esegui query su un grafico con misure
Puoi eseguire query su un grafo con misure utilizzando GQL, ma la query non può fare riferimento direttamente a nessuna proprietà definita da una misura. Ad esempio, la seguente query fa riferimento a nodi per i quali sono definite proprietà di misurazione, ma non utilizza né restituisce nessuno dei campi di misurazione:
GRAPH university.SchoolGraph
MATCH (c:College)->(d:Department)->(course:Course)
RETURN c.college_name, d.dept_name, course.course_name;
/*------------------------+------------------------+-----------------+
| college_name | dept_name | course_name |
+------------------------+------------------------+-----------------+
| College of Engineering | Computer Science | Intro to CS |
| College of Engineering | Computer Science | Data Structures |
| College of Engineering | Mechanical Engineering | Thermodynamics |
| College of Arts | Fine Arts | Oil Painting |
+------------------------+------------------------+-----------------*/
Per utilizzare le misure, utilizza la funzione con valori di tabella (TVF) GRAPH_EXPAND per eseguire query sul grafico come tabella relazionale:
GRAPH_EXPAND(
graph_name [, start_node => 'NodeName'] [, flatten_results => TRUE|FALSE]
)
La funzione accetta i seguenti argomenti:
graph_name: unSTRINGcontenente il nome del grafico.start_node: unSTRINGfacoltativo che specifica la tabella dei nodi di partenza per l'esplorazione. Questo argomento è obbligatorio se il grafico ha più tabelle di nodi principali.flatten_results: unBOOLfacoltativo (il valore predefinito èTRUE):TRUE: appiattisce tutte le proprietà di nodi e archi in colonne di primo livello con prefissi<element>_<property>.FALSE: restituisce le proprietà del nodo principale come colonne di primo livello senza prefisso e le tabelle adiacenti unite come colonneSTRUCT.
Utilizza l'output semplificato
Quando flatten_results è impostato su TRUE (la modalità predefinita), i nomi delle colonne nella tabella di output vengono assegnati concatenando l'etichetta della tabella dei nodi o degli archi e il nome della proprietà, ad esempio Course_course_name o Department_total_budget. La seguente query mostra l'output di esempio della TVF GRAPH_EXPAND:
SELECT
College_college_name,
Department_dept_name,
Department_budget,
Course_course_name
FROM
GRAPH_EXPAND("university.SchoolGraph");
/*------------------------+------------------------+-------------------+--------------------+
| College_college_name | Department_dept_name | Department_budget | Course_course_name |
+------------------------+------------------------+-------------------+--------------------+
| College of Engineering | Computer Science | 500000.0 | Intro to CS |
| College of Engineering | Computer Science | 500000.0 | Data Structures |
| College of Engineering | Mechanical Engineering | 400000.0 | Thermodynamics |
| College of Arts | Fine Arts | 200000.0 | Oil Painting |
+------------------------+------------------------+-------------------+--------------------*/
La funzione GRAPH_EXPAND produce la tabella appiattita applicando una serie di operazioni LEFT JOIN alle tabelle di nodi e archi. Se non specifichi un nodo iniziale, il grafo di input deve avere una singola tabella dei nodi root nel grafo delle relazioni dello schema.
In modo equivalente, la tabella del nodo principale deve avere una relazione molti-a-uno con ogni altra tabella del nodo con cui condivide un arco.
I dati non raggiungibili dalla tabella del nodo principale tramite una serie di join non vengono visualizzati nell'output. Nell'esempio precedente, Course è la tabella del nodo principale. Il dipartimento Research viene omesso dall'output perché non ha corsi.
Non puoi selezionare direttamente una colonna per una proprietà definita da una misura.
Devi invece aggregarli nella funzione AGG().
Questa funzione garantisce che l'aggregazione definita sulle misure venga eseguita esattamente una volta per chiave.
La query seguente calcola contemporaneamente il budget totale e il numero totale di corsi per ogni college:
SELECT
College_college_name,
AGG(Department_total_budget) AS college_budget,
AGG(Course_course_count) AS total_courses
FROM
GRAPH_EXPAND("university.SchoolGraph")
GROUP BY
College_college_name;
/*------------------------+----------------+---------------+
| College_college_name | college_budget | total_courses |
+------------------------+----------------+---------------+
| College of Engineering | 900000.0 | 3 |
| College of Arts | 200000.0 | 1 |
+------------------------+----------------+---------------*/
Utilizza l'output gerarchico
Quando specifichi flatten_results => FALSE, GRAPH_EXPAND restituisce una relazione gerarchica anziché colonne con prefisso:
- Le proprietà del nodo principale iniziale vengono visualizzate come colonne di primo livello senza prefisso (ad esempio,
course_nameocredits). - Le proprietà delle tabelle adiacenti unite, che potrebbero essere tabelle di nodi o archi, vengono visualizzate come campi
STRUCTnidificati con il nome della tabella degli elementi. Ad esempio, se il nodo iniziale èCourse, utilizzerai la proprietà DeptCourse.Department.CollegeDept.College.college_nameto access thecollege_name`. - Le misure all'interno di struct nidificati vengono interrogate utilizzando la notazione con punto all'interno di
AGG(), ad esempioAGG(DeptCourse.Department.total_budget). - Se una tabella di elementi ha una proprietà con lo stesso nome di una tabella di elementi adiacente, non puoi eseguire query sul grafico utilizzando
flatten_results => FALSE. Devi invece appiattire i risultati.
SELECT
DeptCourse.Department.dept_name AS department_name,
DeptCourse.Department.CollegeDept.College.college_name,
AGG(DeptCourse.Department.total_budget) AS total_budget,
AGG(course_count) AS total_courses
FROM GRAPH_EXPAND(
"university.SchoolGraph",
start_node => "Course",
flatten_results => FALSE)
GROUP BY department_name, college_name;
Lavora con più tabelle di nodi principali
I grafici spesso contengono più tabelle di nodi principali, chiamate anche tabelle dei fatti, che condividono tabelle delle dimensioni. Per eseguire query su un grafico con più tabelle di nodi principali, utilizza l'argomento start_node in GRAPH_EXPAND. La funzione attraversa il sottografo raggiungibile dal nodo iniziale.
Ad esempio, puoi aggiungere una tabella Instructor al set di dati university che si collega anche a Department:
CREATE OR REPLACE TABLE university.Instructor (
instructor_id INT64 PRIMARY KEY NOT ENFORCED,
instructor_name STRING,
dept_id INT64,
salary FLOAT64,
FOREIGN KEY (dept_id) REFERENCES university.Department(dept_id) NOT ENFORCED
);
INSERT INTO university.Instructor (instructor_id, instructor_name, dept_id, salary)
VALUES (501, 'Dr. Dana', 1001, 120000),
(502, 'Dr. Lee', 1001, 110000),
(503, 'Dr. Taylor', 1002, 115000),
(504, 'Prof. Izumi', 1003, 90000);
Puoi creare un nuovo grafico denominato university.SchoolGraphMultiRoot che include la tabella dei nodi Instructor e un arco da Instructor a Department:
CREATE OR REPLACE PROPERTY GRAPH university.SchoolGraphMultiRoot
NODE TABLES (
university.College
KEY(college_id)
PROPERTIES(college_id, college_name),
university.Department
KEY(dept_id)
PROPERTIES(dept_id, dept_name, college_id, budget,
MEASURE(SUM(budget)) AS total_budget),
university.Course
KEY(course_id)
PROPERTIES(
course_id, course_name, credits, dept_id,
MEASURE(COUNT(course_id)) AS course_count),
university.Instructor
KEY(instructor_id)
PROPERTIES(
instructor_id, instructor_name, dept_id, salary,
MEASURE(COUNT(instructor_id)) AS instructor_count,
MEASURE(SUM(salary)) AS total_salary)
)
EDGE TABLES (
university.Department AS CollegeDept
SOURCE KEY (college_id) REFERENCES College (college_id)
DESTINATION KEY (dept_id) REFERENCES Department (dept_id),
university.Course AS DeptCourse
SOURCE KEY (dept_id) REFERENCES Department (dept_id)
DESTINATION KEY (course_id) REFERENCES Course (course_id),
university.Instructor AS DeptInstructor
SOURCE KEY (dept_id) REFERENCES Department (dept_id)
DESTINATION KEY (instructor_id) REFERENCES Instructor (instructor_id)
);
In questo grafico, sia Course che Instructor fungono da tabelle dei nodi principali che si collegano a Department e College. Puoi scegliere come target uno dei due sottografi passando start_node:
-- Expand the Course subgraph (Course -> Department -> College)
SELECT
College_college_name,
AGG(Course_course_count) AS total_courses
FROM GRAPH_EXPAND("university.SchoolGraphMultiRoot", start_node => "Course")
GROUP BY College_college_name;
-- Expand the Instructor subgraph (Instructor -> Department -> College)
SELECT
College_college_name,
AGG(Instructor_total_salary) AS total_faculty_salary
FROM GRAPH_EXPAND("university.SchoolGraphMultiRoot", start_node => "Instructor")
GROUP BY College_college_name;
Per analizzare le metriche in più tabelle dei fatti, esegui una query su ogni sottografo utilizzando GRAPH_EXPAND e uniscili in base alle dimensioni condivise in SQL standard:
SELECT
C.College_college_name,
AGG(C.Course_course_count) AS total_courses,
AGG(I.Instructor_total_salary) AS total_faculty_salary
FROM GRAPH_EXPAND("university.SchoolGraphMultiRoot", start_node => "Course") AS C
INNER JOIN GRAPH_EXPAND("university.SchoolGraphMultiRoot", start_node => "Instructor") AS I
ON C.Department_dept_id = I.Department_dept_id
GROUP BY C.College_college_name;
Sia AGG(C.Course_course_count) che AGG(I.Instructor_total_salary) calcolano le loro aggregazioni in modo accurato in base alle rispettive granularità senza interferenze da parte del join.
Best practice
Quando progetti un grafico con misure, segui queste best practice:
Definisci nodi e archi all'interno di una singola tabella
Ti consigliamo di utilizzare la stessa tabella per la definizione di una tabella di nodi e per le definizioni delle tabelle di archi di collegamento. Il riutilizzo della tabella garantisce una relazione uno a uno (1:1) tra la tabella dei nodi e la tabella degli archi, il che impedisce il fan-out e garantisce che la funzione GRAPH_EXPAND non ignori l'arco perché ambiguo.
Ad esempio, se hai una tabella di input Enrollment che contiene chiavi esterne che puntano alle tabelle Student e Course, definisci il nodo Enrollment e i relativi archi in uscita utilizzando la tabella di input Enrollment.
Evita di definire proprietà non necessarie nelle tabelle degli archi
Quando definisci una tabella dei nodi e una tabella degli archi utilizzando la stessa tabella fisica, non utilizzare la clausola PROPERTIES nella tabella degli archi, a meno che non ci siano nuove informazioni da acquisire nell'arco. Poiché la tabella dei nodi e la tabella degli archi utilizzano la stessa tabella fisica, tutte queste proprietà fanno già parte della tabella dei nodi.
La definizione di proprietà ridondanti nella tabella degli archi può far sì che la funzione GRAPH_EXPAND tratti la tabella degli archi come un'entità separata dalla tabella dei nodi condivisa. Per ottimizzare le prestazioni, specifica NO PROPERTIES nella definizione della tabella degli archi quando non ci sono nuove proprietà da acquisire sull'arco.
Modella le relazioni many-to-many come tabelle di nodi
Una relazione many-to-many (M:N) si verifica quando una riga della tabella A può corrispondere a più righe della tabella B e una riga della tabella B può corrispondere a più righe della tabella A. Ad esempio, uno studente può iscriversi a più corsi e un corso può avere molti studenti. Puoi separare una relazione many-to-many
in due relazioni one-to-many utilizzando una
tabella di giunzione intermedia. Ad esempio, puoi definire una tabella Enrollment che contiene chiavi esterne che puntano alle tabelle Student e Course. Se
modelli una tabella di giunzione intermedia come tabella di archi che collega due
tabelle di nodi di dimensione nell'istruzione CREATE PROPERTY GRAPH, come nell'
esempio seguente, la
funzione GRAPH_EXPAND ignora questi archi perché la loro relazione è
ambigua: non è chiaramente many-to-one o one-to-one.
CREATE PROPERTY GRAPH university.SchoolGraph
NODE TABLES (
university.Student,
university.Course
)
EDGE TABLES (
-- Modeling the junction table as a standalone edge causes ambiguity
university.Enrollment AS StudentEnrollment
SOURCE KEY (student_id) REFERENCES Student (student_id)
DESTINATION KEY (course_id) REFERENCES Course (course_id)
);
Se tutti gli archi di un grafo vengono ignorati, le chiamate a GRAPH_EXPAND o BQ.SHOW_GRAPH_EXPAND_SCHEMA non vanno a buon fine e viene generato un errore.
Per modellare correttamente una relazione M:N per le misure, promuovi la tabella di giunzione intermedia a una tabella di nodi. In questa struttura, la tabella dei nodi di giunzione funge da singola tabella dei nodi principali (una tabella dei nodi con un grado di ingresso pari a zero). Poi, definisci due tabelle perimetrali molti-a-uno (N:1) che condividono la tabella di giunzione per connettere N:1 a ciascuna delle tabelle dei nodi delle dimensioni:
CREATE PROPERTY GRAPH university.SchoolGraph
NODE TABLES (
university.Student KEY (student_id),
university.Course KEY (course_id),
-- Promote the junction table to a node table (acting as the single root node)
university.Enrollment KEY (enrollment_id)
)
EDGE TABLES (
-- Share (reuse) the Enrollment table to define N:1 edges to each dimension
university.Enrollment AS EnrollmentToStudent
SOURCE KEY (enrollment_id) REFERENCES Enrollment (enrollment_id)
DESTINATION KEY (student_id) REFERENCES Student (student_id),
university.Enrollment AS EnrollmentToCourse
SOURCE KEY (enrollment_id) REFERENCES Enrollment (enrollment_id)
DESTINATION KEY (course_id) REFERENCES Course (course_id)
);
In questa struttura, Enrollment funge da singola tabella del nodo principale (grado in entrata pari a zero) che collega N:1 alle tabelle delle dimensioni Student e Course (grado in entrata pari a uno). La funzione GRAPH_EXPAND può appiattire questo grafico
attraversando verso l'esterno da Enrollment a Student e Course. Se definisci misure su una di queste tabelle, puoi chiamare la funzione AGG sulle colonne delle misure per calcolare correttamente le aggregazioni senza conteggi eccessivi.
Scegli come gestire le righe senza corrispondenza nelle misure
Quando una riga non ha corrispondenze in una tabella di elementi collegati, le colonne di quella tabella sono NULL nell'output GRAPH_EXPAND. Ad esempio, se un corso non ha un valore dept_id, le colonne Department di quella riga sono NULL. L'inclusione o meno di queste righe da parte di una misura nel nodo Department dipende da dove scrivi l'espressione scalare aggregata dalla misura.
Se scrivi l'espressione all'interno della funzione di aggregazione, l'espressione viene valutata per ogni riga dell'output espanso, incluse le righe senza corrispondenza.
Quando l'espressione restituisce un valore anziché NULL per una di queste righe,
questo valore contribuisce al risultato.
Se definisci l'espressione come una proprietà e fai riferimento a questa proprietà dalla misura, l'espressione viene valutata sulle righe della tabella dei nodi e le righe senza corrispondenza non contribuiscono al risultato.
L'esempio seguente definisce la stessa espressione in entrambi i modi su
university.Department:
university.Department
KEY(dept_id)
PROPERTIES(dept_id, dept_name, college_id, budget,
COALESCE(budget, 0) AS budget_or_zero,
-- Includes courses that have no department, as a budget of 0.
MEASURE(AVG(COALESCE(budget, 0))) AS avg_budget_inline,
-- Averages only departments that exist.
MEASURE(AVG(budget_or_zero)) AS avg_budget_property)
Entrambe le misure sostituiscono un budget di NULL con 0. Il modulo incorporato sostituisce anche i valori NULL prodotti per un corso che non ha un dipartimento, in modo che il corso venga calcolato come un dipartimento con un budget di 0. Scegli il modulo che corrisponde a ciò che vuoi misurare.
Visualizza lo schema GRAPH_EXPAND
Per visualizzare lo schema della tabella restituita dalla funzione GRAPH_EXPAND senza chiamare la funzione, utilizza la procedura di sistema BQ.SHOW_GRAPH_EXPAND_SCHEMA:
DECLARE schema STRING DEFAULT '';
CALL BQ.SHOW_GRAPH_EXPAND_SCHEMA('university.SchoolGraph', schema);
SELECT schema;
Questa procedura compila la variabile schema con il nome, il tipo e la modalità di ogni colonna. Indica anche se la proprietà a cui fa riferimento la colonna è una misura ed elenca eventuali descrizioni o sinonimi che hai definito.
Passaggi successivi
- Scopri come creare ed eseguire query su un grafico.
- Scopri di più sugli schemi dei grafici.