Funções agregadas definidas pelo usuário
Para receber suporte durante a prévia, envie um e-mail para bigquery-sql-preview-support@google.com.
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
efinalize
). 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 argumentostate
depois que a funçãoaggregate
oumerge
é 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çõesserialize
edeserialize
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çãopartialState
com o estado de agregaçãostate
. 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 finalfinalState
.
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çãodeserialize
.deserialize(serializedState)
: desserializaserializedState
(serializada anteriormente pela funçãoserialize
) para um estado de agregação, que pode ser transmitido na funçãoserialize
,aggregate
,merge
oufinalize
.
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.