Lambda를 사용하여 UDF 생성 및 배포
사용자 지정 UDF를 생성하려면 UserDefinedFunctionHandler
클래스를 확장하여 새 Java 클래스를 생성합니다. SDK의 UserDefinedFunctionHandler.java
이 섹션의 단계에서는 명령줄과 배포에서 Apache Maven
Maven을 사용하여 Athena용 사용자 지정 UDF를 생성하려면 다음 단계를 수행합니다.
SDK 복제 및 개발 환경 준비
시작하기 전에 git가 sudo
yum install git -y
를 사용하여 시스템에 설치되어 있는지 확인하세요.
AWS query federation SDK를 설치하려면
-
명령줄에 다음을 입력하여 SDK 리포지토리를 복제합니다. 이 리포지토리에는 SDK, 예제 및 데이터 소스 커넥터 제품군이 포함되어 있습니다. 데이터 소스 커넥터에 대한 자세한 내용은 Amazon Athena 페더레이션 쿼리 사용 단원을 참고하세요.
git clone https://github.com/awslabs/aws-athena-query-federation.git
이 절차의 사전 조건을 설치하려면
이미 Apache Maven, AWS CLI 및AWS Serverless Application Model 빌드 도구가 설치된 개발 머신에서 작업하는 경우 이 단계를 건너뛸 수 있습니다.
-
복제할 때 생성한
aws-athena-query-federation
디렉터리의 루트에서 개발 환경을 준비하는 prepare_dev_env.sh스크립트를 실행합니다. -
을 업데이트하여 설치 프로세스에서 생성된 새 변수를 소싱하거나 터미널 세션을 다시 시작합니다.
source ~/.profile
중요
이 단계를 건너뛰면 나중에 Lambda 함수를 게시할 수 없는 AWS CLI 또는 AWS SAM 빌드 도구에 대한 오류가 발생합니다.
Maven 프로젝트 만들기
다음 명령을 실행하여 Maven 프로젝트를 만듭니다. groupId
를 고유한 조직 ID로 바꾸고 my-athena-udf
를 애플리케이션 이름으로 바꿉니다. 자세한 내용은 Apache Maven 문서에서 첫 번째 Maven 프로젝트를 만들려면 어떻게 해야 합니까?
mvn -B archetype:generate \ -DarchetypeGroupId=org.apache.maven.archetypes \ -DgroupId=
groupId
\ -DartifactId=my-athena-udfs
Maven 프로젝트에 종속성 및 플러그인 추가
Maven 프로젝트 pom.xml
파일에 다음 구성을 추가합니다. 예를 들어 GitHub의 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>
UDF에 대한 Java 코드 작성
UserDefinedFunctionHandler.java
다음 예제에서는 UDF에 대한 두 개의 Java 메서드인 compress()
및 decompress()
가 클래스 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); } }
JAR 파일 구축
mvn clean install
을 실행하여 프로젝트를 빌드합니다. 성공적으로 빌드되면 JAR 파일이
이라는 프로젝트의 artifactId
-version
.jartarget
폴더에 생성됩니다. 여기서 artifactId
는 Maven 프로젝트에서 제공한 이름입니다(예: my-athena-udfs
).
AWS Lambda에 JAR 배포
Lambda에 코드를 배포하는 두 가지 옵션이 있습니다.
-
AWS Serverless Application Repository을 사용하여 배포(권장)
-
JAR 파일에서 Lambda 함수 만들기
옵션 1: AWS Serverless Application Repository에 배포
AWS Serverless Application Repository에 JAR 파일을 배포할 때 애플리케이션의 아키텍처를 나타내는 AWS SAM 템플릿 YAML 파일을 만듭니다. 그런 다음 이 YAML 파일과, 애플리케이션의 아티팩트를 업로드하여 AWS Serverless Application Repository에 공개하는 Amazon S3 버킷을 지정합니다. 아래 절차에서는 앞서 복제했던 Athena Query Federation SDK의 athena-query-federation/tools
디렉터리에 위치한 publish.sh
자세한 내용과 요구 사항은 AWS Serverless Application Repository 개발자 안내서의 애플리케이션 게시, AWS Serverless Application Model 개발자 안내서의 AWS SAM 템플릿 개념 및 AWS SAM CLI를 사용하여 서버리스 애플리케이션 게시를 참조하세요.
다음 예제에서는 YAML 파일의 파라미터를 보여줍니다. YAML 파일에 유사한 파라미터를 추가하고 프로젝트 디렉터리에 저장합니다. 전체 예제는 GitHub에서 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
YAML 파일을 저장한 프로젝트 디렉터리에 publish.sh
스크립트를 복사하고 다음 명령을 실행합니다.
./publish.sh
MyS3Location
MyYamlFile
예를 들어 버킷 위치가 s3://amzn-s3-demo-bucket/mysarapps/athenaudf
이고 YAML 파일이 my-athena-udfs.yaml
로 저장된 경우:
./publish.sh amzn-s3-demo-bucket/mysarapps/athenaudf my-athena-udfs
Lambda 함수를 생성하는 방법
-
https://console.aws.amazon.com/lambda/
에서 Lambda 콘솔을 열고 함수 생성을 선택한 다음 서버리스 앱 리포지토리 찾아보기를 선택합니다. -
프라이빗 애플리케이션을 선택하거나 목록에서 애플리케이션을 찾거나 키워드를 사용하여 애플리케이션을 검색한 다음 선택합니다.
-
애플리케이션 세부 정보를 검토하고 제공한 다음 배포를 선택합니다.
이제 Lambda 함수 JAR 파일에 정의된 메서드 이름을 Athena의 UDF로 사용할 수 있습니다.
옵션 2: 직접 Lambda 함수 생성
콘솔 또는 AWS CLI를 사용하여 직접 Lambda 함수를 만들 수도 있습니다. 다음은 Lambda create-function
CLI 명령을 사용하는 예제입니다.
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