Java UDF 만들기

이 항목에서는 Java UDF(사용자 정의 함수)를 만들고 설치하는 방법을 보여줍니다.

Java UDF를 작성할 때 Snowflake가 UDF 논리로 실행되도록 Java 코드를 작성합니다. 이 Java 코드는 UDF의 처리기입니다. CREATE FUNCTION 과 함께 UDF를 배포하여 UDF의 이름을 지정하고 Java 메서드를 UDF가 호출될 때 사용할 처리기로 지정합니다.

더 많은 예시 코드는 Java UDF 처리기의 예 섹션을 참조하십시오.

이 항목의 내용:

Java로 UDF 처리기 작성하기

Java UDF 처리기를 작성할 때 다음 요구 사항과 지침을 사용하십시오.

  • 클래스를 public으로 정의하십시오.

  • 클래스 내에서 UDF 처리기로 사용할 공용 메서드를 하나 이상 선언합니다.

    인라인 UDF 의 경우 처리기 메서드를 하나만 선언합니다. 대신 클래스를 미리 컴파일된 UDF로 JAR에 패키징하려는 경우 여러 개의 처리기 메서드를 선언한 이후에 각각을 CREATE FUNCTION 문의 HANDLER 절을 사용하여 처리기로 지정할 수 있습니다.

    필요한 경우 처리기 메서드로 호출할 다른 메서드를 선언할 수 있습니다.

    각 처리기 메서드에 대해 다음 요구 사항과 지침을 사용합니다.

    • 정적이든 비정적이든, 처리기 메서드를 공용으로 선언합니다.

      메서드가 비정적인 경우 클래스는 또한 인자가 없는 생성자를 선언하거나 생성자를 전혀 선언하지 않아야 합니다.

      Snowflake는 클래스를 인스턴스화할 때 생성자에 어떤 인자도 전달하지 않습니다. 생성자에서 오류가 발생하는 경우, 이 오류는 예외 메시지와 함께 사용자 오류로서 발생합니다.

    • 적절한 반환 형식을 지정하십시오.

      반환 형식은 SQL-Java 형식 매핑 테이블Java Data Type 열에 지정된 데이터 타입 중 하나여야 합니다. 반환 형식은 CREATE FUNCTION 문의 RETURNS 절에 지정된 SQL 데이터 타입과 호환되어야 합니다.

    • 각 처리기 메서드 인자(있는 경우)가 SQL-Java Type Mappings 테이블Java Data Type 열에 지정된 데이터 타입인지 확인합니다.

      Java 변수의 데이터 타입을 선택할 때 Snowflake에서 전송(및 반환)될 수 있는 데이터의 가능한 최댓값 및 최솟값을 고려하십시오.

    • 각 처리기 메서드와 각 메서드가 호출하는 메서드에서 Java UDF에 대해 Snowflake가 적용한 제약 조건 을 준수합니다.

Snowflake에서 함수 만들기

이 섹션의 정보는 코드가 인라인 으로 지정되었는지 또는 미리 컴파일 되었는지 여부와 관계없이 모든 Java UDF에 적용됩니다.

다음을 포함하여 UDF의 여러 측면을 지정하는 CREATE FUNCTION 문을 실행해야 합니다.

  • UDF 이름.

  • UDF가 호출될 때 Snowflake가 처리기로 호출할 Java 메서드의 이름.

UDF 이름은 Java로 작성된 처리기 메서드의 이름과 일치할 필요가 없습니다. 다음 다이어그램에 나타낸 것처럼, CREATE FUNCTION 문은 UDF 이름을 Java 메서드와 연관시킵니다.

Using the CREATE FUNCTION Statement to Associate the Handler Method With the UDF Name

UDF의 이름을 선택할 때:

  • 오브젝트 식별자 에 대한 규칙을 따르십시오.

  • 고유한 이름을 선택하거나 UDF 이름의 오버로딩 에 대한 규칙을 따르십시오.

    중요

    인자의 수 및 데이터 타입 둘 다를 기반으로 함수를 구별하는 SQL UDF의 오버로드와 달리 Java UDF는 오직 인자 수만을 기반으로 메서드를 구별합니다. 두 Java 메서드가 동일 이름과 동일 수의 인자를 갖지만 데이터 타입이 다른 경우, 이러한 메서드 중 하나를 핸들러로 사용하여 UDF를 호출하면 다음과 유사한 오류가 생성됩니다.

    호출할 핸들러 《handler name》의 구현을 확인할 수 없습니다. <class name>.<handler name> 핸들러가 있는 <user defined function name> 함수에 <number of args> 인자가 있는 여러 정의가 있기 때문입니다.

    웨어하우스를 사용할 수 있는 경우, UDF가 만들어질 때 오류가 감지됩니다. 그렇지 않은 경우, UDF가 호출될 때 오류가 발생합니다.

    데이터 타입을 기반으로 확인하는 것은 비실용적입니다. 일부 SQL 데이터 타입은 둘 이상의 Java 데이터 타입에 맵핑될 수 있고 따라서 잠재적으로 둘 이상의 Java UDF 서명에 맵핑될 수 있기 때문입니다.

