Python UDF 설계하기¶
이 항목은 Python UDF를 설계하는 데 도움이 됩니다.
이 항목의 내용:
참고
벡터화된 Python UDF를 사용하면 입력 행 배치를 Pandas DataFrames 로 수신하고 결과 배치를 Pandas 배열 또는 Series 로 반환하는 Python 함수를 정의할 수 있습니다. 배치 인터페이스를 사용하면 머신 러닝 추론 시나리오에서 훨씬 더 나은 성능을 얻을 수 있습니다. 자세한 내용은 벡터화된 Python UDF 섹션을 참조하십시오.
데이터 타입 선택하기¶
코드를 작성하기 전에:
함수가 인자로 수락해야 하는 데이터 타입, 그리고 함수가 반환해야 하는 데이터 타입을 선택하십시오.
타임존 관련 문제를 고려하십시오.
NULL 값을 처리하는 방법을 결정하십시오.
Snowflake가 Python 및 SQL 데이터 타입을 매핑하는 방법에 대한 자세한 내용은 SQL-Python 데이터 타입 매핑 섹션을 참조하십시오.
TIMESTAMP_LTZ 값 및 타임존¶
Python UDF는 호출되는 환경과 크게 분리되어 있습니다. 그러나 타임존은 호출 환경에서 상속됩니다. 호출자의 세션이 Python UDF 호출 전에 기본 타임존을 설정한 경우, Python UDF는 동일한 기본 타임존을 갖습니다. 타임존에 대한 자세한 내용은 TIMEZONE 섹션을 참조하십시오.
NULL 값¶
Variant를 제외한 모든 Snowflake 형식의 경우 Python UDF에 대한 SQL NULL
인자는 Python None
값으로 변환되고 반환된 Python None
값은 다시 SQL NULL
로 변환됩니다.
Variant 형식 값은 SQL NULL
또는 VARIANT JSON null
일 수 있습니다. Snowflake VARIANT NULL에 대한 자세한 내용은 NULL 값 을 참조하십시오.
VARIANT JSON
null
은 PythonNone
으로 변환됩니다.SQL
NULL
은is_sql_null
속성이 있는 Python 오브젝트로 변환됩니다.
예를 들어 Python UDF에서의 NULL 처리 를 참조하십시오.
Snowflake에서 부과한 제약 조건 내에서 유지되는 Python UDF 설계하기¶
Snowflake 환경 내에서 안정성을 보장하기 위해 Snowflake는 Python UDF에 다음과 같은 제약 조건을 적용합니다. 달리 명시되지 않는 한 이러한 제한 사항은 UDF가 만들어질 때가 아니라 실행될 때 적용됩니다.
머신 러닝(Z) 모델 학습은 때로는 리소스를 매우 많이 사용할 수 있습니다. Snowpark에 최적화된 웨어하우스는 대량의 메모리와 컴퓨팅 리소스가 필요한 워크로드에 사용할 수 있는 일종의 Snowflake 가상 웨어하우스입니다. 머신 러닝 모델과 Snowpark Python에 대한 자세한 내용은 Snowpark Python으로 머신 러닝 모델 학습시키기 섹션을 참조하십시오.
메모리¶
너무 많은 메모리를 사용하지 마십시오.
큰 데이터 값은 많은 양의 메모리를 사용할 수 있습니다.
과도한 스택 깊이는 많은 양의 메모리를 사용할 수 있습니다.
UDF는 메모리를 너무 많이 사용하는 경우 오류를 반환합니다. 특정 제한은 변경될 수 있습니다.
너무 많은 메모리를 사용하여 UDF가 실패하는 경우 Snowpark에 최적화된 웨어하우스 를 사용해 보십시오.
시간¶
호출당 많은 시간이 소요되는 알고리즘을 피하십시오.
UDF를 완료하는 데 너무 오래 걸리는 경우, Snowflake는 SQL 문을 종료하고 사용자에게 오류를 반환합니다. 이는 무한 루프와 같은 오류의 영향과 비용을 제한합니다.
모듈 설계하기¶
SQL 문이 Python UDF를 호출하면 Snowflake는 사용자가 작성한 Python 함수를 호출합니다. Python 함수를 “핸들러 함수” 또는 줄여서 “핸들러”라고 합니다. 핸들러는 사용자 제공 모듈 내부에 구현된 함수입니다.
모든 Python 함수와 마찬가지로 함수는 모듈의 일부로 선언되어야 합니다.
핸들러는 Python UDF에 전달된 각 행에 대해 한 번 호출됩니다. 해당 함수를 포함하는 모듈은 각 행에 대해 다시 가져오지 않습니다. Snowflake는 동일한 모듈의 핸들러 함수를 두 번 이상 호출할 수 있습니다.
코드 실행을 최적화하기 위해 Snowflake는 초기화가 느릴 수 있는 반면 핸들러 함수의 실행은 빠르다고 가정합니다. Snowflake는 핸들러를 실행하는 것(한 행의 입력으로 핸들러를 호출하는 시간)보다 초기화 실행(UDF를 로딩하는 시간과 모듈을 초기화하는 시간 포함)에 더 긴 시간 제한을 설정합니다.
모듈 설계에 대한 추가 정보는 Python UDF 만들기 에 있습니다.
스칼라 UDF에서 초기화 최적화 및 전역 상태 제어¶
대부분의 스칼라 UDF는 아래 지침을 따라야 합니다.
행 간에 변경되지 않는 공유 상태를 초기화해야 하는 경우, 핸들러 함수 대신 모듈에서 초기화하십시오.
스레드로부터 안전하도록 핸들러 함수를 작성하십시오.
행 간에 동적 상태를 저장 및 공유하지 마십시오.
UDF가 이러한 지침을 따를 수 없는 경우 Snowflake는 스칼라 UDF가 독립적으로 처리될 것으로 예상합니다. 호출 간에 공유되는 상태에 의존하면 예기치 않은 동작이 발생할 수 있습니다. 시스템이 임의의 순서로 행을 처리하고 이러한 호출을 여러 인스턴스에 분산할 수 있기 때문입니다. 또한 여러 스레드의 동일한 Python 인터프리터 내에서 같은 핸들러 함수가 여러 번 실행될 수 있습니다.
UDF는 핸들러 함수에 대한 호출에서 공유 상태에 의존하는 것을 피해야 합니다. 그러나 사용자가 UDF에서 공유 상태를 저장하려 할 수 있는 다음 두 가지 상황이 있습니다.
각 행에 대해 반복하고 싶지 않은, 부담이 큰 초기화 논리가 포함된 코드입니다.
캐시와 같이 행 간에 공유 상태를 활용하는 코드입니다.
여러 핸들러 호출에서 공유할 전역 상태를 유지해야 할 때는 스레딩 - 스레드 기반 병렬 처리 에 설명된 동기화 기본 요소를 사용하여 데이터 경합으로부터 전역 상태를 보호해야 합니다.
규모와 성능 최적화하기¶
데이터 과학 라이브러리와 함께 벡터화된 Python UDF 사용하기¶
코드에서 머신 러닝 또는 데이터 과학 라이브러리를 사용할 때 벡터화된 Python UDF를 사용하여 이러한 라이브러리가 작동하도록 최적화된 배치로 입력 행을 수신하는 Python 함수를 정의합니다.
자세한 내용은 벡터화된 Python UDF 섹션을 참조하십시오.
단일 스레드 UDF 핸들러 작성하기¶
단일 스레드로 된 UDF 핸들러를 작성합니다. Snowflake는 가상 웨어하우스 컴퓨팅 리소스 전반에 걸쳐 데이터 분할과 UDF 확장을 처리합니다.
모듈에 값비싼 초기화 코드 넣기¶
모듈 범위에 값비싼 초기화 코드를 넣습니다. 그러면 UDF가 초기화될 때 코드가 한 번 수행됩니다. 모든 UDF 핸들러 호출에서 값비싼 초기화 코드를 다시 실행하지 마십시오.
오류 처리¶
UDF로 사용되는 Python 함수는 일반 Python 예외 처리 기술을 사용하여 함수 내에서 오류를 포착할 수 있습니다.
함수 내에서 예외가 발생하고 이 예외가 함수에서 포착되지 않으면 Snowflake는 예외에 대한 스택 추적을 포함하는 오류를 발생시킵니다. 처리되지 않은 예외 로깅 이 활성화되면 Snowflake는 이벤트 테이블에 처리되지 않은 예외에 대한 데이터를 기록합니다.
쿼리를 종료하고 SQL 오류를 생성하기 위해 예외를 포착하지 않고 명시적으로 예외를 발생시킬 수 있습니다. 예:
if (x < 0):
raise ValueError("x must be non-negative.");
디버깅할 때 SQL 오류 메시지 텍스트에 값을 포함할 수 있습니다. 이렇게 하려면 전체 Python 함수 본문을 try-catch 블록에 배치하고, 포착된 오류 메시지에 인자 값을 추가하고, 확장된 메시지와 함께 예외가 발생하도록 하십시오. 민감한 데이터가 노출되지 않도록 하려면 프로덕션 환경에 배포하기 전에 인자 값을 제거하십시오.
우수한 보안 관행 따르기¶
처리기가 안전한 방식으로 작동하도록 보장하려면 UDF 및 프로시저의 보안 모범 사례 에 설명된 모범 사례를 참조하십시오.