Funções agregadas definidas pelo usuário

Para receber suporte durante a prévia, envie um e-mail para [email protected].

Neste documento, descrevemos como criar, chamar e excluir funções de agregação definidas pelo usuário (UDAFs, na sigla em inglês) no BigQuery.

Um UDAF permite criar uma função agregada usando uma expressão que contém código. Um UDAF aceita colunas de entrada, realiza um cálculo em um grupo de linhas por vez e, em seguida, retorna o resultado desse cálculo como um único valor.

Criar um UDAF SQL

Nesta seção, descrevemos as várias maneiras de criar um UDAF SQL permanente ou temporário no BigQuery.

Criar um UDAF SQL permanente

É possível criar um UDAF do SQL que seja persistente, o que significa que é possível reutilizar o UDAF em várias consultas. UDAFs persistentes podem ser chamados com segurança quando são compartilhados entre os proprietários. As UDAFs não podem modificar dados, se comunicar com sistemas externos ou enviar registros para a observabilidade do Google Cloud ou aplicativos semelhantes.

Para criar um UDAF persistente, use a instrução CREATE AGGREGATE FUNCTION sem a palavra-chave TEMP ou TEMPORARY. Você precisa incluir o conjunto de dados no caminho da função.

Por exemplo, a consulta a seguir cria um UDAF persistente chamado ScaledAverage:

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

Criar um UDAF SQL temporário

É possível criar um UDAF do SQL temporário, o que significa que ele existe apenas no escopo de uma única consulta, script, sessão ou procedimento.

Para criar um UDAF temporário, use a instrução CREATE AGGREGATE FUNCTION com a palavra-chave TEMP ou TEMPORARY.

Por exemplo, a consulta a seguir cria um UDAF temporário chamado ScaledAverage:

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

Usar parâmetros agregados e não agregados

É possível criar um UDAF SQL com parâmetros agregados e não agregados.

Os UDAFs normalmente agregam parâmetros de função em todas as linhas de um grupo. No entanto, você pode especificar um parâmetro de função como não agregado com a palavra-chave NOT AGGREGATE.

Um parâmetro de função não agregada é um parâmetro de função escalar com um valor constante para todas as linhas em um grupo. Um parâmetro de função não agregada válido precisa ser um literal. Na definição da UDAF, os parâmetros da função agregada só podem aparecer como argumentos de função para agregar chamadas de função. As referências a parâmetros de função não agregados podem aparecer em qualquer lugar na definição da UDAF.

Por exemplo, a função a seguir contém um parâmetro a gregado chamado dividend e um parâmetro não agregado chamado divisor:

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

Usar o projeto padrão no corpo da função

No corpo de uma UDAF em SQL, todas as referências a entidades do BigQuery, como tabelas ou visualizações, precisam incluir o ID do projeto, a menos que a entidade resida no mesmo projeto que contém a UDAF.

Por exemplo, considere a seguinte instrução:

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

Se você executar a instrução anterior no projeto project1, ela será bem-sucedida porque my_table existe em project1. No entanto, se você executar a instrução anterior de um projeto diferente, ela falhará. Para corrigir o erro, inclua o ID do projeto na referência da tabela:

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

Também é possível referenciar uma entidade em um projeto ou conjunto de dados diferente daquele em que a função é criada:

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

Criar um UDAF em JavaScript

Nesta seção, descrevemos as várias maneiras de criar um UDAF em JavaScript no BigQuery. Há algumas regras a serem observadas ao criar um UDAF em JavaScript:

  • O corpo do UDAF em JavaScript precisa ser um literal de string entre aspas que representa o código JavaScript. Para saber mais sobre os diferentes tipos de literais de string entre aspas que podem ser usados, consulte Formatos para literais entre aspas.

  • Apenas algumas codificações de tipo são permitidas. Para mais informações, consulte Codificações de tipo SQL permitidas em um UDAF em JavaScript.

  • O corpo da função JavaScript precisa incluir quatro funções JavaScript que inicializam, agregam, mesclam e finalizam os resultados do UDAF em JavaScript (initialState, aggregate, merge e finalize). Para mais informações, consulte Codificações de tipo SQL permitidas em um UDAF em JavaScript.

  • Qualquer valor retornado pela função initialState ou que seja deixado no argumento state depois que a função aggregate ou merge é chamada precisa ser serializável. Se você quiser trabalhar com dados de agregação não serializáveis, como funções ou campos de símbolo, use as funções serialize e deserialize incluídas. Para saber mais, consulte Serializar e desserializar dados em um UDAF em JavaScript.

Criar um UDAF JavaScript persistente

É possível criar um UDAF JavaScript que seja persistente, o que significa que é possível reutilizar o UDAF em várias consultas. UDAFs persistentes podem ser chamados com segurança quando são compartilhados entre os proprietários. As UDAFs não podem modificar dados, se comunicar com sistemas externos ou enviar registros para a observabilidade do Google Cloud ou aplicativos semelhantes.

