Las funciones con nombre hacen una consulta independiente de los operadores. Spark y Flink piden tres cambios más, porque difieren de PostgreSQL de tres maneras. Ya poseen algunos de los nombres que MobilityDB usa: ambos definen round, lower y length, y el analizador sintáctico de Flink rechaza set y unnest sin comillas; tal nombre lleva un prefijo que designa la clase o el tipo base de su argumento (“Los nombres que poseen los motores”). No llaman implícitamente ninguna función de entrada o salida de un tipo, de modo que un literal, una conversión y el texto de un valor se vuelven llamadas que la consulta nombra (“Lectura y escritura de valores”). Y cada motor llama a una función que devuelve filas a su manera (“Funciones que devuelven filas”). La tabla siguiente resume los cambios; una función que no cubre conserva su nombre.
| Lo que contiene la consulta | MobilityDB | Spark y Flink |
|---|---|---|
| Un operador: su función con nombre, como la dan las secciones anteriores | trip && box | stboxOverlaps(trip, box) |
| Un nombre que el motor ya posee, sobre un valor cuyo tipo base tiene la operación: el tipo base delante | round(speed(trip), 2) | floatRound(speed(trip), 2) |
| Un nombre que el motor ya posee, sobre otro valor conjunto, rango, conjunto de rangos o temporal: la clase delante | lower(timeSpan(trip)) | spanLower(timeSpan(trip)) |
| Un nombre que el motor ya posee, sobre un cuadro delimitador o un tipo base: el tipo delante | round(box, 2) | stboxRound(box, 2) |
| Un literal con tipo: el constructor de texto de su tipo | tint '1@2001-01-01' | tintFromText('1@2001-01-01') |
| El texto de un valor, que PostgreSQL escribe mediante la función de salida de su tipo: asText | SELECT speed(trip) | SELECT asText(speed(trip)) |
| Una conversión: la función que su entrada da a su lado, como tbool::tint es tint(tbool) | flag::tint | tint(flag) |
Un nombre que el motor posee lleva el prefijo de la clase o del tipo base de su argumento, y las funciones que van juntas llevan el mismo prefijo: spanLowerInc va con spanLower, geoCumulativeLength con geoLength. Spark y Flink llevan un único conjunto de nombres: cada uno registra tal función solo bajo su nombre con prefijo, de modo que una consulta escrita para uno se ejecuta en el otro, y round(1.23456, 2) sigue siendo el redondeo propio del motor de un número. Los nombres que cambian son los siguientes.
| Nombre en MobilityDB | Clase del argumento | Nombre en Spark y Flink |
|---|---|---|
| lower, upper, initcap | textset, ttext | textLower, textUpper, textInitcap |
| lower, upper, lowerInc, upperInc | rango, conjunto de rangos | spanLower, spanUpper, spanLowerInc, spanUpperInc, spansetLower, spansetUpper, spansetLowerInc, spansetUpperInc |
| lowerInc, upperInc | temporal | temporalLowerInc, temporalUpperInc |
| round | float y sus tipos conjunto, rango, conjunto de rangos y temporal | floatRound |
| geometría y geografía, sus conjuntos y tipos temporales, trgeometry | geoRound | |
| cbuffer, cbufferset, tcbuffer; npoint, npointset, tnpoint; nsegment; pose, poseset, tpose; posechain, posechainset, tposechain; tbox; stbox; tpcbox | cbufferRound, npointRound, nsegmentRound, poseRound, posechainRound, tboxRound, stboxRound, tpcboxRound | |
| abs | tint, tbigint, tfloat | intAbs, bigintAbs, floatAbs |
| ceil, floor, degrees, radians, cos, sin, tan, exp, ln, log10 | float y sus tipos conjunto, rango, conjunto de rangos y temporal | floatCeil, floatFloor, floatDegrees, floatRadians, floatCos, floatSin, floatTan, floatExp, floatLn, floatLog10 |
| transform | los conjuntos y tipos temporales de geometría y geografía, trgeometry | geoTransform |
| transformPipeline | geometría y geografía, sus conjuntos y tipos temporales, trgeometry | geoTransformPipeline |
| cbuffer, cbufferset, tcbuffer; pose, poseset, tpose; posechain, posechainset, tposechain; stbox; raster | cbufferTransform, poseTransform, posechainTransform, stboxTransform, rasterTransform, y el …TransformPipeline de cada uno | |
| translate, affine, rotate, rotateX, rotateY, rotateZ, scale, transscale | geometry, tgeompoint, tgeometry | geoTranslate, geoAffine, geoRotate, geoRotateX, geoRotateY, geoRotateZ, geoScale, geoTransscale |
| translate, rotate, rotateX, rotateY, rotateZ | tcbuffer; tpose; tposechain | cbufferTranslate, cbufferRotate, cbufferRotateZ; poseTranslate, poseRotate, poseRotateX, poseRotateY, poseRotateZ; lo mismo para posechain (posechainTranslate, …) |
| trgeometry | geoTranslate, geoRotate, geoRotateX, geoRotateY, geoRotateZ | |
| length, cumulativeLength | geometría, geografía, tgeompoint, tgeogpoint, trgeometry | geoLength, geoCumulativeLength |
| tnpoint | npointLength, npointCumulativeLength | |
| hash, hashExtended | conjunto, rango, conjunto de rangos, cuadro delimitador, temporal, tipo base | setHash, spanHash, spansetHash, tboxHash, stboxHash, temporalHash, cbufferHash, …, y sus …HashExtended |
| insert, update, merge | temporal | temporalInsert, temporalUpdate, temporalMerge |
| merge (el agregado) | temporal | mergeAgg |
| unnest | conjunto, temporal | setUnnest, temporalUnnest |
| set (el constructor) | cualquiera | setMake |
PostgreSQL lee y escribe un valor mediante las cuatro funciones que declara su tipo, y las llama implícitamente: un literal con tipo, una conversión desde texto y un COPY de texto pasan por la función de entrada, el texto que imprime un cliente por la función de salida, y un COPY binario o un controlador en modo binario por las funciones de recepción y envío. Spark y Flink no llaman ninguna de ellas: un valor viaja como sus bytes WKB, y cada dirección es una función que la consulta nombra, la inversa de otra, como muestra la tabla siguiente.
| Lo que usa PostgreSQL | Dirección | Spark y Flink |
|---|---|---|
| la función de entrada: un literal con tipo, una conversión desde texto | texto a valor | ttypeFromText(text), settypeFromText(text), boxFromText(text), …, una por tipo, con el nombre del tipo como prefijo; con un SRID también tspatialFromEWKT(text) |
| la función de salida: el texto que imprime un cliente | valor a texto | asText(value); con un SRID también asEWKT(value) |
| la función de recepción: COPY binario, un controlador binario | binario a valor | ttypeFromBinary(bytea), ttypeFromHexWKB(text), y lo mismo para todo otro tipo; con un SRID también tspatialFromEWKB(bytea), tspatialFromHexEWKB(text) |
| la función de envío | valor a binario | asBinary(value), asHexWKB(value); con un SRID también asEWKB(value), asHexEWKB(value) |
| ninguna | MF-JSON | ttypeFromMFJSON(text), asMFJSON(ttype) |
Todo tipo tiene cada par que puede expresar, las formas E cuando sus formas de texto y binaria omiten el SRID que lleva y MF-JSON cuando es temporal, incluidos los tipos que PostgreSQL lee y escribe solo mediante sus cuatro funciones: los tipos de conjunto, de rango y de conjunto de rangos de enteros, enteros grandes, flotantes, fechas y marcas de tiempo, textset y jsonbset, tbox y stbox, tbool, tint, tbigint, tfloat y ttext, y quadbin, s2cell, nsegment y tpcbox. Un tipo cuyo texto es su WKB hexadecimal, raquet, lee y escribe su texto mediante raquetFromHexWKB y asHexWKB, como un ráster de PostGIS mediante ST_RastFromHexWKB y ST_AsHexWKB. Una caja, stbox o tpcbox, escribe su SRID en su texto y en su WKB, por lo que no necesita formas E. Toda salida WKB acepta el orden de bytes endian, y toda salida de texto de un valor con números flotantes o coordenadas la precisión maxdecimaldigits. Una columna de bytes WKB, por ejemplo una columna TemporalParquet, entra así en todos los motores por el constructor binario de su tipo, como en tgeompointFromBinary(col).
Una función que devuelve un conjunto de filas, como timeSplit o unnest, se llama como función de tabla en la cláusula FROM en PostgreSQL. En Flink y en Spark la misma función, unnest bajo los nombres setUnnest y temporalUnnest, devuelve un arreglo, un elemento por fila, un arreglo de registros cuando devuelve varias columnas; Flink lo despliega en filas con CROSS JOIN UNNEST, y Spark con LATERAL VIEW explode, o inline para un arreglo de registros.
La consulta
SELECT vehicle, round(length(trip)::numeric, 1), lower(timeSpan(trip)) FROM Trips WHERE trip && stbox 'SRID=3857;STBOX X((0,0),(1000,1000))';
se escribe, en Spark y Flink,
SELECT vehicle, round(geoLength(trip), 1), spanLower(timeSpan(trip))
FROM Trips
WHERE stboxOverlaps(trip, stboxFromText('SRID=3857;STBOX X((0,0),(1000,1000))'));
donde round del número resultante es el del propio motor.