Creación e implementación de una UDF mediante Lambda
Para crear una UDF personalizada, cree una nueva clase Java mediante la extensión de la clase UserDefinedFunctionHandler
. El código fuente de UserDefinedFunctionHandler.java
Los pasos de esta sección muestran cómo escribir y crear un archivo Jar de UDF personalizado mediante Apache Maven
Instrucciones para crear una UDF personalizada para Athena mediante Maven
Clonación del SDK y preparación del entorno de desarrollo
Antes de comenzar, asegúrese de que git esté instalado en su sistema mediante sudo
yum install git -y
.
Para instalar el SDK de federación de consultas de AWS
-
Escriba lo siguiente en la línea de comandos para clonar el repositorio de SDK. Este repositorio incluye el SDK, ejemplos y un conjunto de conectores de origen de datos. Para obtener más información sobre los conectores de origen de datos, consulte Uso de consulta federada de Amazon Athena.
git clone https://github.com/awslabs/aws-athena-query-federation.git
Para instalar los requisitos previos para este procedimiento, tenga en cuenta lo siguiente:
Si está trabajando en un equipo de desarrollo que ya tiene instalado Apache Maven, la AWS CLI y la herramienta de compilación de AWS Serverless Application Model, puede omitir este paso.
-
Desde la raíz del directorio
aws-athena-query-federation
que creó cuando realizó la clonación, ejecute el script prepare_dev_env.shque prepara el entorno de desarrollo. -
Actualice el shell para generar nuevas variables creadas por el proceso de instalación o reinicie la sesión de terminal.
source ~/.profile
importante
Si omite este paso, obtendrá errores más adelante acerca de que la herramienta de compilación de la AWS CLI o el AWS SAM no puede publicar su función de Lambda.
Creación del proyecto de Maven
Ejecute el siguiente comando para crear el proyecto de Maven. Reemplace groupId
por el ID único de su organización y sustituya my-athena-udf
por el nombre de su aplicación. Para obtener más información, consulte ¿Cómo realizo mi primer proyecto de Maven?
mvn -B archetype:generate \ -DarchetypeGroupId=org.apache.maven.archetypes \ -DgroupId=
groupId
\ -DartifactId=my-athena-udfs
Adición de dependencias y complementos al proyecto de Maven
Agregue las siguientes configuraciones al archivo pom.xml
del proyecto de Maven. Para ver un ejemplo, consulte el archivo pom.xml
<properties> <aws-athena-federation-sdk.version>2022.47.1</aws-athena-federation-sdk.version> </properties> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-athena-federation-sdk</artifactId> <version>${aws-athena-federation-sdk.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.1</version> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
Escritura de código Java para las UDF
Extienda UserDefinedFunctionHandler.java
En el siguiente ejemplo, se crean dos métodos Java para UDF compress()
y decompress()
, dentro de la clase MyUserDefinedFunctions
.
*package *com.mycompany.athena.udfs; public class MyUserDefinedFunctions extends UserDefinedFunctionHandler { private static final String SOURCE_TYPE = "MyCompany"; public MyUserDefinedFunctions() { super(SOURCE_TYPE); } /** * Compresses a valid UTF-8 String using the zlib compression library. * Encodes bytes with Base64 encoding scheme. * * @param input the String to be compressed * @return the compressed String */ public String compress(String input) { byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8); // create compressor Deflater compressor = new Deflater(); compressor.setInput(inputBytes); compressor.finish(); // compress bytes to output stream byte[] buffer = new byte[4096]; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(inputBytes.length); while (!compressor.finished()) { int bytes = compressor.deflate(buffer); byteArrayOutputStream.write(buffer, 0, bytes); } try { byteArrayOutputStream.close(); } catch (IOException e) { throw new RuntimeException("Failed to close ByteArrayOutputStream", e); } // return encoded string byte[] compressedBytes = byteArrayOutputStream.toByteArray(); return Base64.getEncoder().encodeToString(compressedBytes); } /** * Decompresses a valid String that has been compressed using the zlib compression library. * Decodes bytes with Base64 decoding scheme. * * @param input the String to be decompressed * @return the decompressed String */ public String decompress(String input) { byte[] inputBytes = Base64.getDecoder().decode((input)); // create decompressor Inflater decompressor = new Inflater(); decompressor.setInput(inputBytes, 0, inputBytes.length); // decompress bytes to output stream byte[] buffer = new byte[4096]; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(inputBytes.length); try { while (!decompressor.finished()) { int bytes = decompressor.inflate(buffer); if (bytes == 0 && decompressor.needsInput()) { throw new DataFormatException("Input is truncated"); } byteArrayOutputStream.write(buffer, 0, bytes); } } catch (DataFormatException e) { throw new RuntimeException("Failed to decompress string", e); } try { byteArrayOutputStream.close(); } catch (IOException e) { throw new RuntimeException("Failed to close ByteArrayOutputStream", e); } // return decoded string byte[] decompressedBytes = byteArrayOutputStream.toByteArray(); return new String(decompressedBytes, StandardCharsets.UTF_8); } }
Creación del archivo JAR
Ejecute mvn clean install
para crear su proyecto. Después de que se compile correctamente, se crea un archivo JAR en la carpeta target
de su proyecto denominada
, donde artifactId
-version
.jarartifactId
es el nombre que proporcionó en el proyecto de Maven, por ejemplo, my-athena-udfs
.
Implementación de JAR en AWS Lambda
Tiene dos opciones para implementar su código en Lambda:
-
Implementación mediante AWS Serverless Application Repository (recomendado)
-
Creación de una función de Lambda desde el archivo JAR
Opción 1: implementación en el AWS Serverless Application Repository
Al implementar el archivo JAR en AWS Serverless Application Repository, se crea un archivo YAML de plantilla AWS SAM que representa la arquitectura de la aplicación. A continuación, especifique este archivo YAML y un bucket de Amazon S3 donde los artefactos de su aplicación se carguen y estén disponibles para el AWS Serverless Application Repository. El siguiente procedimiento utiliza el script publish.shathena-query-federation/tools
del SDK de Athena Query Federation que clonó anteriormente.
Para obtener más información y requisitos, consulte Publicación de aplicaciones en la Guía para desarrolladores de AWS Serverless Application Repository, Conceptos de plantillas de AWS SAM en la Guía para desarrolladores de AWS Serverless Application Model y Publicación de aplicaciones sin servidor mediante la CLI de AWS SAM.
En el siguiente ejemplo se muestran los parámetros de un archivo YAML. Agregue parámetros similares a su archivo YAML y guárdelo en su directorio de proyecto. Consulte athena-udf.yaml
Transform: 'AWS::Serverless-2016-10-31' Metadata: 'AWS::ServerlessRepo::Application': Name:
MyApplicationName
Description: 'The description I write for my application
' Author: 'Author Name
' Labels: - athena-federation SemanticVersion: 1.0.0 Parameters: LambdaFunctionName: Description: 'The name of the Lambda function that will contain your UDFs.
' Type: String LambdaTimeout: Description: 'Maximum Lambda invocation runtime in seconds. (min 1 - 900 max)' Default: 900 Type: Number LambdaMemory: Description: 'Lambda memory in MB (min 128 - 3008 max).' Default: 3008 Type: Number Resources: ConnectorConfig: Type: 'AWS::Serverless::Function' Properties: FunctionName: !Ref LambdaFunctionName Handler: "full.path.to.your.handler. For example, com.amazonaws.athena.connectors.udfs.MyUDFHandler
" CodeUri: "Relative path to your JAR file. For example, ./target/athena-udfs-1.0.jar
" Description: "My description of the UDFs that this Lambda function enables.
" Runtime: java8 Timeout: !Ref LambdaTimeout MemorySize: !Ref LambdaMemory
Copie el script publish.sh
en el directorio del proyecto donde guardó el archivo YAML y ejecute el siguiente comando:
./publish.sh
MyS3Location
MyYamlFile
Por ejemplo, si la ubicación del bucket es s3://amzn-s3-demo-bucket/mysarapps/athenaudf
y el archivo YAML se guardó como my-athena-udfs.yaml
:
./publish.sh amzn-s3-demo-bucket/mysarapps/athenaudf my-athena-udfs
Cómo crear una función de Lambda
-
Abra la consola de Lambda en https://console.aws.amazon.com/lambda/
, elija Create function (Crear función), y luego elija Browse serverless app repository (Explorar el repositorio de aplicaciones sin servidor). -
Elija Private applications (Aplicaciones privadas) busque su aplicación en la lista o búsquela con palabras clave y selecciónela.
-
Revise y proporcione los detalles de la aplicación y, a continuación, elija Deploy (Implementar).
Ahora puede utilizar los nombres de los métodos definidos en su archivo JAR de la función de Lambda como UDF en Athena.
Opción 2: creación directa de una función de Lambda
También puede crear una función de Lambda directamente mediante la consola o la AWS CLI. En el siguiente ejemplo, se muestra el uso del comando de la CLI create-function
de Lambda.
aws lambda create-function \ --function-name
MyLambdaFunctionName
\ --runtime java8 \ --role arn:aws:iam::1234567890123:role/my_lambda_role
\ --handlercom.mycompany.athena.udfs.MyUserDefinedFunctions
\ --timeout 900 \ --zip-file fileb://./target/my-athena-udfs-1.0-SNAPSHOT.jar