O AnalyticDB for MySQL oferece suporte à função REMOTE_CALL(), que permite invocar funções definidas pelo usuário (UDFs) personalizadas hospedadas no Function Compute diretamente via SQL. Apenas UDFs escalares são suportadas.
Pré-requisitos
Antes de começar, verifique se você possui:
Um cluster do AnalyticDB for MySQL executando a versão do kernel 3.2.1.0 ou posterior
O cluster e seu serviço do Function Compute na mesma região
Para obter tempos de inicialização a frio mais rápidos, selecione Python , Go ou Node.js como o Runtime Environment ao criar a UDF.
Como funciona
O Function Compute atua como o servidor de funções remotas. Quando a função REMOTE_CALL() é invocada em uma instrução SQL, o AnalyticDB for MySQL envia dados ao Function Compute no formato JSON e retorna o resultado ao cliente.
Um cliente envia uma instrução SQL ao AnalyticDB for MySQL.
Após a chamada da função
REMOTE_CALL(), o AnalyticDB for MySQL transmite os dados ao Function Compute no formato JSON.O Function Compute processa os dados utilizando sua UDF.
O Function Compute devolve o resultado ao AnalyticDB for MySQL no formato JSON.
O AnalyticDB for MySQL entrega o resultado final ao cliente.
Sintaxe
remote_call('returnType', 'func_name', ['{external_config}'|NULL], X1, X2, ..., Xn)
Parâmetros
|
Parâmetro |
Descrição |
|
|
|
Tipo de dados do valor de retorno. Valores válidos: BOOLEAN, DOUBLE, VARCHAR, INTEGER, TINYINT, BIGINT, TIME, DATE, TIMESTAMP, DATETIME. |
|
|
|
Nome da UDF no Function Compute. Para o Function Compute 3.0, especifique apenas o nome da função. Para o Function Compute 2.0, utilize o formato |
|
|
|
|
Configuração estendida no formato JSON. Especifique |
|
|
Parâmetros de entrada. Valores válidos: BOOLEAN, DOUBLE, VARCHAR, INTEGER, TINYINT, BIGINT, TIME, DATE, TIMESTAMP, DATETIME. |
Parâmetros estendidos para external_config
Defina os parâmetros de external_config no nível da consulta ou configure-os globalmente usando SET ADB_CONFIG. As configurações no nível da consulta têm precedência sobre as configurações globais.
|
Parâmetro global |
Parâmetro no nível da consulta |
Obrigatório |
Descrição |
|
|
|
Sim |
Endpoint de serviço interno do Function Compute. Para mais detalhes, consulte Endpoints de serviço. |
|
|
— |
Condicional |
AccessKey ID da conta Alibaba Cloud ou do usuário do Resource Access Management (RAM) com permissões no Function Compute. Obrigatório para clusters da Data Warehouse Edition. Nos clusters das edições Enterprise, Basic e Data Lakehouse, o Security Token Service (STS) gerencia a autenticação automaticamente para acesso na mesma conta; o acesso entre contas exige o AccessKey ID. Pode ser definido apenas como parâmetro global. Para mais detalhes, consulte Contas e permissões. |
|
|
— |
Condicional |
AccessKey secret da conta Alibaba Cloud ou do usuário RAM. Segue as mesmas condições de |
|
|
|
Não |
Determina se o payload de dados deve ser compactado no formato GZIP antes do envio ao Function Compute. Padrão: |
|
|
|
Não |
Número máximo de linhas enviadas ao Function Compute por lote. Padrão: sem limite. Um tamanho de lote menor reduz a pressão sobre CPU e memória no Function Compute, mas aumenta o tempo de consulta. |
Os parâmetros XIHE_REMOTE_CALL_SERVER_AK e XIHE_REMOTE_CALL_SERVER_SK só podem ser configurados como parâmetros globais por meio de SET ADB_CONFIG.
Escreva um handler do Function Compute
Sua UDF deve aceitar entradas e retornar resultados no formato JSON utilizado pela função REMOTE_CALL().
Exemplo: handler Java
O exemplo a seguir implementa ConcactNumberWithCompress, que recebe dois inteiros a e b e retorna a string "a&b&1".
public class App
implements StreamRequestHandler, FunctionInitializer
{
public static final Logger log = Logger.getLogger(App.class.getName());
public void initialize(Context context) throws IOException {
// TODO
}
@Override
public void handleRequest(
InputStream inputStream, OutputStream outputStream, Context context)
throws IOException
{
// Step 1: Decompress the input.
// REMOTE_CALL() compresses data with GZIP by default (compressed=true).
// If you set compressed=false in external_config, skip this step.
InputStream decompressedInput = tryUnCompress(inputStream);
JSONObject response = new JSONObject();
try {
// Step 2: Parse the JSON body sent by AnalyticDB for MySQL.
// The body has the structure: {"rowCount": N, "compressed": true/false, "data": [[...], ...]}
JSONObject requestJson = JSONObject.parseObject(IOUtils.toString(decompressedInput));
if (requestJson.containsKey("data")) {
JSONArray result = new JSONArray();
// Step 3: Iterate over the rows in the "data" array.
// Each row is a JSON array whose columns match the X1...Xn parameter order in REMOTE_CALL().
// This function expects two integers: X1 (index 0) and X2 (index 1).
JSONArray data = requestJson.getJSONArray("data");
for (int i = 0; i < data.size(); i++) {
JSONArray row = data.getJSONArray(i);
if (row.size() == 2) {
result.add(testFunc(row.getInteger(0), row.getInteger(1)));
} else {
throw new RuntimeException("row size is not 2");
}
}
// Step 4: Build the response.
response.put("result", result);
response.put("success", true);
response.put("message", "");
} else {
response.put("success", false);
response.put("message", "no data inside");
}
} catch (Exception e) {
log.info("error happened" + e.getMessage());
response.put("success", false);
response.put("message", e.getMessage());
}
// Step 5: Compress the response.
// REMOTE_CALL() expects a GZIP-compressed response when compressed=true (the default).
// If you set compressed=false in external_config, remove this compression step.
outputStream.write(tryCompress(response.toJSONString().getBytes()));
}
private String testFunc(int a, int b) {
// Concatenate a, b, and 1 with ampersands.
return String.valueOf(a) + '&' + b + '&' + 1;
}
public static byte[] tryCompress(byte[] bytes) {
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
try {
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteOutputStream);
gzipOutputStream.write(bytes);
gzipOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
return byteOutputStream.toByteArray();
}
public static InputStream tryUnCompress(InputStream inputStream) throws IOException {
return new GZIPInputStream(inputStream);
}
}
Exemplos
Chamada com configuração no nível da consulta
Passe o endpoint do Function Compute diretamente no parâmetro external_config:
-- Concatenate 1 and 2 with an ampersand
SELECT remote_call(
'varchar',
'ConcactNumberWithCompress',
'{endpoint:"1234567890000****.cn-zhangjiakou-internal.fc.aliyuncs.com"}',
1, 2
);
-- Result: 1&2&1
Desative a compactação GZIP e defina um limite de tamanho de lote:
SELECT remote_call(
'varchar',
'ConcactNumberWithCompress',
'{endpoint:"1234567890000****.cn-zhangjiakou-internal.fc.aliyuncs.com",compressed:false,max_batch_size:5000000}',
3, 4
);
-- Result: 3&4&1
Chamada com configuração global
Configure os parâmetros globais uma única vez usando SET ADB_CONFIG e, em seguida, omita external_config nas chamadas subsequentes:
SELECT remote_call('varchar', 'ConcactNumberWithCompress', null, 5, 6);
-- Result: 5&6&1
Solução de problemas
java.util.zip.ZipException: Not in GZIP format
Este erro geralmente ocorre por dois motivos:
Incompatibilidade de descompactação na entrada: O AnalyticDB for MySQL compacta os dados no formato GZIP e os envia ao Function Compute, mas a função definida pelo usuário criada no Function Compute não contém código de descompactação. Consequentemente, o Function Compute não consegue analisar os dados.
Incompatibilidade de compactação na saída: O AnalyticDB for MySQL envia dados não compactados ao Function Compute. Após o processamento, o Function Compute compacta o resultado usando o formato GZIP e o retorna ao AnalyticDB for MySQL. Como resultado, o AnalyticDB for MySQL não consegue analisar os dados.
parse remote_call config error
O JSON de external_config está malformado. Verifique a sintaxe do valor de external_config em sua instrução SQL, corrija-o e execute a consulta novamente.