Trabaja con medidas

En este documento, se muestra cómo definir y consultar medidas en tus gráficos. Puedes usar medidas para garantizar que las agregaciones se realicen correctamente en todas las uniones.

Descripción general

Una medida es una propiedad agregada que se define dentro de la cláusula PROPERTIES de una tabla de nodos o aristas. Las medidas se definen con la palabra clave MEASURE y una de las siguientes funciones de agregación admitidas:

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

Las medidas definen su agregación en referencia al KEY de la tabla de nodos o aristas en la que se definen. Esto significa que, cuando consultas una métrica, la agregación se realiza correctamente incluso si la tabla subyacente se une de una manera que provoca que se dupliquen las filas.

No puedes hacer referencia a una propiedad definida por una métrica en una consulta de GQL. En cambio, puedes acceder a las medidas llamando a la TVF GRAPH_EXPAND para crear una representación de tabla aplanada de tu gráfico. Esta función no acepta todos los tipos de gráficos. Para obtener más información sobre qué gráficos forman una entrada válida, consulta las limitaciones de entrada.

Puedes llamar a la función AGG en el resultado de la TVF GRAPH_EXPAND para agregar las propiedades según la función de agregación que definiste en la métrica.

Cómo definir medidas

Puedes definir medidas dentro de la cláusula PROPERTIES de una definición de tabla de nodos o aristas usando la palabra clave MEASURE() alrededor de una función agregada admitida.

En el siguiente ejemplo, se crea un conjunto de datos llamado university y tablas para universidades, departamentos y cursos:

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 siguiente instrucción crea un gráfico llamado SchoolGraph que define medidas en algunas de las propiedades de los nodos Department y Course. Debes proporcionar un alias para las propiedades definidas por una métrica.

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

Visualización del gráfico de SchoolGraph.

La medida total_budget se define como MEASURE(SUM(budget)). La medida bloquea la agregación en KEY, que es dept_id.

Información sobre el recuento excesivo

Cuando unes tablas, los datos se repiten cada vez que hay una relación de uno a varios en tus datos. Por ejemplo, si unes las tablas Course, Department y College, un departamento con varios cursos aparecerá en varias filas del resultado:

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 intentas calcular el presupuesto total por facultad con SUM(budget), el presupuesto del departamento de Ciencias de la Computación se cuenta dos veces. Puedes evitar este problema consultando la tabla Department directamente, pero este enfoque no funciona si deseas calcular varias agregaciones a partir de diferentes tablas que contribuyen a tus datos combinados. En la siguiente sección, se muestra cómo las medidas resuelven este problema.

Cómo consultar un gráfico con medidas

Puedes consultar un gráfico con medidas usando GQL, pero tu consulta no puede hacer referencia directamente a ninguna propiedad definida por una medida. Por ejemplo, la siguiente consulta hace referencia a nodos que tienen propiedades de medidas definidas, pero no usa ni devuelve ninguno de los campos de medidas:

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

Trabaja con medidas

Para trabajar con medidas, usa la función con valor de tabla (TVF) GRAPH_EXPAND para consultar tu gráfico como una sola tabla aplanada. Las columnas de la tabla de salida se derivan de las propiedades definidas en el grafo para cada tabla de nodos y aristas. Para evitar conflictos de nombres, las columnas se nombran concatenando la etiqueta de la tabla de nodos o aristas y el nombre de la propiedad (por ejemplo, Course_course_name o Department_total_budget). La siguiente consulta muestra algunos resultados de muestra 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 función GRAPH_EXPAND produce la tabla aplanada aplicando una serie de operaciones LEFT JOIN a las tablas de nodos y bordes. Un gráfico de entrada válido debe tener exactamente una tabla de nodos raíz, que es una tabla cuyo valor de KEY no aparece en ninguna otra tabla. Los datos a los que no se puede acceder desde la tabla del nodo raíz a través de una serie de uniones no aparecen en el resultado. En el ejemplo anterior, la tabla Course es la tabla del nodo raíz. El departamento de Research se omite del resultado porque no tiene ningún curso.

