2 puntos por GN⁺ 3 시간 전 | Aún no hay comentarios. | Compartir por WhatsApp
  • Los grafos de propiedades de Postgres 19 son una función SQL/PGQ que declara tablas existentes como vértices y aristas, y busca patrones de relaciones fijos con MATCH; no copia datos ni crea un motor de ejecución de grafos separado
  • Los patrones de grafos se compilan como joins relacionales, por lo que usan tal cual el optimizador, los índices y las estadísticas existentes; así, los recorridos lentos se pueden analizar y optimizar igual que los joins normales
  • Las tablas de dimensiones se corresponden naturalmente con vértices, y las tablas puras de join con aristas, pero conviene modelar las tablas de hechos que tienen varias claves foráneas y propiedades propias como vértices hub que representan eventos
  • Una misma tabla puede declararse simultáneamente como vértice y como varias aristas con distintos alias, por lo que no hace falta crear ni almacenar tablas de aristas separadas usando las claves foráneas existentes de results
  • Postgres 19 no admite rutas de longitud variable, por lo que no es adecuado para rutas más cortas, alcanzabilidad a N saltos ni PageRank; sí es adecuado para exploraciones de longitud fija en las que se conoce de antemano la estructura relacional

Cómo leer un esquema relacional como un grafo

  • En un esquema relacional normalizado, las tablas de dimensiones como drivers, constructors y circuits contienen entidades, mientras que las tablas de hechos registran eventos como resultados de carreras o sesiones de clasificación
  • Cada fila es un vértice potencial, y cada clave foránea es una arista potencial que apunta a otra fila
    • Un diagrama ER corresponde a un grafo a nivel de esquema
    • Las filas reales y sus relaciones de claves foráneas corresponden a un grafo a nivel de instancia
  • La petición “encontrar el constructor correspondiente a cada resultado” es un recorrido de grafo que en SQL relacional se escribe como results JOIN constructors ON ...
  • SQL/PGQ no agrega un grafo nuevo como tal, sino que permite formular la pregunta en forma de grafo en lugar de enumerar joins directamente
  • El enfoque de RelBench trae las tablas a pandas y construye un grafo de PyTorch en memoria, pero los grafos de propiedades de Postgres usan tal cual las relaciones entre tablas existentes dentro de la base de datos
  • Los ejemplos de PyG también usan principalmente archivos planos o grafos en memoria
  • El código experimentado con el dataset de Formula 1 está disponible en el repositorio de GitHub

Composición de un grafo de propiedades

  • CREATE PROPERTY GRAPH es un objeto declarativo con nombre que se crea sobre tablas existentes
    • VERTEX TABLES especifica las tablas cuyas filas se leerán como vértices
    • EDGE TABLES especifica las tablas cuyas filas se leerán como relaciones de conexión
  • En cada tabla de vértices se definen los siguientes elementos
    • KEY: identificador del vértice; en la mayoría de los casos se usa la clave primaria
    • LABEL: nombre del tipo de vértice que se usará en MATCH
    • PROPERTIES: lista de columnas accesibles desde las consultas de grafo
  • En cada tabla de aristas se especifican SOURCE y DESTINATION, y ambos valores hacen referencia a la clave de un vértice
  • CREATE PROPERTY GRAPH no mueve ni copia datos
    • Las filas permanecen en sus tablas originales
    • La declaración solo define cómo leer como grafo la estructura de claves foráneas existente
  • Los elementos estructurales de un grafo de propiedades son solo dos tipos: vértices y aristas
    • Las etiquetas y propiedades son atributos que pertenecen a vértices o aristas
    • En psql, el Element Kind de cada elemento es vertex o edge

Consultar patrones fijos con MATCH

  • Las consultas de grafo se escriben colocando un patrón MATCH dentro de GRAPH_TABLE(...)
  • El siguiente patrón representa una relación que va de driver a race pasando por result
MATCH (d IS driver)<-[IS of_driver]-(res IS result)-[IS in_race]->(ra IS race)  
  • La cláusula COLUMNS especifica las columnas que la consulta de grafo devolverá al exterior
  • En el SELECT externo se puede consultar el resultado de GRAPH_TABLE(...) como si fuera una tabla normal
  • Como el patrón incluye direcciones y etiquetas, la relación se lee casi como una oración, lo que facilita entender la estructura frente a un conjunto equivalente de múltiples joins

