Utiliser les mesures

Ce document vous explique comment définir et interroger des mesures dans vos graphiques. Vous pouvez utiliser des mesures pour vous assurer que les agrégations sont effectuées correctement dans les jointures.

Présentation

Une mesure est une propriété agrégée définie dans la clause PROPERTIES d'une table de nœuds ou d'arêtes. Les mesures sont définies à l'aide du mot clé MEASURE et de l'une des fonctions d'agrégation compatibles suivantes :

  • SUM
  • AVG
  • COUNT
  • COUNT(DISTINCT)
  • MIN
  • MAX

Les mesures définissent leur agrégation en référence à la KEY de la table de nœuds ou d'arêtes sur laquelle elles sont définies. Cela signifie que lorsque vous interrogez une mesure, l'agrégation est effectuée correctement, même si la table sous-jacente est jointe de manière à entraîner la duplication des lignes.

Vous ne pouvez pas référencer une propriété définie par une mesure dans une requête GQL. Au lieu de cela, vous accédez aux mesures en appelant la TVF GRAPH_EXPAND pour créer une représentation tabulaire aplatie de votre graphique. Cette fonction n'accepte pas tous les types de graphiques. Pour en savoir plus sur les graphiques qui constituent des entrées valides, consultez les limites d'entrée. Pour exécuter des requêtes GQL, vous devez disposer d'une réservation qui utilise l'édition Enterprise ou Enterprise Plus. Si vous utilisez un tarif à la demande, vous pouvez appeler la fonction GRAPH_EXPAND pour exécuter des requêtes SQL sur votre graphique.

Vous pouvez appeler la fonction AGG sur la sortie de la TVF GRAPH_EXPAND pour agréger les propriétés en fonction de la fonction d'agrégation que vous avez définie dans la mesure.

Définir des mesures

Vous définissez des mesures dans la clause PROPERTIES d'une définition de table de nœuds ou d'arêtes en utilisant le mot clé MEASURE() autour d'une fonction d'agrégation compatible.

L'exemple suivant crée un ensemble de données appelé university et des tables pour les établissements, les départements et les cours :

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);

L'instruction suivante crée un graphique appelé SchoolGraph qui définit des mesures sur certaines propriétés des nœuds Department et Course. Vous devez fournir un alias pour les propriétés définies par une mesure.

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),
    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)
  )
  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)
  );

Visualisation du graphique SchoolGraph.

La mesure total_budget est définie comme MEASURE(SUM(budget)). La mesure verrouille l'agrégation sur KEY, qui est dept_id.

Comprendre le double comptage

Lorsque vous joignez des tables, les données sont répétées chaque fois qu'il existe une relation un-à-plusieurs dans vos données. Par exemple, si vous joignez les tables Course, Department et College, un département avec plusieurs cours apparaît sur plusieurs lignes dans le résultat :

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 |
 +------------------------+------------------------+-----------------+----------*/

Si vous essayez de calculer le budget total par faculté à l'aide de SUM(budget), le budget du département d'informatique est comptabilisé deux fois. Vous pouvez éviter ce problème en interrogeant directement la table Department, mais cette approche ne fonctionne pas si vous souhaitez calculer plusieurs agrégations à partir de différentes tables qui contribuent à vos données jointes. La section suivante explique comment les mesures résolvent ce problème.

Interroger un graphique avec des mesures

Vous pouvez interroger un graphique avec des mesures à l'aide de GQL, mais votre requête ne peut pas faire directement référence à une propriété définie par une mesure. Par exemple, la requête suivante fait référence à des nœuds dont les propriétés de mesure sont définies, mais n'utilise ni ne renvoie aucun des champs de mesure :

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    |
 +------------------------+------------------------+-----------------*/

Utiliser les mesures

Pour travailler avec des mesures, vous utilisez la fonction de valeur de table (TVF) GRAPH_EXPAND pour interroger votre graphique en tant que tableau unique aplati. Les colonnes du tableau de sortie sont dérivées des propriétés définies dans le graphique pour chaque table de nœuds et d'arêtes. Pour éviter les conflits de noms, les colonnes sont nommées en concaténant le libellé de la table de nœuds ou d'arêtes et le nom de la propriété (par exemple, Course_course_name ou Department_total_budget). La requête suivante montre des exemples de résultats de la 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 fonction GRAPH_EXPAND produit la table aplatie en appliquant une série d'opérations LEFT JOIN aux tables de nœuds et d'arêtes. Un graphique d'entrée valide doit comporter exactement une table de nœuds racine, c'est-à-dire une table dont la valeur KEY n'apparaît dans aucune autre table. Les données qui ne sont pas accessibles à partir de la table du nœud racine via une série de jointures n'apparaissent pas dans la sortie. Dans l'exemple précédent, la table Course est la table du nœud racine. Le département Research est omis du résultat, car il ne comporte aucun cours.