No puedes seleccionar directamente una columna para una propiedad definida por una medida. En cambio, debes unirlas en la función AGG(). Esta función garantiza que la agregación definida en las medidas se realice exactamente una vez por clave.

La siguiente consulta calcula simultáneamente el presupuesto total y la cantidad total de cursos para cada universidad:

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

Prácticas recomendadas

Cuando diseñes un gráfico con medidas, sigue estas prácticas recomendadas:

Cómo definir nodos y aristas en una sola tabla

Te recomendamos que uses la misma tabla para la definición de una tabla de nodos y sus definiciones de tablas de aristas de conexión. La reutilización de la tabla garantiza una relación exacta de uno a uno (1:1) entre la tabla de nodos y la tabla de aristas, lo que evita el fan-out y garantiza que la función GRAPH_EXPAND no ignore la arista como ambigua.

Por ejemplo, si tienes una tabla de entrada Enrollment que contiene claves externas que apuntan a las tablas Student y Course, define el nodo Enrollment y sus aristas salientes con la tabla de entrada Enrollment.

Cómo modelar relaciones de varios a varios como tablas de nodos

Se produce una relación de varios a varios (M:N) cuando una fila de la tabla A puede corresponder a varias filas de la tabla B, y una fila de la tabla B puede corresponder a varias filas de la tabla A. Por ejemplo, un estudiante puede inscribirse en varios cursos y un curso puede tener muchos estudiantes. Puedes separar una relación de varios a varios en dos relaciones de uno a varios con una tabla de unión intermedia. Por ejemplo, puedes definir una tabla Enrollment que contenga claves externas que apunten a las tablas Student y Course. Si modelas una tabla de unión intermedia como una tabla de borde que conecta dos tablas de nodos de dimensión en tu instrucción CREATE PROPERTY GRAPH, la función GRAPH_EXPAND ignora estos bordes porque su relación es ambigua: no es claramente de muchos a uno ni de uno a uno.

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 función GRAPH_EXPAND ignora estas aristas porque son ambiguas (no son claramente de muchos a uno o de uno a uno entre las tablas de nodos). Si se ignoran todas las aristas de un gráfico, las llamadas a GRAPH_EXPAND o BQ.SHOW_GRAPH_EXPAND_SCHEMA fallan con un error.

Para modelar correctamente una relación de M:N para las mediciones, promueve la tabla de unión intermedia a una tabla de nodos. En esta estructura, la tabla de nodos de unión sirve como la única tabla de nodos raíz (una tabla de nodos con un grado de entrada de cero). Luego, define dos tablas de conexión de integración de muchos a uno (N:1) que compartan la tabla de unión para conectar N:1 a cada una de las tablas de nodos de dimensión:

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

En esta estructura, Enrollment actúa como la única tabla de nodos raíz (grado de entrada cero) que conecta N:1 a las tablas de dimensiones Student y Course (grado de entrada uno). La función GRAPH_EXPAND puede aplanar este gráfico recorriéndolo hacia afuera desde Enrollment hasta Student y Course. Si defines medidas en cualquiera de estas tablas, puedes llamar a la función AGG en las columnas de medidas para calcular correctamente las agregaciones sin contar de más.

Ver el esquema de GRAPH_EXPAND

Para ver el esquema de la tabla que devuelve la función GRAPH_EXPAND sin llamar a la función, usa el procedimiento del sistema BQ.SHOW_GRAPH_EXPAND_SCHEMA:

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

Este procedimiento completa la variable schema con el nombre, el tipo y el modo de cada columna. También indica si la propiedad a la que hace referencia la columna es una métrica y enumera cualquier descripción o sinónimos que hayas definido en ella.

¿Qué sigue?