Funciones de agregación definidas por el usuario

Para obtener asistencia durante la vista previa, envía un correo electrónico a [email protected].

En este documento, se describe cómo crear, llamar y borrar funciones de agregación definidas por el usuario (UDAF) en BigQuery.

Una UDAF te permite crear una función agregada mediante una expresión que contiene código. Una UDAF acepta columnas de entrada, realiza un cálculo en un grupo de filas a la vez y, luego, muestra el resultado de ese cálculo como un valor único.

Crea una UDAF de SQL

En esta sección, se describen las diversas formas en que puedes crear una UDAF de SQL persistente o temporal en BigQuery.

Crea una UDAF de SQL persistente

Puedes crear un UDAF de SQL que sea persistente, lo que significa que puedes reutilizar la UDAF en varias consultas. Es seguro llamar a las UDAF persistentes cuando se comparten entre propietarios. Las UDAF no pueden mutar datos, comunicarse con sistemas externos ni enviar registros a la observabilidad de Google Cloud o a aplicaciones similares.

Para crear un UDAF persistente, usa la declaración CREATE AGGREGATE FUNCTION sin la palabra clave TEMP o TEMPORARY. Debes incluir el conjunto de datos en la ruta de la función.

Por ejemplo, la siguiente consulta crea una UDAF persistente que se llama ScaledAverage:

CREATE AGGREGATE FUNCTION myproject.mydataset.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  AVG(dividend / divisor)
);

Crea una UDAF de SQL temporal

Puedes crear una UDAF de SQL que sea temporal, lo que significa que la UDAF solo existe dentro del alcance de una sola consulta, secuencia de comandos, sesión o procedimiento.

Para crear un UDAF temporal, usa la declaración CREATE AGGREGATE FUNCTION con la palabra clave TEMP o TEMPORARY.

Por ejemplo, la siguiente consulta crea una UDAF temporal que se llama ScaledAverage:

CREATE TEMP AGGREGATE FUNCTION ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  AVG(dividend / divisor)
);

Usa parámetros agregados y no agregados

Puedes crear una UDAF de SQL que tenga parámetros agregados y no agregados.

Por lo general, las UDAF agregan parámetros de función en todas las filas de un grupo. Sin embargo, puedes especificar un parámetro de función como no agregado con la palabra clave NOT AGGREGATE.

Un parámetro de función sin agregación es un parámetro de función escalar con un valor constante para todas las filas de un grupo. Un parámetro de función sin agregación válido debe ser un literal. Dentro de la definición de UDAF, los parámetros de funciones de agregación solo pueden aparecer como argumentos de funciones para agregar llamadas a funciones. Las referencias a parámetros de funciones no agregadas pueden aparecer en cualquier parte de la definición de la UDAF.

Por ejemplo, la siguiente función contiene un parámetro agregado llamado dividend y un parámetro no agregado llamado divisor:

-- Create the function.
CREATE TEMP AGGREGATE FUNCTION ScaledSum(
  dividend FLOAT64,
  divisor FLOAT64 NOT AGGREGATE)
RETURNS FLOAT64
AS (
  SUM(dividend) / divisor
);

Usa el proyecto predeterminado en el cuerpo de la función

En el cuerpo de una UDAF de SQL, cualquier referencia a entidades de BigQuery, como tablas o vistas, debe incluir el ID del proyecto, a menos que la entidad resida en el mismo proyecto que contiene la UDAF.

Por ejemplo, considera la siguiente declaración:

CREATE AGGREGATE FUNCTION project1.dataset_a.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  ( SELECT AVG(dividend / divisor) FROM dataset_a.my_table )
);

Si ejecutas la instrucción anterior en el proyecto project1, la declaración tiene éxito porque my_table existe en project1. Sin embargo, si ejecutas la instrucción anterior desde un proyecto diferente, la instrucción fallará. Para corregir el error, incluye el ID del proyecto en la referencia de la tabla:

CREATE AGGREGATE FUNCTION project1.dataset_a.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  ( SELECT AVG(dividend / divisor) FROM project1.dataset_a.my_table )
);

También puedes hacer referencia a una entidad en un proyecto o conjunto de datos diferente del que creaste la función:

CREATE AGGREGATE FUNCTION project1.dataset_a.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  ( SELECT AVG(dividend / divisor) FROM project2.dataset_c.my_table )
);

Crea una UDAF de JavaScript

En esta sección, se describen las diversas formas en las que puedes crear una UDAF de JavaScript en BigQuery. Debes tener en cuenta algunas reglas cuando se crea una UDAF de JavaScript:

  • El cuerpo de la UDAF de JavaScript debe ser un literal de cadena entre comillas que represente el código de JavaScript. Para obtener más información acerca de los diferentes tipos de literales de cadena entre comillas que puedes usar, consulta Formatos para literales entrecomillados.

  • Solo se permiten ciertas codificaciones de tipos. Para obtener más información, consulta Codificaciones de tipos de SQL permitidas en una UDAF de JavaScript.

  • El cuerpo de la función de JavaScript debe incluir cuatro funciones de JavaScript que inicializan, agregan, combinan y finalizan los resultados de la UDAF de JavaScript (initialState, aggregate, merge yfinalize). Para obtener más información, consulta Codificaciones de tipos de SQL permitidas en una UDAF de JavaScript.

  • Cualquier valor que muestre la función initialState o que quede en el argumento state después de que se llame a la función aggregate o merge debe ser serializable. Si deseas trabajar con datos de agregación no serializables, como funciones o campos de símbolos, debes usar las funciones serialize y deserialize incluidas. Para obtener más información, consulta Serializa y deserializa datos en una UDAF de JavaScript.

Crea una UDAF de JavaScript persistente

Puedes crear una UDAF de SQL que sea persistente, lo que significa que puedes reutilizar la UDAF en varias consultas. Es seguro llamar a las UDAF persistentes cuando se comparten entre propietarios. Las UDAF no pueden mutar datos, comunicarse con sistemas externos ni enviar registros a la observabilidad de Google Cloud o a aplicaciones similares.

Para crear una UDAF persistente, usa la declaración CREATE AGGREGATE FUNCTION sin la palabra clave TEMP o TEMPORARY. Debes incluir el conjunto de datos en la ruta de la función.

En la siguiente consulta, se crea una UDAF de JavaScript persistente que se llama SumPositive:

CREATE OR REPLACE AGGREGATE FUNCTION my_project.my_dataset.SumPositive(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  export function initialState() {
    return {sum: 0}
  }
  export function aggregate(state, x) {
    if (x > 0) {
      state.sum += x;
    }
  }
  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }
  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([1.0, -1.0, 3.0, -3.0, 5.0, -5.0]) AS x)
SELECT my_project.my_dataset.SumPositive(x) AS sum FROM numbers;

/*-----*
 | sum |
 +-----+
 | 9.0 |
 *-----*/

Crea una UDAF de JavaScript temporal

Puedes crear una UDAF de JavaScript que sea temporal, lo que significa que la UDAF solo existe dentro del alcance de una sola consulta, secuencia de comandos, sesión o procedimiento.

Para crear un UDAF temporal, usa la declaración CREATE AGGREGATE FUNCTION con la palabra clave TEMP o TEMPORARY.

En la siguiente consulta, se crea una UDAF de JavaScript temporal que se llama SumPositive:

CREATE TEMP AGGREGATE FUNCTION SumPositive(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  export function initialState() {
    return {sum: 0}
  }
  export function aggregate(state, x) {
    if (x > 0) {
      state.sum += x;
    }
  }
  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }
  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([1.0, -1.0, 3.0, -3.0, 5.0, -5.0]) AS x)
SELECT SumPositive(x) AS sum FROM numbers;

/*-----*
 | sum |
 +-----+
 | 9.0 |
 *-----*/

Incluye parámetros no agregados en una UDAF de JavaScript