처리기 메서드 인자는 이름이 아닌 위치를 기준으로 UDF 인자에 바인딩됩니다. 달리 말하자면, 첫 번째 UDF 인자는 첫 번째 메서드 인자로 전달되고 두 번째 UDF 인자는 두 번째 메서드 인자로 전달되는 식입니다.

아래 예에서 SQL UDF 인자 x 는 Java 메서드 인자 a 에 해당하고 yb 에 해당합니다.

create function add_int_float(x numeric(9, 0), y float)
returns float
language java
handler = 'MyClass.addIntFloat';
public static float addIntFloat(int a, float b) {
  // ...
}

인자의 데이터 타입에 대한 자세한 내용은 매개 변수 및 반환 형식에 대한 SQL-Java 데이터 타입 매핑 을 참조하십시오.

참고

스칼라 함수(UDF)의 입력 인자는 500개로 제한됩니다.

기본 버전은 향후 변경될 수 있으므로 CREATE FUNCTION 문의 RUNTIME_VERSION 매개 변수를 사용하여, 지원되는 Java 런타임 버전을 지정하는 것이 좋습니다.

인라인 UDF vs. 미리 컴파일된 UDF

다음 방식 중 하나로 Java UDF 처리기를 정의할 수 있습니다.

  • 컴파일된 Java 처리기를 JAR에 패키징하여 Snowflake가 읽을 수 있는 곳에 배치하는 사전 컴파일 방식.

    CREATE FUNCTION 문은 처리기를 포함하는 JAR 파일의 위치를 지정합니다. CREATE FUNCTION 을 실행하기 전에 Snowflake가 읽을 수 있는 스테이지 에 JAR 파일을 복사합니다.

  • UDF 선언 자체와 함께 Java 코드를 포함하는 인라인 방식.

    CREATE FUNCTION 문 자체가 Java 소스 코드를 지정합니다. Snowflake는 소스 코드를 컴파일하고 컴파일된 코드를 JAR 파일에 저장합니다. CREATE FUNCTION을 실행할 때 TARGET_PATH 절을 사용하여 결과 JAR 파일의 위치를 지정할 수 있습니다.

    • CREATE FUNCTION이 JAR 파일의 위치를 지정하면 Snowflake는 코드를 한 번 컴파일하고, 나중에 사용할 수 있도록 JAR 파일을 보관합니다.

    • CREATE FUNCTION이 JAR 파일의 위치를 지정하지 않으면 Snowflake는 UDF를 호출하는 각 SQL 문에 대한 코드를 다시 컴파일하고 Snowflake는 SQL 문이 완료된 후 JAR 파일을 자동으로 정리합니다.

실질적인 차이점

인라인 Java UDF의 장점

  • 구현하기가 일반적으로 더 쉽습니다. 개발 도구를 사용하여 코드가 의도대로 작동하는지 확인한 후, CREATE FUNCTION 문에 코드를 복사한 다음 문을 실행하여 코드를 배포할 수 있습니다. 컴파일된 출력을 JAR에 따로 다시 패키징하고 스테이지에서 업데이트할 필요 없이 CREATE FUNCTION을 업데이트하고 실행하여 코드를 유지 관리할 수 있습니다.

사전 컴파일된 Java UDF의 장점

  • JAR 파일이 있지만 소스 코드가 없는 경우 사용할 수 있습니다.

  • 소스 코드가 너무 커서 CREATE FUNCTION 문에 붙여넣을 수 없는 경우 사용할 수 있습니다. (인라인 Java UDF는 소스 코드 크기에 상한이 있습니다.)

  • 사전 컴파일된 Java UDF는 여러 처리기 함수를 포함할 수 있습니다. 여러 CREATE FUNCTION 문은 동일한 JAR 파일을 참조할 수 있지만, JAR 파일 내에서 다양한 핸들러 함수를 지정할 수 있습니다.

    일반적으로 인라인 Java UDF는 호출 가능한 함수를 하나만 포함합니다. (호출 가능한 함수는 다른 함수를 호출할 수 있으며, 이러한 다른 함수는 동일한 클래스에 정의되거나 라이브러리 JAR 파일에 정의된 다른 클래스에 정의될 수 있습니다.)

  • JAR 파일을 테스트하거나 디버깅하기 위한 도구나 환경이 있는 경우, JAR 파일을 사용하여 UDF에서 대부분의 개발 작업을 수행하는 것이 더 편리할 수 있습니다. 코드가 크거나 복잡한 경우 특히 그렇습니다.