Estructura que se transforma en joins relacionales al ejecutarse

  • MATCH no es un motor de ejecución de grafos añadido por separado a Postgres, sino sintaxis que se compila como joins relacionales
  • Al ejecutar EXPLAIN sobre el patrón driver–result–race aparecen cuatro hash joins sobre las tablas base
  • Igual que con joins escritos manualmente, usa los siguientes elementos
    • El optimizador existente de Postgres
    • Los índices existentes
    • Las estadísticas existentes
  • Si un recorrido de grafo es lento, las causas y las formas de optimizarlo son las mismas que cuando un join normal es lento
  • También en psql se pueden inspeccionar los grafos con comandos similares a los de tablas
    • \dG: muestra la lista de grafos de propiedades
    • \d f1: muestra cada vértice y arista, la tabla base, el tipo de elemento y los vértices de origen y destino de las aristas
    • \d+ f1: reconstruye la sentencia completa CREATE PROPERTY GRAPH, incluida la clave de arista inferida a partir de la clave primaria de la tabla de aristas

Diferencia entre claves y propiedades

  • Una columna especificada como KEY de un vértice no se convierte automáticamente en propiedad
  • Si se especifica driver_id solo como clave de vértice y luego se filtra con d.driver_id = 1, la consulta falla porque esa columna no es una propiedad consultable
  • La clave identifica al vértice, pero no la expone a las consultas
  • Para filtrar o devolver una columna de ID, hay que agregarla explícitamente a la lista PROPERTIES

Restricción de rutas de longitud variable en Postgres 19

  • Postgres 19 no admite cuantificadores de patrones de elementos como seguir una arista de 1 a 3 veces
ERROR: element pattern quantifier is not supported  
  • Para explorar dos saltos, hay que especificar dos patrones de aristas en MATCH
  • Las rutas de longitud arbitraria no pueden expresarse con la sintaxis de grafos de propiedades
  • Las exploraciones de profundidad abierta deben manejarse con CTE recursivas sobre las tablas base, en cuyo caso se sale de la sintaxis de grafos de propiedades

Mapear tablas existentes a vértices y aristas

  • Las tablas de dimensiones son vértices

    • Las tablas de entidades con claves primarias y atributos estables, como drivers, constructors y circuits, se corresponden directamente con vértices
    • Basta con usar la clave primaria como clave de vértice y exponer como propiedades las columnas necesarias
  • Las tablas puras de join son aristas

    • Las tablas puente de muchos a muchos como student_courses(student_id, course_id) tienen como función original conectar dos entidades, por lo que se corresponden naturalmente con aristas
    • Se declara una clave foránea como vértice de origen y la otra como vértice de destino
    • Como cada fila de la tabla de join ya es una relación, no se necesita una transformación de datos separada para el grafo
    • En esta estructura, students y courses son vértices, y student_courses se convierte en la arista enrolled_in
  • Las tablas de hechos son vértices de eventos

    • Una fila de results apunta a tres entidades —driver, race y constructor— y además tiene datos propios como grid, position, points y status
    • Como una arista SQL/PGQ es una relación binaria con un origen y un destino, no se puede convertir toda una fila con tres claves foráneas en una sola arista
    • Si la propia fila de hechos es objeto de análisis, conviene declarar esa tabla como vértice
    • El vértice results conserva el evento y sus atributos
    • Aristas estrechas como results_driver, results_race y results_constructor lo conectan con entidades externas
    • Este modelo crea una estructura de hub como driver <- result -> race, y permite detenerse en el vértice result para filtrar o consultar atributos
    • Si la relación en sí es el objeto de interés, modélala como arista; si lo es una fila o evento específico con atributos propios, modélalo como vértice
    • Las tablas de join representan relaciones, y las tablas de hechos representan eventos