Puedes crear una UDAF de JavaScript que tenga parámetros agregados y no agregados.

Por lo general, las UDAF agregan parámetros de función en todas las filas de un grupo. Sin embargo, puedes especificar un parámetro de función como no agregado con la palabra clave NOT AGGREGATE.

Un parámetro de función sin agregación es un parámetro de función escalar con un valor constante para todas las filas de un grupo. Un parámetro de función sin agregación válido debe ser un literal. Dentro de la definición de UDAF, los parámetros de funciones de agregación solo pueden aparecer como argumentos de funciones para agregar llamadas a funciones. Las referencias a parámetros de funciones no agregadas pueden aparecer en cualquier parte de la definición de la UDAF.

En el siguiente ejemplo, la UDAF de JavaScript contiene un parámetro agregado llamado s y un parámetro no agregado llamado delimiter:

CREATE TEMP AGGREGATE FUNCTION JsStringAgg(
  s STRING,
  delimiter STRING NOT AGGREGATE)
RETURNS STRING
LANGUAGE js
AS r'''

  export function initialState() {
    return {strings: []}
  }
  export function aggregate(state, s) {
    state.strings.push(s);
  }
  export function merge(state, partialState) {
    state.strings = state.strings.concat(partialState.strings);
  }
  export function finalize(state, delimiter) {
    return state.strings.join(delimiter);
  }

''';

-- Call the JavaScript UDAF.
WITH strings AS (
  SELECT * FROM UNNEST(["aaa", "bbb", "ccc", "ddd"]) AS values)
SELECT JsStringAgg(values, '.') AS result FROM strings;

/*-----------------*
 | result          |
 +-----------------+
 | aaa.bbb.ccc.ddd |
 *-----------------*/

Serializa y deserializa datos en una UDAF de JavaScript

BigQuery debe serializar cualquier objeto que muestre la función initialState o que quede en el argumento state después de que se llame a la función aggregate o merge. BigQuery admite la serialización de un objeto si todos los campos son uno de los siguientes:

  • Un valor básico de JavaScript (por ejemplo: 2, "abc", null, undefined).
  • Un objeto de JavaScript para el que BigQuery admite la serialización de todos los valores de campo.
  • Un array de JavaScript para el que BigQuery admite la serialización de todos los elementos.

Los siguientes valores de retorno son serializables:

export function initialState() {
  return {a: "", b: 3, c: null, d: {x: 23} }
}
export function initialState() {
  return {value: 2.3};
}

Los siguientes valores de retorno no se pueden serializar:

export function initialState() {
  return {
    value: function() {return 6;}
  }
}
export function initialState() {
  return 2.3;
}

Si deseas trabajar con estados de agregación no serializables, la UDAF de JavaScript debe incluir las funciones serialize y deserialize. La función serialize convierte el estado de agregación en un objeto serializable. La función deserialize vuelve a convertir el objeto serializable en un estado de agregación.

En el siguiente ejemplo, una biblioteca externa calcula las sumas a través de una interfaz:

export class SumAggregator {
 constructor() {
   this.sum = 0;
 }
 update(value) {
   this.sum += value;
 }
 getSum() {
   return this.sum;
 }
}

La siguiente consulta no se ejecuta porque el objeto de clase SumAggregator no se puede serializar con BigQuery debido a la presencia de funciones dentro de la clase.