클래스 경로에 종속 항목 추가하기

처리기 코드에 외부 JAR 파일에 패키징된 클래스가 필요할 때는 처리기에서 사용할 수 있는 Snowflake 관리 클래스 경로에 이러한 종속 항목을 추가할 수 있습니다. 다음은 Java UDF 처리기에서 볼 수 있는 클래스 경로에 JAR 파일을 추가하는 방법을 설명합니다.

  1. 처리기가 사용할 수 있는 스테이지를 만듭니다.

    UDF 종속 항목의 경우 외부 스테이지 또는 내부 스테이지를 사용할 수 있습니다. 내부 스테이지를 사용하는 경우 사용자 또는 명명된 스테이지여야 합니다. Snowflake는 현재 UDF 종속 항목에 테이블 스테이지를 사용할 수 있도록 지원하지 않습니다. 스테이지 생성에 대한 자세한 내용은 CREATE STAGE 섹션을 참조하십시오. 내부 스테이지 유형 선택에 대한 자세한 내용은 로컬 파일을 위한 내부 스테이지 선택하기 섹션을 참조하십시오.

  2. 종속성 JAR을 스테이지에 복사합니다.

    PUT 명령을 사용하여 로컬 드라이브에서 스테이지로 JAR을 복사할 수 있습니다. 명령 참조는 PUT 섹션을 참조하십시오. PUT으로 파일을 스테이징하는 자세한 방법은 로컬 파일 시스템에서 데이터 파일 스테이징하기 섹션을 참조하십시오.

  3. UDF를 만들 때 종속성 JAR을 참조합니다.

    CREATE FUNCTION을 실행하여 UDF를 만들 때 모든 종속성 JAR 파일의 스테이지 위치와 파일 경로 및 이름을 IMPORTS 절의 값으로 지정합니다. 런타임에 Snowflake는 클래스 경로에 JAR을 추가합니다. 참조 정보는 CREATE FUNCTION 섹션을 참조하십시오.

    다음 예제의 코드는 my_udf 라는 UDF를 만들어 스테이지 @mystage 에 대한 my_handler_dependency.jar 종속성을 지정합니다.

    CREATE FUNCTION my_udf(i NUMERIC)
      RETURNS NUMERIC
      LANGUAGE JAVA
      IMPORTS = ('@mystage/dependencies/my_handler_dependency.jar')
      HANDLER = 'MyClass.myFunction'
      AS
      $$
        // Handler code omitted.
      $$
    

인라인 Java UDF 만들기

인라인 UDF의 경우, CREATE FUNCTION 문의 일부로서 Java 소스 코드를 제공합니다.

Java 소스 코드를 AS 절에 넣고 코드를 작은따옴표나 한 쌍의 달러 기호($$)로 묶습니다. 소스 코드에 작은따옴표가 포함되어 있을 때와 같이, 이중 달러 기호를 사용하는 것이 더 쉬울 수 있습니다.

다음 예제의 코드에서는 처리기가 TestAddFunc 클래스의 add 메서드인 add UDF를 선언합니다.

create function add(x integer, y integer)
returns integer
language java
handler='TestAddFunc.add'
target_path='@~/TestAddFunc.jar'
as
$$
    class TestAddFunc {
        public static int add(int x, int y) {
          return x + y;
        }
    }
$$;

Java 소스 코드가 둘 이상의 클래스, 그리고 한 클래스에 둘 이상의 메서드를 포함할 수 있다는 점을 고려하면, HANDLER 절은 처리기로 사용할 클래스와 메서드를 지정합니다.

(미리 컴파일된 Java UDF와 같은) 인라인 Java UDF는 CREATE FUNCTION 문의 IMPORTS 절에 포함된 JAR 파일의 코드를 호출할 수 있습니다.

CREATE FUNCTION 문의 구문에 대한 자세한 내용은 CREATE FUNCTION 을 참조하십시오.

더 많은 예는 Java UDF 처리기의 예 섹션을 참조하십시오.

미리 컴파일된 Java UDF 만들기

처리기에 대한 기존 JAR의 위치를 지정하는 UDF를 만들려는 경우 다음과 같은 방법으로 처리기를 개발합니다.

파일 정리