Usar una misma tabla como vértice y arista al mismo tiempo

  • La distinción “vértice o arista” se aplica a cada declaración de elemento del grafo, no a la tabla base
  • Una misma tabla puede declararse en VERTEX TABLES y EDGE TABLES con distintos alias
  • Al usar results como vértice result, se puede reutilizar la misma tabla con los siguientes alias de aristas
    • results AS res_driver: conecta result con driver
    • results AS res_race: conecta result con race
    • results AS res_constr: conecta result con constructor
  • Cada alias de arista usa las columnas de clave primaria y claves foráneas que ya existen en results
  • No hace falta crear tablas separadas results_driver, results_race ni results_constructor, y los alias no almacenan datos
  • Una tabla de hechos con tres claves foráneas no debe declararse como una única arista con múltiples extremos, sino como tres alias de aristas, cada uno con un origen y un destino
  • Este enfoque usa tres alias declarativos sobre una sola tabla base en lugar de tres tablas físicas o vistas

Conflictos de nombres y tipos de propiedades

  • Si se omite PROPERTIES, SQL/PGQ expone todas las columnas de la tabla como propiedades
  • Si tanto results como qualifying tienen una columna number, pero con tipos double precision y bigint respectivamente, se produce el siguiente error
ERROR: property "number" data type mismatch: double precision vs. bigint  
  • En todo el grafo, las propiedades con el mismo nombre deben tener un único tipo, por lo que chocan las columnas homónimas con tipos distintos
  • Si se especifican solo las columnas necesarias en PROPERTIES, se pueden excluir del grafo las columnas conflictivas
  • Tanto el problema de que las claves no se conviertan automáticamente en propiedades como los conflictos de tipos pueden resolverse con una lista explícita de propiedades permitidas

Consultas adecuadas e inadecuadas

  • Patrones de relación fijos

    • Los grafos de propiedades son adecuados para preguntas como “encuentra los objetos conectados con X mediante este patrón específico”
    • En el grafo de Formula 1 se pueden escribir consultas como las siguientes
      1. Explorar en qué constructor corrió un driver específico
      2. Encontrar competidores mediante un patrón que va de driver a otro driver pasando por result, race y otro result
      3. Filtrar conjuntamente por condiciones de estructura y atributos, como resultados donde la posición de salida fue fuera del top 10 y el driver es italiano
    • Cuando se conoce de antemano la forma de la relación y esa estructura es fija y finita, mejora la legibilidad de la sintaxis de búsqueda, filtrado y agregación
    • Incluso las consultas que requieren varios self joins pueden expresarse de forma legible con un único patrón MATCH
  • Problemas donde la ruta en sí es desconocida

    • Los siguientes problemas no encajan con los grafos de propiedades de Postgres 19
      • La ruta más corta entre dos drivers
      • Todos los objetos alcanzables dentro de N saltos
      • Exploraciones de conectividad cuya profundidad no se conoce de antemano
    • Estas consultas requieren recorridos de longitud variable, por lo que deben usar CTE recursivas sobre las tablas base
    • Los algoritmos de grafos como PageRank, detección de comunidades y cálculo de centralidad también son problemas distintos del pattern matching, por lo que quedan fuera del alcance de esta función
    • Los grafos de propiedades encuentran objetos conectados cuando se conoce la estructura de la ruta, pero no descubren rutas cuando no se sabe por qué camino están conectados X e Y, ni calculan la importancia estructural dentro del grafo

Aspectos a evaluar antes de adoptarlo

  • SQL/PGQ es una capa declarativa superpuesta sobre la estructura de claves foráneas existente y no almacena datos adicionales salvo que se elija hacerlo por separado
  • Sus principales ventajas son dos
    • Permite escribir recorridos de forma fija de manera más legible que con joins relacionales
    • Proporciona un objeto con nombre que documenta el esquema como grafo
  • La mayor limitación es que no hay rutas de longitud variable, por lo que las exploraciones profundas o abiertas deben manejarse con SQL recursivo
  • Las tablas en sí no son inherentemente vértices o aristas; en cada grafo se puede decidir si leer sus filas como vértices, aristas o ambas cosas
  • Si se quiere consultar patrones de grafo fijos sobre un esquema existente en Postgres 19, conviene evaluar CREATE PROPERTY GRAPH y MATCH antes de mover los datos a una base de datos de grafos separada
  • Para explorar profundidades desconocidas se necesitan CTE recursivas, pero independientemente del enfoque los datos no tienen por qué salir de Postgres
  • Antes de adoptarlo en la práctica, hay que probar directamente si ofrece el rendimiento necesario

Aún no hay comentarios.

Aún no hay comentarios.