Para criar um UDAF persistente, use a instrução CREATE AGGREGATE FUNCTION sem a palavra-chave TEMP ou TEMPORARY. Você precisa incluir o conjunto de dados no caminho da função.

A consulta a seguir cria um UDAF JavaScript persistente que é chamado de 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 |
 *-----*/

Criar um UDAF JavaScript temporário

É possível criar um UDAF JavaScript temporário, o que significa que ele existe apenas no escopo de uma única consulta, script, sessão ou procedimento.

Para criar um UDAF temporário, use a instrução CREATE AGGREGATE FUNCTION com a palavra-chave TEMP ou TEMPORARY.

A consulta a seguir cria um UDAF temporário em JavaScript chamado 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 |
 *-----*/

Incluir parâmetros não agregados em um UDAF JavaScript

É possível criar um UDAF JavaScript com parâmetros agregados e não agregados.

Os UDAFs normalmente agregam parâmetros de função em todas as linhas de um grupo. No entanto, você pode especificar um parâmetro de função como não agregado com a palavra-chave NOT AGGREGATE.

Um parâmetro de função não agregada é um parâmetro de função escalar com um valor constante para todas as linhas em um grupo. Um parâmetro de função não agregada válido precisa ser um literal. Na definição da UDAF, os parâmetros da função agregada só podem aparecer como argumentos de função para agregar chamadas de função. As referências a parâmetros de função não agregados podem aparecer em qualquer lugar na definição da UDAF.

No exemplo a seguir, o UDAF em JavaScript contém um parâmetro agregado chamado s e um parâmetro não agregado chamado 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 |
 *-----------------*/

Serializar e desserializar dados em um UDAF em JavaScript

O BigQuery precisa serializar qualquer objeto retornado pela função initialState ou que seja deixado no argumento state depois que a função aggregate ou merge é chamada. O BigQuery é compatível com a serialização de um objeto se todos os campos forem um dos seguintes:

  • Um valor primitivo de JavaScript (por exemplo: 2, "abc", null, undefined).
  • Um objeto JavaScript para o qual o BigQuery é compatível com a serialização de todos os valores de campo.
  • Uma matriz JavaScript para a qual o BigQuery é compatível com a serialização de todos os elementos.

Os seguintes valores de retorno são serializáveis:

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

Os seguintes valores de retorno não são serializáveis:

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

Se você quiser trabalhar com estados de agregação não serializáveis, a UDAF em JavaScript precisa incluir as funções serialize e deserialize. A função serialize converte o estado de agregação em um objeto serializável. a função deserialize converte o objeto serializável de volta a um estado de agregação.

No exemplo a seguir, uma biblioteca externa calcula somas usando uma interface:

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

A consulta a seguir não é executada porque o objeto da classe SumAggregator não é serializável pelo BigQuery devido à presença de funções dentro da classe.

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;

Se você adicionar as funções serialize e deserialize à consulta anterior, ela será executada porque o objeto de classe SumAggregator será convertido em um objeto serializável pelo BigQuery e, em seguida, de volta para um objeto de classe SumAggregator novamente.

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 saber mais sobre as funções de serialização, consulte Funções opcionais de serialização do JavaScript.

Incluir variáveis globais e funções personalizadas em um UDAF em JavaScript

O corpo da função JavaScript pode incluir código JavaScript personalizado, como variáveis globais JavaScript e funções personalizadas.

As variáveis globais são executadas quando o JavaScript é carregado no BigQuery e antes da função initialState ser executada. Variáveis globais podem ser úteis se você precisar realizar um trabalho de inicialização única que não precisa se repetir para cada grupo de agregação, como seria o caso com initialState, aggregate, merge e finalize.

Não use variáveis globais para armazenar o estado da agregação. Em vez disso, limite o estado de agregação aos objetos transmitidos para as funções exportadas. Use variáveis globais apenas para armazenar em cache operações caras que não sejam específicas de uma operação de agregação específica.

Na consulta a seguir, a função SumOfPrimes calcula uma soma, mas apenas números primos são incluídos no cálculo. No corpo da função JavaScript, há duas variáveis globais, primes e maxTested, que são inicializadas primeiro. Além disso, há uma função personalizada chamada isPrime que verifica se um número é 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  |
 *-----*/

Incluir bibliotecas JavaScript

É possível estender os UDAFs em JavaScript com a opção library na cláusula OPTIONS. Essa opção permite especificar bibliotecas de código externas para a UDAF em JavaScript e, em seguida, importá-las com a declaração import.

No exemplo a seguir, o código em bar.js está disponível para qualquer código no corpo da função do UDAF em 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 ...;
  }

