Uma função de agregação definida pelo usuário (UDAF) reduz várias linhas de entrada a um único valor de saída (mapeamento de muitos para um). Use UDAFs quando as funções de agregação integradas, como SUM ou MAX, não atenderem à sua lógica de agregação.
Para mais informações sobre funções definidas pelo usuário no Flink, consulte Funções definidas pelo usuário.
Funções definidas pelo usuário e ASI_UDX_Demo estão hospedados em sites de terceiros e podem apresentar lentidão ou indisponibilidade ocasional.
Funcionamento
A UDAF usa um acumulador para armazenar o estado intermediário da agregação. Para cada grupo de linhas com a mesma chave GROUP BY, o runtime executa três métodos em sequência:
createAccumulator()— cria um novo acumulador com o estado inicial.accumulate(acc, ...)— atualiza o acumulador para cada linha de entrada.getValue(acc)— retorna o resultado final após o processamento de todas as linhas.
Por exemplo, se uma tabela tiver uma coluna numérica e você precisar da soma cumulativa dos valores 1, 2 e 3 no mesmo grupo:
O runtime chama
createAccumulator()uma vez para inicializar o acumulador comsum = 0.Em seguida, executa
accumulate()para cada linha, atualizandosumpara1, depois3e, por fim,6.Por último, chama
getValue()para retornar o resultado final.
A saída varia conforme a ativação do mini-batch:
Sem mini-batch (padrão): gera uma saída por linha —
1,3,6.Com mini-batch ativado: retorna apenas o resultado final —
6. A quantidade de saídas intermediárias depende das configurações do mini-batch e da distribuição dos dados.
Para configurar o mini-batch, consulte Optimize Flink SQL.
Métodos obrigatórios
|
Método |
Finalidade |
|
|
Retorna um novo acumulador com estado inicial |
|
|
Atualiza o acumulador com uma linha de entrada |
|
|
Retorna o resultado agregado final |
Outros métodos podem ser necessários dependendo do caso de uso:
|
Método |
Finalidade |
|
|
Permite retrair uma mensagem gerada por um operador upstream |
|
|
Habilita a otimização de agregação em dois estágios (local-global) |
Criar uma UDAF
O Realtime Compute for Apache Flink oferece um projeto de demonstração de UDF (ASI_UDX_Demo) com ambiente de desenvolvimento pré-configurado, eliminando a necessidade de configuração manual.
O projeto de demonstração inclui implementações de exemplo para funções escalares definidas pelo usuário (UDSFs), UDAFs e funções de tabela definidas pelo usuário (UDTFs).
Pré-requisitos
Antes de começar, verifique se você tem:
IntelliJ IDEA instalado
Maven instalado
Ambiente de desenvolvimento Java configurado
Etapas
-
Baixe e descompacte o ASI_UDX_Demo na sua máquina local. A pasta descompactada
ASI_UDX-maincontém:pom.xml— configuração do projeto Maven, incluindo coordenadas, dependências e regras de build.\ASI_UDX-main\src\main\java\ASI_UDAF\ASI_UDAF.java— implementação de exemplo da UDAF.
No IntelliJ IDEA, selecione File > Open e escolha a pasta
ASI_UDX-main.-
Abra o arquivo
pom.xmlno diretório\ASI_UDX-main\e configure as dependências. O arquivo já inclui a dependência mínima para o Flink 1.12:Se o job não exigir dependências adicionais, pule para a próxima etapa.
Caso precise de mais dependências, adicione-as ao
pom.xml.
<dependencies> <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-table-common</artifactId> <version>1.12.7</version> <scope>provided</scope> </dependency> </dependencies>Use a versão secundária mais recente da versão principal do Apache Flink correspondente à sua versão do Ververica Runtime (VVR). Para consultar o mapeamento entre versões do VVR e do Flink, veja Overview.
-
Edite o arquivo
\ASI_UDX-main\src\main\java\ASI_UDAF\ASI_UDAF.javae implemente sua lógica de agregação. O exemplo abaixo faz uma soma cumulativa:package ASI_UDAF; import org.apache.flink.table.functions.AggregateFunction; import java.util.Iterator; public class ASI_UDAF{ public static class AccSum{ public long sum; } public static class MySum extends AggregateFunction<Long, AccSum>{ @Override public Long getValue(AccSum acSum){ return acSum.sum; } @Override public AccSum createAccumulator(){ AccSum acCount= new AccSum(); acCount.sum=0; return acCount; } public void accumulate(AccSum acc,long num){ acc.sum += num; } /** * Supports retracting a message generated by an upstream operator. */ public void retract(AccSum acc,long num){ acc.sum -= num; } /** * Supports local-global two-stage aggregate optimization. */ public void merge(AccSum acc,Iterable<AccSum> it){ Iterator<AccSum> iter=it.iterator(); while(iter.hasNext()){ AccSum accSum=iter.next(); if(null!=accSum){ acc.sum+=accSum.sum; } } } } } -
No diretório onde está o
pom.xml, execute:mvn package -Dcheckstyle.skipO empacotamento da UDAF será bem-sucedido quando o arquivo
ASI_UDX-1.0-SNAPSHOT.jaraparecer em\ASI_UDX-main\target\.
Usar uma UDAF
Há duas formas de usar uma UDAF em jobs SQL. A tabela a seguir resume as principais diferenças:
|
Aspecto |
Método 1: UDAF registrada |
Método 2: JAR no nível do job |
|
Escopo |
Disponível em múltiplos jobs |
Apenas no job específico |
|
Como registrar |
Registre pela página de gerenciamento de UDF |
Faça upload do JAR em Additional dependency files no job |
|
Como chamar no SQL |
Chame pelo nome registrado (sem necessidade de |
Defina um alias com |
|
Reutilização |
Alta — ideal para lógicas de negócio compartilhadas |
Baixa — vinculada a um único job |
Método 1: Usar uma UDAF registrada (recomendado)
Registre a UDAF uma única vez e reutilize-a em vários jobs. Para instruções de registro, consulte Gerencie UDFs.
Após registrá-la como ASI_UDAF$MySum, chame-a diretamente no SQL:
CREATE TEMPORARY TABLE ASI_UDAF_Source (
a BIGINT NOT NULL
) WITH (
'connector' = 'datagen'
);
CREATE TEMPORARY TABLE ASI_UDAF_Sink (
sum BIGINT
) WITH (
'connector' = 'print'
);
INSERT INTO ASI_UDAF_Sink
SELECT `ASI_UDAF$MySum`(a)
FROM ASI_UDAF_Source;
Método 2: Fazer upload de um JAR para um job específico
Na página Data Studio > ETL do Flink, envie o pacote JAR pela opção Additional dependency files, em More configurations. Em seguida, defina um alias de função temporária no SQL do job.
Esse JAR fica restrito ao job em questão e não pode ser compartilhado com outros jobs.
Supondo que a função temporária se chame mysum:
CREATE TEMPORARY TABLE ASI_UDAF_Source (
a BIGINT
) WITH (
'connector' = 'datagen'
);
CREATE TEMPORARY TABLE ASI_UDAF_Sink (
sum BIGINT
) WITH (
'connector' = 'print'
);
CREATE TEMPORARY FUNCTION `mysum` AS 'ASI_UDAF.ASI_UDAF$MySum'; -- Create the temporary function mysum.
INSERT INTO ASI_UDAF_Sink
SELECT `mysum`(a)
FROM ASI_UDAF_Source;
Executar o job
Após desenvolver e implantar o job SQL, acesse Operation Center > Job O&M. Localize o job desejado e clique em Start na coluna Operation.
Com o job em execução, a UDAF agregará o campo a da tabela ASI_UDAF_Source e gravará a soma cumulativa em ASI_UDAF_Sink.
Próximos passos
Gerencie UDFs — registre e gerencie UDAFs para reutilização em diferentes jobs.
Optimize Flink SQL — configure o mini-batch para controlar a emissão de resultados intermediários.
Overview — identifique a versão do Apache Flink compatível com sua versão do VVR.