Vous ne pouvez pas sélectionner directement une colonne pour une propriété définie par une mesure. À la place, vous devez les encapsuler dans la fonction AGG(). Cette fonction garantit que l'agrégation définie sur les mesures est effectuée exactement une fois par clé.

La requête suivante calcule simultanément le budget total et le nombre total de cours pour chaque établissement :

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             |
 +------------------------+----------------+---------------*/

Bonnes pratiques

Lorsque vous concevez un graphique avec des mesures, suivez ces bonnes pratiques :

Définir des nœuds et des arêtes dans un même tableau

Nous vous recommandons d'utiliser la même table pour la définition d'une table de nœuds et pour les définitions des tables d'arêtes qui y sont associées. La réutilisation de la table garantit une relation exacte un-à-un (1:1) entre la table de nœuds et la table d'arêtes, ce qui empêche la distribution ramifiée et garantit que la fonction GRAPH_EXPAND n'ignore pas l'arête comme ambiguë.

Par exemple, si vous disposez d'une table d'entrée Enrollment contenant des clés étrangères pointant vers les tables Student et Course, définissez le nœud Enrollment et ses arêtes sortantes à l'aide de la table d'entrée Enrollment.

Modéliser les relations plusieurs à plusieurs en tant que tables de nœuds

Une relation plusieurs à plusieurs (M:N) se produit lorsqu'une ligne du tableau A peut correspondre à plusieurs lignes du tableau B, et qu'une ligne du tableau B peut correspondre à plusieurs lignes du tableau A. Par exemple, un élève peut s'inscrire à plusieurs cours et un cours peut compter plusieurs élèves. Vous pouvez séparer une relation plusieurs-à-plusieurs en deux relations un-à-plusieurs à l'aide d'une table de jonction intermédiaire. Par exemple, vous pouvez définir une table Enrollment contenant des clés étrangères pointant vers les tables Student et Course. Si vous modélisez une table de jonction intermédiaire en tant que table d'arêtes qui relie deux tables de nœuds de dimension dans votre instruction CREATE PROPERTY GRAPH, la fonction GRAPH_EXPAND ignore ces arêtes, car leur relation est ambiguë (elle n'est pas clairement de type "plusieurs à un" ou "un à un").

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)
  );

La fonction GRAPH_EXPAND ignore ces arêtes, car elles sont ambiguës (elles ne sont pas clairement de type "plusieurs-à-un" ou "un-à-un" entre les tables de nœuds elles-mêmes). Si tous les bords d'un graphique sont ignorés, les appels à GRAPH_EXPAND ou BQ.SHOW_GRAPH_EXPAND_SCHEMA échouent et génèrent une erreur.

Pour modéliser correctement une relation M:N pour les mesures, promouvez la table de jonction intermédiaire en table de nœuds. Dans cette structure, la table de nœuds de jonction sert de table de nœuds racine unique (une table de nœuds avec un degré entrant de zéro). Définissez ensuite deux tables périphériques plusieurs-à-un (N:1) qui partagent la table de jonction pour connecter N:1 à chacune des tables de nœuds de dimension :

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)
  );

Dans cette structure, Enrollment sert de table de nœud racine unique (degré entrant zéro) qui connecte N:1 aux tables de dimensions Student et Course (degré entrant un). La fonction GRAPH_EXPAND peut aplatir ce graphique en parcourant les nœuds de Enrollment à Student et Course. Si vous définissez des mesures sur l'une de ces tables, vous pouvez appeler la fonction AGG sur les colonnes de mesure pour calculer correctement les agrégations sans surestimation.

Afficher le schéma GRAPH_EXPAND

Pour afficher le schéma de la table renvoyée par la fonction GRAPH_EXPAND sans appeler la fonction, utilisez la procédure système BQ.SHOW_GRAPH_EXPAND_SCHEMA :

DECLARE schema STRING DEFAULT '';
CALL BQ.SHOW_GRAPH_EXPAND_SCHEMA('university.SchoolGraph', schema);
SELECT schema;

Cette procédure remplit la variable schema avec le nom, le type et le mode de chaque colonne. Il indique également si la propriété référencée par la colonne est une mesure et liste toute description ou tout synonyme que vous avez définis pour celle-ci.

Étapes suivantes