''';

Estrutura JavaScript obrigatória

Ao contrário de uma UDF em JavaScript, em que o corpo da função é um JavaScript de formato livre executado em todas as linhas, o corpo de uma UDAF em JavaScript é um módulo JavaScript que contém algumas funções exportadas, como invocado em várias etapas do processo de agregação. Algumas dessas funções integradas são necessárias, enquanto outras são opcionais. Você também pode adicionar suas funções JavaScript.

Funções de agregação JavaScript necessárias

É possível incluir suas funções JavaScript, mas o corpo da função JavaScript precisa incluir as seguintes funções JavaScript exportáveis:

  • initialState([nonAggregateParam]): retorna um objeto JavaScript que representa um estado de agregação em que nenhuma linha foi agregada ainda.

  • aggregate(state, aggregateParam[, ...][, nonAggregateParam]): agrega uma linha de dados, atualizando o estado para armazenar o resultado da agregação. Não retorna um valor.

  • merge(state, partialState, [nonAggregateParam]): mescla o estado de agregação partialState com o estado de agregação state. Essa função é usada quando o mecanismo agrega diferentes seções de dados em paralelo e precisa combinar os resultados. Não retorna um valor.

  • finalize(finalState, [nonAggregateParam]): retorna o resultado final da função agregada, considerando um estado de agregação final finalState.

Para saber mais sobre as funções necessárias, consulte Funções necessárias em um UDAF em JavaScript.

Funções opcionais de serialização JavaScript

Se você quiser trabalhar com estados de agregação não serializáveis, a UDAF em JavaScript precisará fornecer as funções serialize e deserialize. A função serialize converte o estado de agregação em um objeto serializável do BigQuery. a função deserialize converte o objeto serializável do BigQuery de volta a um estado de agregação.

  • serialize(state): retorna um objeto serializável que contém as informações no estado de agregação, a ser desserializado por meio da função deserialize.

  • deserialize(serializedState): desserializa serializedState (serializada anteriormente pela função serialize) para um estado de agregação, que pode ser transmitido na função serialize, aggregate, merge ou finalize.

Para saber mais sobre as funções integradas de serialização do JavaScript, consulte Funções de serialização para um UDAF em JavaScript.

Para aprender a serializar e desserializar dados com um UDAF em JavaScript, consulte Serializar e desserializar dados em um UDAF em JavaScript.

Codificações de tipo SQL permitidas em um UDAF em JavaScript

Nos UDAFs de JavaScript, os seguintes tipos de dados do GoogleSQL compatíveis representam os tipos de dados do JavaScript da seguinte maneira:

Tipo de dados
GoogleSQL
Tipo de dados
do JavaScript
Observações
ARRAY Array Uma matriz de matrizes não é aceita. Para contornar essa limitação, use os tipos de dados Array<Object<Array>> (JavaScript) e ARRAY<STRUCT<ARRAY>> (GoogleSQL).
BIGNUMERIC Number ou String Igual a NUMERIC
BOOL Boolean
BYTES Uint8Array
DATE Date
FLOAT64 Number
INT64 BigInt
JSON Vários tipos O tipo de dados JSON do GoogleSQL pode ser convertido em um Object, Array ou outro tipo de dados JavaScript compatível com GoogleSQL.
NUMERIC Number ou String Se um valor NUMERIC puder ser representado exatamente como um valor de ponto flutuante IEEE 754 (intervalo [-253, 253]) e não tiver uma parte fracionária, ele é codificado como um tipo de dados Number. Caso contrário, ele é codificado como um tipo de dados String.
STRING String
STRUCT Object Cada campo STRUCT é uma propriedade nomeada no tipo de dados Object. Um campo STRUCT sem nome não é aceito.
TIMESTAMP Date Date contém um campo de microssegundo com a fração de microssegundo de TIMESTAMP.

Ligar para um UDAF

Nesta seção, descrevemos as várias maneiras de chamar um UDAF em permanente ou temporário depois de criá-lo no BigQuery.

Chamar um UDAF persistente

É possível chamar um UDAF permanente da mesma maneira que uma função agregada integrada. Para mais informações, consulte Chamadas de função agregada. Você precisa incluir o conjunto de dados no caminho da função.

No exemplo a seguir, a consulta chama um UDAF persistente chamado 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
);

Uma tabela com os seguintes resultados é produzida:

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

Ligar para um UDAF temporário

É possível chamar um UDAF temporário da mesma forma que você chama uma função agregada integrada. Para mais informações, consulte Chamadas de função agregada.

A função temporária precisa ser incluída em uma consulta de várias instruções ou um procedimento que contenha a chamada de função do UDAF.

No exemplo a seguir, a consulta chama um UDAF temporário chamado 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
);

Uma tabela com os seguintes resultados é produzida:

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

Ignorar ou incluir linhas com valores NULL

Quando um UDAF em JavaScript é chamado com o argumento IGNORE NULLS, o BigQuery pula automaticamente as linhas para as quais qualquer argumento agregado é avaliado como NULL. Essas linhas são excluídas completamente da agregação e não são transmitidas para a função aggregate do JavaScript. Quando o argumento RESPECT NULLS é fornecido, a filtragem NULL é desativada e todas as linhas são transmitidas para o UDAF JavaScript, independentemente dos valores NULL.

Quando os argumentos IGNORE NULLS e RESPECT NULLS não forem fornecidos, o argumento padrão será IGNORE NULLS.

O exemplo a seguir ilustra o comportamento padrão NULL, IGNORE NULLS e 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            |
 *-----+------------------+-------------------*/

Excluir um UDAF

Nesta seção, descrevemos as várias maneiras de excluir um UDAF permanente ou temporário depois de criá-lo no BigQuery.

Excluir um UDAF persistente

Para excluir um UDAF permanente, use a instrução DROP FUNCTION. Você precisa incluir o conjunto de dados no caminho da função.

No exemplo a seguir, a consulta exclui um UDAF persistente chamado WeightedAverage:

DROP FUNCTION IF EXISTS my_project.my_dataset.WeightedAverage;

Excluir um UDAF temporário

Para excluir um UDAF temporário, use a instrução DROP FUNCTION.

No exemplo a seguir, a consulta exclui um UDAF temporário chamado WeightedAverage:

DROP FUNCTION IF EXISTS WeightedAverage;

Um UDAF temporário expira assim que a consulta termina, e o UDAF não precisa ser excluído, a menos que você queira removê-lo antecipadamente de uma consulta de várias instruções ou procedimento.

Listar UDAFs

Os UDAFs são um tipo de rotina. Para listar todas as rotinas em um conjunto de dados, consulte Listar rotinas.

Dicas de desempenho

Se você quiser melhorar o desempenho das consultas, considere o seguinte:

  • Pré-filtre a entrada. O processamento de dados em JavaScript é mais caro que no SQL, então é melhor filtrar a entrada o máximo possível no SQL primeiro.

    A consulta a seguir é menos eficiente porque filtra a entrada usando x > 0 na chamada da UDAF:

    SELECT JsFunc(x) FROM t;
    

    A consulta a seguir é mais eficiente porque pré-filtra a entrada usando WHERE x > 0 antes que o UDAF seja chamado:

    SELECT JsFunc(x) FROM t WHERE x > 0;
    
  • Use funções de agregação integradas em vez de JavaScript quando possível. A reimplementação de uma função agregada integrada no JavaScript é mais lenta do que chamar uma função agregada que faz a mesma coisa.

    A consulta a seguir é menos eficiente porque implementa um UDAF:

    SELECT SumSquare(x) FROM t;
    

    A consulta a seguir é mais eficiente porque implementa uma função integrada que produz os mesmos resultados que a consulta anterior:

    SELECT SUM(x*x) FROM t;
    
  • UDAFs em JavaScript são adequados para operações de agregação mais complexas, que não podem ser expressas por funções integradas.

  • Use a memória de maneira eficiente. O ambiente de processamento do JavaScript tem memória limitada disponível para cada consulta. As consultas da UDAF em JavaScript que acumulam muitos estados locais podem ter falhas devido ao esgotamento da memória. Esteja especialmente atento para minimizar o tamanho dos objetos de estado de agregação e evitar estados de agregação que acumulam um grande número de linhas.

    A consulta a seguir não é eficiente porque a função aggregate usa uma quantidade ilimitada de memória quando o número de linhas processadas fica grande.

    export function initialState() {
      return {rows: []};
    }
    export function aggregate(state, x) {
      state.rows.push(x);
    }
    ...
    
  • Use tabelas particionadas quando possível. Os UDAFs em JavaScript normalmente são executados com mais eficiência ao consultar uma tabela particionada em comparação com uma tabela não particionada, porque uma tabela particionada armazena dados em muitos arquivos menores em comparação com uma tabela não particionada, permitindo maior paralelismo.

Limitações

  • UDAFs têm as mesmas limitações que se aplicam às UDFs. Para mais detalhes, consulte Limitações de UDF.

  • Somente literais, parâmetros de consulta e variáveis de script podem ser transmitidos como argumentos não agregados para um UDAF.

  • Não há suporte para o uso da cláusula ORDER BY em uma chamada de função UDAF em JavaScript.

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

Preços

Os UDAFs são cobrados de acordo com o modelo de preços padrão do BigQuery.

Cotas e limites

As UDAFs têm as mesmas cotas e limites que se aplicam às UDFs. Para mais informações sobre cotas de UDF, consulte Cotas e limites.