Escrita solo con funciones, una consulta ya no depende de los operadores. Spark y Flink difieren de PostgreSQL en otras tres cosas, y cada una pide un cambio. Ya definen algunos de los nombres que MobilityDB usa: ambos tienen round, lower y length, y Flink rechaza set y unnest sin comillas; tal nombre toma un prefijo que nombra la clase o el tipo base de su argumento (“Los nombres que poseen los motores”). Nunca llaman por usted a la función de entrada o de salida de un tipo, por lo que un literal, una conversión y el texto de un valor se convierten en llamadas a funciones que la consulta escribe (“Lectura y escritura de valores”). Y cada motor llama a su manera a una función que devuelve filas (“Funciones que devuelven filas”). La tabla siguiente resume estos cambios; una función que no lista 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 ya define toma el prefijo de la clase o del tipo base de su argumento, y las funciones que van juntas toman el mismo prefijo: spanLowerInc va con spanLower, geoCumulativeLength con geoLength. Spark y Flink usan los mismos nombres, por lo que una consulta escrita para uno se ejecuta en el otro, y round(1.23456, 2) sigue significando 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 | |
| width, height, bandPixelType, bandHasNoDataValue, bandNoDataValue, pixels, asHexWKB, stbox | raster; raquet | rasterWidth, rasterHeight, rasterBandPixelType, rasterBandHasNoDataValue, rasterBandNoDataValue, rasterPixels, rasterAsHexWKB, rasterStbox; raquetWidth, raquetHeight, raquetBandPixelType, raquetBandHasNoDataValue, raquetBandNoDataValue, raquetPixels, raquetAsHexWKB, raquetStbox |
| length, cumulativeLength | geometría, geografía, tgeompoint, tgeogpoint, trgeometry | geoLength, geoCumulativeLength |
| tnpoint | npointLength, npointCumulativeLength | |
| contains, covers, disjoint, intersects, touches, dwithin, relate | geometría, geografía | geoContains, geoCovers, geoDisjoint, geoIntersects, geoTouches, geoDwithin, geoRelate |
| reverse | geometría | geoReverse |
| collect | geometría[] | geoCollect |
| transform | geometría, geografía | geoTransform |
| 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 |
| tMin, tMax, merge, appendInstant, appendSequence, tAnd, tOr (los agregados) | temporal | tMinAgg, tMaxAgg, mergeAgg, appendInstantAgg, appendSequenceAgg, tAndAgg, tOrAgg |
| setUnion, spanUnion, spansetUnion (los agregados) | valor base, conjunto, rango, conjunto de rangos | setUnionAgg, spanUnionAgg, spansetUnionAgg |
| sameAlignment (el agregado) | raster | sameAlignmentAgg |
| wAvg (el agregado) | tint, tbigint, tfloat | wAvgAgg |
| jsonbSet, jsonbSetLax | jsonb | pgJsonbSet, pgJsonbSetLax |
| unnest | conjunto, temporal | setUnnest, temporalUnnest |
| set (el constructor) | cualquiera | setMake |
Las funciones jsonbSet y jsonbSetLax toman el prefijo pg de PostgreSQL, que las proporciona, ya que Spark y Flink, que ignoran las mayúsculas de un nombre, leerían jsonbSet como jsonbset, la conversión de un textset en un jsonbset.
Los nombres que comparten un raster y un raquet también toman el prefijo de su tipo, aunque el motor no defina ese nombre: ambos viajan como WKB, por lo que un motor con una sola función por nombre no distingue un raster dado a width de un raquet.
PostgreSQL lee y escribe un valor mediante las cuatro funciones que declara su tipo, y las llama por usted: un literal tipado, una conversión desde texto y un COPY de texto pasan por la función de entrada, el texto que muestra 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 a ninguna de ellas. Un valor viaja entre ellos como sus bytes Well-Known Binary (WKB), y cada conversión es una función que la consulta llama, cada una con su inversa, 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) |
Cada tipo tiene las funciones de la tabla que se le aplican: las formas E cuando lleva un SRID que sus formas de texto y binaria simples omiten, y MF-JSON cuando es temporal. Esto incluye los tipos que PostgreSQL lee y escribe solo mediante sus cuatro funciones: los tipos de conjunto, rango y 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.
El texto de un raquet es su WKB hexadecimal, por lo que se lee con raquetFromHexWKB y se escribe con asHexWKB, como un ráster de PostGIS con ST_RastFromHexWKB y ST_AsHexWKB. Una caja, stbox o tpcbox, escribe su SRID tanto en su texto como en su WKB, y no tiene por ello forma E. Toda salida WKB toma el orden de bytes endian, y toda salida de texto de un valor con flotantes o coordenadas el número de dígitos decimales maxdecimaldigits. Una columna de bytes WKB, como una columna TemporalParquet, se lee en todos los motores con el constructor binario de su tipo, como en tgeompointFromBinary(col).
Una función que devuelve varias filas, como timeSplit o unnest, se llama en PostgreSQL como una tabla en la cláusula FROM. En Spark y Flink la misma función, unnest bajo los nombres setUnnest y temporalUnnest, devuelve un arreglo con un elemento por fila, un arreglo de registros cuando devuelve varias columnas. Flink convierte el arreglo 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))'));
Aquí round se aplica a un número, por lo que es la función propia del motor y conserva su nombre.