Ejecución de una consulta en Apache Spark y Apache Flink

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 consultaMobilityDBSpark y Flink
Un operador: su función con nombre, como la dan las secciones anteriorestrip && boxstboxOverlaps(trip, box)
Un nombre que el motor ya posee, sobre un valor cuyo tipo base tiene la operación: el tipo base delanteround(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 delantelower(timeSpan(trip))spanLower(timeSpan(trip))
Un nombre que el motor ya posee, sobre un cuadro delimitador o un tipo base: el tipo delanteround(box, 2)stboxRound(box, 2)
Un literal con tipo: el constructor de texto de su tipotint '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: asTextSELECT 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::tinttint(flag)

Los nombres que poseen los motores

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 MobilityDBClase del argumentoNombre en Spark y Flink
lower, upper, initcaptextset, ttexttextLower, textUpper, textInitcap
lower, upper, lowerInc, upperIncrango, conjunto de rangosspanLower, spanUpper, spanLowerInc, spanUpperInc, spansetLower, spansetUpper, spansetLowerInc, spansetUpperInc
lowerInc, upperInctemporaltemporalLowerInc, temporalUpperInc
roundfloat y sus tipos conjunto, rango, conjunto de rangos y temporalfloatRound
 geometría y geografía, sus conjuntos y tipos temporales, trgeometrygeoRound
 cbuffer, cbufferset, tcbuffer; npoint, npointset, tnpoint; nsegment; pose, poseset, tpose; posechain, posechainset, tposechain; tbox; stbox; tpcboxcbufferRound, npointRound, nsegmentRound, poseRound, posechainRound, tboxRound, stboxRound, tpcboxRound
abstint, tbigint, tfloatintAbs, bigintAbs, floatAbs
ceil, floor, degrees, radians, cos, sin, tan, exp, ln, log10float y sus tipos conjunto, rango, conjunto de rangos y temporalfloatCeil, floatFloor, floatDegrees, floatRadians, floatCos, floatSin, floatTan, floatExp, floatLn, floatLog10
transformlos conjuntos y tipos temporales de geometría y geografía, trgeometrygeoTransform
transformPipelinegeometría y geografía, sus conjuntos y tipos temporales, trgeometrygeoTransformPipeline
 cbuffer, cbufferset, tcbuffer; pose, poseset, tpose; posechain, posechainset, tposechain; stbox; rastercbufferTransform, poseTransform, posechainTransform, stboxTransform, rasterTransform, y el …TransformPipeline de cada uno
translate, affine, rotate, rotateX, rotateY, rotateZ, scale, transscalegeometry, tgeompoint, tgeometrygeoTranslate, geoAffine, geoRotate, geoRotateX, geoRotateY, geoRotateZ, geoScale, geoTransscale
translate, rotate, rotateX, rotateY, rotateZtcbuffer; tpose; tposechaincbufferTranslate, cbufferRotate, cbufferRotateZ; poseTranslate, poseRotate, poseRotateX, poseRotateY, poseRotateZ; lo mismo para posechain (posechainTranslate, …)
 trgeometrygeoTranslate, geoRotate, geoRotateX, geoRotateY, geoRotateZ
width, height, bandPixelType, bandHasNoDataValue, bandNoDataValue, pixels, asHexWKB, stboxraster; raquetrasterWidth, rasterHeight, rasterBandPixelType, rasterBandHasNoDataValue, rasterBandNoDataValue, rasterPixels, rasterAsHexWKB, rasterStbox; raquetWidth, raquetHeight, raquetBandPixelType, raquetBandHasNoDataValue, raquetBandNoDataValue, raquetPixels, raquetAsHexWKB, raquetStbox
length, cumulativeLengthgeometría, geografía, tgeompoint, tgeogpoint, trgeometrygeoLength, geoCumulativeLength
 tnpointnpointLength, npointCumulativeLength
contains, covers, disjoint, intersects, touches, dwithin, relategeometría, geografíageoContains, geoCovers, geoDisjoint, geoIntersects, geoTouches, geoDwithin, geoRelate
reversegeometríageoReverse
collectgeometría[]geoCollect
transformgeometría, geografíageoTransform
hash, hashExtendedconjunto, rango, conjunto de rangos, cuadro delimitador, temporal, tipo basesetHash, spanHash, spansetHash, tboxHash, stboxHash, temporalHash, cbufferHash, …, y sus …HashExtended
insert, update, mergetemporaltemporalInsert, temporalUpdate, temporalMerge
tMin, tMax, merge, appendInstant, appendSequence, tAnd, tOr (los agregados)temporaltMinAgg, tMaxAgg, mergeAgg, appendInstantAgg, appendSequenceAgg, tAndAgg, tOrAgg
setUnion, spanUnion, spansetUnion (los agregados)valor base, conjunto, rango, conjunto de rangossetUnionAgg, spanUnionAgg, spansetUnionAgg
sameAlignment (el agregado)rastersameAlignmentAgg
wAvg (el agregado)tint, tbigint, tfloatwAvgAgg
jsonbSet, jsonbSetLaxjsonbpgJsonbSet, pgJsonbSetLax
unnestconjunto, temporalsetUnnest, temporalUnnest
set (el constructor)cualquierasetMake

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.

Lectura y escritura de valores

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 PostgreSQLDirecciónSpark y Flink
la función de entrada: un literal con tipo, una conversión desde textotexto a valorttypeFromText(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 clientevalor a textoasText(value); con un SRID también asEWKT(value)
la función de recepción: COPY binario, un controlador binariobinario a valorttypeFromBinary(bytea), ttypeFromHexWKB(text), y lo mismo para todo otro tipo; con un SRID también tspatialFromEWKB(bytea), tspatialFromHexEWKB(text)
la función de envíovalor a binarioasBinary(value), asHexWKB(value); con un SRID también asEWKB(value), asHexEWKB(value)
ningunaMF-JSONttypeFromMFJSON(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).

Funciones que devuelven filas

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.

Ejemplo

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.