CREATE TEMP AGGREGATE FUNCTION F(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  class SumAggregator {
   constructor() {
     this.sum = 0;
   }

   update(value) {
     this.sum += value;
   }

   getSum() {
     return this.sum;
   }
  }

  export function initialState() {
   return new SumAggregator();
  }

  export function aggregate(agg, value) {
   agg.update(value);
  }

  export function merge(agg1, agg2) {
   agg1.update(agg2.getSum());
  }

  export function finalize(agg) {
   return agg.getSum();
  }

''';

--Error: getSum is not a function
SELECT F(x) AS results FROM UNNEST([1,2,3,4]) AS x;

Si agregas las funciones serialize y deserialize a la consulta anterior, la consulta se ejecuta porque el objeto de clase SumAggregator se convierte en un objeto que se puede serializar con BigQuery y, luego, de nuevo en un objeto de clase SumAggregator.

CREATE TEMP AGGREGATE FUNCTION F(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  class SumAggregator {
   constructor() {
     this.sum = 0;
   }

   update(value) {
     this.sum += value;
   }

   getSum() {
     return this.sum;
   }
  }

  export function initialState() {
   return new SumAggregator();
  }

  export function aggregate(agg, value) {
   agg.update(value);
  }

  export function merge(agg1, agg2) {
   agg1.update(agg2.getSum());
  }

  export function finalize(agg) {
   return agg.getSum();
  }

  export function serialize(agg) {
   return {sum: agg.getSum()};
  }

  export function deserialize(serialized) {
   var agg = new SumAggregator();
   agg.update(serialized.sum);
   return agg;
  }

''';

SELECT F(x) AS results FROM UNNEST([1,2,3,4]) AS x;

/*-----------------*
 | results         |
 +-----------------+
 | 10.0            |
 *-----------------*/

Para obtener más información acerca de las funciones de serialización, consulta Funciones opcionales de serialización de JavaScript.

Incluye variables globales y funciones personalizadas en una UDAF de JavaScript

El cuerpo de la función de JavaScript puede incluir código de JavaScript personalizado, como variables globales de JavaScript y funciones personalizadas.

Las variables globales se ejecutan cuando se carga JavaScript en BigQuery y antes de que se ejecute la función initialState. Las variables globales pueden ser útiles si necesitas realizar un trabajo de inicialización único que no debe repetirse para cada grupo de agregación, como sería el caso con las funciones initialState, aggregate, merge y finalize.

No uses variables globales para almacenar el estado de agregación. En su lugar, limita el estado de agregación a los objetos que se pasan a las funciones exportadas. Usa variables globales solo para almacenar en caché las operaciones costosas que no son específicas de ninguna operación de agregación en particular.

En la siguiente consulta, la función SumOfPrimes calcula una suma, pero solo se incluyen números primos en el cálculo. En el cuerpo de la función de JavaScript, hay dos variables globales, primes y maxTested, que se inicializan primero. Además, hay una función personalizada llamada isPrime que verifica si un número es primo.

CREATE TEMP AGGREGATE FUNCTION SumOfPrimes(x INT64)
RETURNS INT64
LANGUAGE js
AS r'''

  var primes = new Set([2]);
  var maxTested = 2;

  function isPrime(n) {
    if (primes.has(n)) {
      return true;
    }
    if (n <= maxTested) {
      return false;
    }
    for (var k = 2; k < n; ++k) {
      if (!isPrime(k)) {
        continue;
      }
      if ((n % k) == 0) {
        maxTested = n;
        return false;
      }
    }
    maxTested = n;
    primes.add(n);
    return true;
  }

  export function initialState() {
    return {sum: 0};
  }

  export function aggregate(state, x) {
    x = Number(x);
    if (isPrime(x)) {
      state.sum += x;
    }
  }

  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }

  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([10, 11, 13, 17, 19, 20]) AS x)
SELECT SumOfPrimes(x) AS sum FROM numbers;

/*-----*
 | sum |
 +-----+
 | 60  |
 *-----*/

Incluye bibliotecas de JavaScript

Puedes extender tus UDAF de JavaScript con la opción library en la cláusula OPTIONS. Esta opción te permite especificar bibliotecas de código externas para la UDAF de JavaScript y, luego, importar esas bibliotecas con la declaración import.

En el siguiente ejemplo, el código en bar.js está disponible para cualquier código en el cuerpo de la función de la UDAF de JavaScript:

CREATE TEMP AGGREGATE FUNCTION JsAggFn(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
OPTIONS (library = ['gs://foo/bar.js'])
AS r'''

  import doInterestingStuff from 'bar.js';

  export function initialState() {
    return ...
  }
  export function aggregate(state, x) {
    var result = doInterestingStuff(x);
    ...
  }
  export function merge(state, partial_state) {
    ...
  }
  export function finalize(state) {
    return ...;
  }

''';

Estructura de JavaScript obligatoria

A diferencia de una UDF de JavaScript, en la que el cuerpo de la función es JavaScript de formato libre que se ejecuta para cada fila, el cuerpo de la función para una UDAF de JavaScript es un módulo de JavaScript que contiene algunas funciones integradas exportadas, que se invocan en varias etapas del proceso de agregación. Algunas de estas funciones integradas son obligatorias, mientras que otras son opcionales. También puedes agregar tus funciones de JavaScript.

Funciones de agregación de JavaScript obligatorias

Puedes incluir tus funciones de JavaScript, pero el cuerpo de la función debe incluir las siguientes funciones exportables de JavaScript:

  • initialState([nonAggregateParam]): muestra un objeto de JavaScript que representa un estado de agregación en el que aún no se agregaron filas.

  • aggregate(state, aggregateParam[, ...][, nonAggregateParam]): agrega una fila de datos, lo que actualiza el estado para almacenar el resultado de la agregación. No muestra un valor.

  • merge(state, partialState, [nonAggregateParam]): combina el estado de agregación partialState en el estado de agregación state. Esta función se usa cuando el motor agrega diferentes secciones de datos en paralelo y necesita combinar los resultados. No muestra un valor.

  • finalize(finalState, [nonAggregateParam]): muestra el resultado final de la función agregada, según un estado de agregación final finalState.

Para obtener más información acerca de las funciones obligatorias, consulta Funciones requeridas en una UDAF de JavaScript.

Funciones opcionales de serialización de JavaScript

Si deseas trabajar con estados de agregación no serializables, la UDAF de JavaScript debe proporcionar las funciones serialize y deserialize. La función serialize convierte el estado de agregación en un objeto que se puede serializar con BigQuery. La función deserialize vuelve a convertir el objeto que se puede serializar con BigQuery en un estado de agregación.

  • serialize(state): muestra un objeto serializable que contiene la información en el estado de agregación que se deserializará a través de la función deserialize.

  • deserialize(serializedState): deserializa serializedState (anteriormente serializado por la función serialize) en un estado de agregación que puede pasarse a las funciones serialize, aggregate, merge o finalize.

Para obtener más información acerca de las funciones de serialización de JavaScript integradas, consulta Funciones de serialización para una UDAF de JavaScript.

Para aprender a serializar y deserializar datos con una UDAF de JavaScript, consulta Serializa y deserializa datos en una UDAF de JavaScript.

Codificaciones de tipos de SQL permitidas en una UDAF de JavaScript

En las UDAF de JavaScript, los siguientes tipos de datos de GoogleSQL compatibles representan tipos de datos de JavaScript de la siguiente manera:

Tipo de datos
de GoogleSQL
Tipo de dato
de JavaScript
Notas
ARRAY Array No se admite un array de arrays. Para evitar esta limitación, usa los tipos de datos Array<Object<Array>> (JavaScript) y ARRAY<STRUCT<ARRAY>> (GoogleSQL).
BIGNUMERIC Number o String Igual que NUMERIC.
BOOL Boolean
BYTES Uint8Array
DATE Date
FLOAT64 Number
INT64 BigInt
JSON Varios tipos El tipo de datos JSON de GoogleSQL se puede convertir en un Object, Array o en otro tipo de datos de JavaScript compatible con GoogleSQL.
NUMERIC Number o String Si un valor NUMERIC se puede representar de forma exacta como un valor de punto flotante IEEE 754 (rango [-253, 253]) y no tiene una parte fraccionaria, se codifica como un tipo de datos Number; de lo contrario, se codifica como un tipo de datos String.
STRING String
STRUCT Object Cada campo STRUCT es una propiedad con nombre en el tipo de datos Object. No se admite un campo STRUCT sin nombre.
TIMESTAMP Date Date contiene un campo de microsegundos con la fracción de microsegundos de TIMESTAMP.

Llama a una UDAF

En esta sección, se describen las diversas formas en las que puedes llamar a una UDAF persistente o temporal después de crearla en BigQuery.

Llama a una UDAF persistente

Puedes llamar a una UDAF persistente de la misma manera que llamas a una función de agregación integrada. Para obtener más información, consulta Llamadas a funciones de agregación. Debes incluir el conjunto de datos en la ruta de la función.

En el siguiente ejemplo, la consulta llama a una UDAF persistente que se llama WeightedAverage:

SELECT my_project.my_dataset.WeightedAverage(item, weight, 2) AS weighted_average
FROM (
  SELECT 1 AS item, 2.45 AS weight UNION ALL
  SELECT 3 AS item, 0.11 AS weight UNION ALL
  SELECT 5 AS item, 7.02 AS weight
);

Se genera una tabla con los siguientes resultados:

/*------------------*
 | weighted_average |
 +------------------+
 | 4.5              |
 *------------------*/

Llama a una UDAF temporal

Puedes llamar a una UDAF temporal de la misma manera en que llamas a una función de agregación integrada. Para obtener más información, consulta Llamadas a funciones de agregación.

La función temporal debe incluirse en una consulta de varias instrucciones o un procedimiento que contenga la llamada a la función de UDAF.

En el siguiente ejemplo, la consulta llama a una UDAF temporal que se llama WeightedAverage:

CREATE TEMP AGGREGATE FUNCTION WeightedAverage(...)

-- Temporary UDAF function call
SELECT WeightedAverage(item, weight, 2) AS weighted_average
FROM (
  SELECT 1 AS item, 2.45 AS weight UNION ALL
  SELECT 3 AS item, 0.11 AS weight UNION ALL
  SELECT 5 AS item, 7.02 AS weight
);

Se genera una tabla con los siguientes resultados:

/*------------------*
 | weighted_average |
 +------------------+
 | 4.5              |
 *------------------*/

Ignora o incluye filas con valores NULL

Cuando se llama a una UDAF de JavaScript con el argumento IGNORE NULLS, BigQuery omite automáticamente las filas para las que cualquier argumento agregado se evalúa como NULL. Estas filas se excluyen por completo de la agregación y no se pasan a la función aggregate de JavaScript. Cuando se proporciona el argumento RESPECT NULLS, se inhabilita el filtrado de NULL y cada fila se pasa a la UDAF de JavaScript, sin importar los valores NULL.

Cuando no se proporcionan los argumentos IGNORE NULLS ni RESPECT NULLS, el argumento predeterminado es IGNORE NULLS.

En el siguiente ejemplo, se ilustran el comportamiento predeterminado NULL, el comportamiento IGNORE NULLS y el comportamiento RESPECT NULLS:

CREATE TEMP AGGREGATE FUNCTION SumPositive(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  export function initialState() {
    return {sum: 0}
  }
  export function aggregate(state, x) {
    if (x == null) {
      // Use 1000 instead of 0 as placeholder for null so
      // that NULL values passed are visible in the result.
      state.sum += 1000;
      return;
    }
    if (x > 0) {
      state.sum += x;
    }
  }
  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }
  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([1.0, 2.0, NULL]) AS x)
SELECT
  SumPositive(x) AS sum,
  SumPositive(x IGNORE NULLS) AS sum_ignore_nulls,
  SumPositive(x RESPECT NULLS) AS sum_respect_nulls
FROM numbers;

/*-----+------------------+-------------------*
 | sum | sum_ignore_nulls | sum_respect_nulls |
 +-----+------------------+-------------------+
 | 3.0 | 3.0              | 1003.0            |
 *-----+------------------+-------------------*/

Borra una UDAF

En esta sección, se describen las diversas formas en las que puedes borrar una UDAF persistente o temporal después de crearla en BigQuery.

Borra una UDAF persistente

Para borrar una UDAF, usa la declaración DROP FUNCTION. Debes incluir el conjunto de datos en la ruta de la función.

En el siguiente ejemplo, la consulta borra una UDAF persistente que se llama WeightedAverage:

DROP FUNCTION IF EXISTS my_project.my_dataset.WeightedAverage;

Borra una UDAF temporal

Para borrar una UDAF temporal, usa la declaración DROP FUNCTION.

En el siguiente ejemplo, la consulta borra una UDAF temporal que se llama WeightedAverage:

DROP FUNCTION IF EXISTS WeightedAverage;

Una UDAF temporal vence apenas finaliza la consulta y no es necesario borrar la UDAF, a menos que desees quitarla antes de un procedimiento o una consulta de varias instrucciones.

Enumera UDAF

Las UDAF son un tipo de rutina. Para enumerar todas las rutinas en un conjunto de datos, consulta Enumera rutinas.

Sugerencias para un mejor rendimiento

Si deseas mejorar el rendimiento de tus consultas, ten en cuenta lo siguiente:

  • Realiza un filtro previo a tu entrada. El procesamiento de datos en JavaScript es más costoso que en SQL, por lo que es mejor filtrar la entrada tanto como sea posible en SQL primero.

    La siguiente consulta es menos eficiente porque filtra la entrada a través de x > 0 en la llamada a la UDAF:

    SELECT JsFunc(x) FROM t;
    

    La siguiente consulta es más eficiente porque filtra previamente la entrada a través de WHERE x > 0 antes de que se llame a la UDAF:

    SELECT JsFunc(x) FROM t WHERE x > 0;
    
  • Usa funciones de agregación integradas en lugar de JavaScript cuando sea posible. Volver a implementar una función de agregación integrada en JavaScript es más lento que llamar a una función de agregación integrada que hace lo mismo.

    La siguiente consulta es menos eficiente porque implementa una UDAF:

    SELECT SumSquare(x) FROM t;
    

    La siguiente consulta es más eficiente porque implementa una función integrada que produce los mismos resultados que la consulta anterior:

    SELECT SUM(x*x) FROM t;
    
  • Las UDAF de JavaScript son apropiadas para operaciones de agregación más complejas, que no se pueden expresar a través de funciones integradas.

  • Usa la memoria de manera eficaz. El entorno de procesamiento de JavaScript tiene memoria limitada disponible para cada consulta. Las consultas de UDAF de JavaScript que acumulan demasiado estado local pueden fallar debido al agotamiento de la memoria. Ten mucho cuidado con la minimización del tamaño de los objetos de estado de agregación y evita los estados de agregación que acumulan una gran cantidad de filas.

    La siguiente consulta no es eficiente porque la función aggregate usa una cantidad de memoria no definida cuando la cantidad de filas procesadas es grande.

    export function initialState() {
      return {rows: []};
    }
    export function aggregate(state, x) {
      state.rows.push(x);
    }
    ...
    
  • Usa tablas particionadas cuando sea posible. Por lo general, las UDAF de JavaScript se ejecutan de manera más eficiente cuando se realizan consultas en una tabla particionada en comparación con una tabla no particionada, ya que una tabla particionada almacena datos en muchos archivos más pequeños en comparación con una tabla no particionada, lo que permite un mayor paralelismo.

Limitaciones

  • Las UDAF tienen las mismas limitciones que se aplican a las UDF. Para obtener más detalles, consulta las limitaciones de UDF.

  • Solo los literales, los parámetros de consulta y las variables de secuencia de comandos se pueden pasar como argumentos no agregados para una UDAF.

  • No se admite el uso de la cláusula ORDER BY en una llamada a función UDAF de JavaScript.

    SELECT MyUdaf(x ORDER BY y) FROM t; -- Error: ORDER BY is unsupported.
    

Precios

Las UDAF se facturan según el modelo estándar de precios de BigQuery.

Cuotas y límites

Las UDAF tienen las mismas cuotas y los mismos límites que se aplican a las UDF. Para obtener información sobre las cuotas de UDF, consulta Cuotas y límites.