Java 코드를 컴파일하여 JAR 파일을 직접 만들 계획이라면 아래와 같이 파일을 구성할 수 있습니다. 이 예에서는 Java의 패키지 메커니즘을 사용할 계획이라고 가정합니다.

  • developmentDirectory

    • packageDirectory

      • class_file1.java

      • class_file2.java

    • classDirectory

      • class_file1.class

      • class_file2.class

    • manifest_file.manifest(선택 사항)

    • jar_file.jar

    • put_command.sql

developmentDirectory

이 디렉터리에는 Java UDF를 만드는 데 필요한 프로젝트별 파일이 포함되어 있습니다.

packageDirectory

이 디렉터리에는 패키지에 컴파일하고 포함할 .java 파일이 포함되어 있습니다.

class_file#.java

이 파일에는 UDF의 Java 소스 코드가 포함되어 있습니다.

class_file#.class

이들은 .java 파일을 컴파일하여 만들어진 .class 파일입니다.

manifest_file.manifest

.class 파일(및 필요에 따라 종속성 JAR 파일)을 JAR 파일에 결합할 때 사용되는 선택적 매니페스트 파일입니다.

jar_file.jar

UDF 코드가 포함된 JAR 파일입니다.

put_command.sql

이 파일에는 JAR 파일을 Snowflake 스테이지 에 복사하는 SQL PUT 명령이 포함되어 있습니다.

Java 코드 컴파일 및 JAR 파일 생성

컴파일된 Java 코드가 포함된 JAR 파일을 만들려면:

  • javac를 사용하여 .java 파일을 .class 파일로 컴파일하십시오.

    버전 11.x보다 최신 버전의 컴파일러를 사용하는 경우, 《-release》 옵션을 사용하여 대상 버전이 버전 11임을 지정할 수 있습니다.

  • .class 파일을 JAR 파일에 넣으십시오. 여러 클래스 파일(및 기타 JAR 파일)을 JAR 파일에 패키지할 수 있습니다.

    예:

    jar cf ./my_udf.jar MyClass.class
    

    처리기 클래스가 패키지에 있으면 매니페스트 파일이 필수적이고, 그렇지 않으면 선택 사항입니다. 다음 예에서는 매니페스트 파일을 사용합니다.

    jar cmf my_udf.manifest ./my_udf.jar example/MyClass.class
    

    모든 종속성이 포함된 jar 파일을 빌드하려면 maven-assembly-plugin과 함께 Maven의 mvn package 명령을 사용할 수 있습니다. maven-assembly-plugin에 대한 자세한 내용은 Maven 사용 페이지 를 참조하십시오.

    Snowflake는 표준 Java 라이브러리 (예: java.util)를 자동으로 제공합니다. 코드에서 이러한 라이브러리를 호출하는 경우 이를 JAR 파일에 포함할 필요가 없습니다.

    라이브러리에서 호출하는 메서드는 Java 메서드와 동일한 Snowflake 부과 제약 조건 을 따라야 합니다.

JAR 파일을 스테이지에 복사

Snowflake가 처리기 메서드를 포함한 JAR에서 읽도록 하려면 JAR를 다음 종류의 스테이지 중 하나로 복사해야 합니다.

  • 사용자 또는 명명된 내부 스테이지.

    Snowflake는 현재 테이블 스테이지를 사용하여 UDF 처리기가 있는 JAR 파일을 저장하는 기능을 지원하지 않습니다. 내부 스테이지에 대한 자세한 내용은 로컬 파일을 위한 내부 스테이지 선택하기 섹션을 참조하십시오.

  • 외부 스테이지.

JAR 파일을 호스팅하는 스테이지는 UDF 소유자 가 읽을 수 있어야 합니다.

일반적으로 PUT 명령을 사용하여 명명된 내부 스테이지로 JAR를 업로드합니다. Snowflake GUI를 통해 PUT 명령을 실행할 수 없으며, SnowSQL을 사용해 PUT 을 실행할 수 있습니다. .jar 파일을 스테이지에 복사하는 예제 PUT 명령은 Java UDF 처리기의 예 섹션을 참조하십시오.

스테이지 생성에 대한 자세한 내용은 CREATE STAGE 섹션을 참조하십시오.

경고 및 모범 사례

JAR 파일을 삭제하거나 이름을 바꾸면 더 이상 UDF를 호출할 수 없습니다.

JAR 파일을 업데이트해야 하는 경우:

  • UDF를 호출할 수 없는 동안 업데이트하십시오.

  • 이전 .jar 파일이 아직 스테이지에 있는 경우, PUT 명령에 OVERWRITE=TRUE 절이 포함되어야 합니다.

참고

UDF와 관련된 작업을 수행하는 사용자는 작업에 필요한 권한이 할당된 역할이 있어야 합니다. 자세한 내용은 사용자 정의 함수에 대한 권한 부여하기 섹션을 참조하십시오.