벡터화된 Python UDF¶
이 항목에서는 벡터화된 Python UDF를 소개합니다.
이 항목의 내용:
개요¶
벡터화된 Python UDF를 사용하면 입력 행 배치를 Pandas DataFrames 로 수신하고 결과 배치를 Pandas 배열 또는 Series 로 반환하는 Python 함수를 정의할 수 있습니다. 다른 Python UDF를 호출하는 것과 같은 방식으로 벡터화된 Python UDF를 호출합니다.
기본 행 단위 처리 패턴에 비해 벡터화된 Python UDF를 사용할 때의 이점은 다음과 같습니다.
Python 코드가 행 배치에서 효율적으로 작동할 경우 성능이 향상될 가능성이 있습니다.
Pandas DataFrame 또는 Pandas 배열에서 작동하는 라이브러리로 호출하는 경우 변환 논리가 덜 필요합니다.
벡터화된 Python UDF를 사용하는 경우:
Python UDF를 사용하여 쿼리를 작성하는 방법을 변경할 필요가 없습니다. 모든 일괄 처리는 자체 코드가 아니라 UDF 프레임워크로 처리됩니다.
벡터화되지 않은 UDF와 마찬가지로, 처리기 코드의 어떤 인스턴스에서 어떤 입력 배치가 나타날지 보장할 수 없습니다.
벡터화된 Python UDF 시작하기¶
벡터화된 Python UDF를 만들려면 처리기 함수에 주석을 추가하기 위해 지원되는 메커니즘 중 하나를 사용하십시오.
vectorized
데코레이터 사용하기¶
_snowflake
모듈은 Snowflake 내에서 실행되는 Python UDF에 노출됩니다. Python 코드에서 _snowflake
모듈을 가져오고 vectorized
데코레이터를 사용하여 input
매개 변수를 pandas.DataFrame
으로 설정함으로써 핸들러가 Pandas DataFrame을 수신할 것으로 예상하도록 지정합니다.
create function add_one_to_inputs(x number(10, 0), y number(10, 0))
returns number(10, 0)
language python
runtime_version = 3.8
packages = ('pandas')
handler = 'add_one_to_inputs'
as $$
import pandas
from _snowflake import vectorized
@vectorized(input=pandas.DataFrame)
def add_one_to_inputs(df):
return df[0] + df[1] + 1
$$;
함수 속성 사용하기¶
_snowflake 모듈을 가져오고 vectorized
데코레이터를 사용하는 대신, 처리기 함수에 특수한 _sf_vectorized_input
속성을 설정할 수 있습니다.
create function add_one_to_inputs(x number(10, 0), y number(10, 0))
returns number(10, 0)
language python
runtime_version = 3.8
packages = ('pandas')
handler = 'add_one_to_inputs'
as $$
import pandas
def add_one_to_inputs(df):
return df[0] + df[1] + 1
add_one_to_inputs._sf_vectorized_input = pandas.DataFrame
$$;
대상 배치 크기 설정하기¶
Python 처리기 함수에 대한 호출은 180초의 시간 제한 내에서 실행해야 하며 처리기 함수에 대한 입력으로 전달된 각 DataFrame에는 현재 최대 수천 개의 행이 포함될 수 있습니다. 시간 제한 내로 유지하기 위해 핸들러 함수의 대상 배치 크기를 설정하고 싶을 수도 있는데, 그러면 입력 DataFrame당 최대 행 개수가 지정됩니다. 더 큰 값을 설정한다고 해서 Snowflake가 지정된 행 개수로 배치를 인코딩하리라는 보장은 없습니다. vectorized
데코레이터 또는 함수의 속성을 사용하여 대상 배치 크기를 설정할 수 있습니다.
참고
max_batch_size
를 사용하는 것은 UDF가 단일 배치당 처리할 수 있는 행 수를 제한하는 메커니즘의 의미가 있습니다. 예를 들어, 한 번에 최대 100개의 행만 처리할 수 있는 방식으로 UDF가 작성된 경우 max_batch_size
는 100로 설정해야 합니다. max_batch_size
설정은 임의의 큰 배치 크기를 지정하는 메커니즘으로 사용하기 위한 것은 아닙니다. UDF가 모든 크기의 배치를 처리할 수 있는 경우 이 매개 변수를 설정하지 않은 상태로 두는 것이 좋습니다.
vectorized
데코레이터 사용하기¶
vectorized
데코레이터를 사용하여 대상 배치 크기를 설정하려면 max_batch_size
로 명명된 인자용으로 양의 정수 값을 전달하십시오.
한 예로서, 이 문을 실행하면 각 Dataframe을 최대 100개의 행으로 제한하는 벡터화된 Python UDF가 생성됩니다.
create function add_one_to_inputs(x number(10, 0), y number(10, 0))
returns number(10, 0)
language python
runtime_version = 3.8
packages = ('pandas')
handler = 'add_one_to_inputs'
as $$
import pandas
from _snowflake import vectorized
@vectorized(input=pandas.DataFrame, max_batch_size=100)
def add_one_to_inputs(df):
return df[0] + df[1] + 1
$$;
함수 속성 사용하기¶
함수 속성을 사용하여 대상 배치 크기를 설정하려면 핸들러 함수에서 _sf_max_batch_size
속성에 대해 양의 정수 값을 설정하십시오.
한 예로서, 이 문을 실행하면 각 DataFrame을 최대 100개의 행으로 제한하는 벡터화된 Python UDF가 생성됩니다.
create function add_one_to_inputs(x number(10, 0), y number(10, 0))
returns number(10, 0)
language python
runtime_version = 3.8
packages = ('pandas')
handler = 'add_one_to_inputs'
as $$
import pandas
def add_one_to_inputs(df):
return df[0] + df[1] + 1
add_one_to_inputs._sf_vectorized_input = pandas.DataFrame
add_one_to_inputs._sf_max_batch_size = 100
$$;
DataFrame 인코딩¶
UDF에 대한 인자의 배치는 입력 Pandas DataFrame의 배열로 인코딩되며 각 DataFrame의 행 개수는 다를 수 있습니다. 자세한 내용은 대상 배치 크기 설정하기 를 참조하십시오. 인자는 인덱스로 DataFrame에서 액세스할 수 있습니다. 즉, 첫 번째 인자의 인덱스는 0이고 두 번째 인자의 1인 식입니다. UDF 핸들러가 반환하는 Pandas 배열 또는 Series는 입력 DataFrame의 Pandas 배열 또는 Series와 길이와 같아야 합니다.
설명을 위해 다음과 같이 벡터화된 Python UDF를 정의한다고 해보겠습니다.
create or replace function add_inputs(x int, y float)
returns float
language python
runtime_version = 3.8
packages = ('pandas')
handler = 'add_inputs'
as $$
import pandas
from _snowflake import vectorized
@vectorized(input=pandas.DataFrame)
def add_inputs(df):
return df[0] + df[1]
$$;
이 UDF는 첫 번째 인자에 대해서는 df[0]
를 사용하여 Pandas 배열에 액세스하고, 두 번째 인자에 대해서는 df[1]
을 사용합니다. df[0] + df[1]
은 두 배열의 해당 요소를 쌍으로 합한 Pandas 배열을 생성합니다. UDF를 만든 후, 일부 입력 행으로 이를 호출할 수 있습니다.
select add_inputs(x, y)
from (
select 1 as x, 3.14::float as y union all
select 2, 1.59 union all
select 3, -0.5
);
+------------------+
| ADD_INPUTS(X, Y) |
|------------------|
| 4.14 |
| 3.59 |
| 2.5 |
+------------------+
여기서 add_inputs
Python 함수는 다음 Python 코드로 생성된 것과 유사한 DataFrame을 수신합니다.
>>> import pandas
>>> df = pandas.DataFrame({0: pandas.array([1, 2, 3]), 1: pandas.array([3.14, 1.59, -0.5])})
>>> df
0 1
0 1 3.14
1 2 1.59
2 3 -0.50
핸들러 함수의 return df[0] + df[1]
행은 다음 Python 코드와 유사한 배열을 생성합니다.
>>> df[0] + df[1]
0 4.14
1 3.59
2 2.50
dtype: float64
타입 지원¶
벡터화된 Python UDF는 인자 및 반환 값에 대해 다음 SQL 타입 을 지원합니다. 이 표는 각 SQL 인자가 특정 dtype 의 Pandas 배열로 인코딩되는 방식을 반영합니다.
SQL 형식 |
Pandas dtype |
참고 |
---|---|---|
NUMBER |
|
UDF에 대한 입력 인자가 nullable이 아닌 것으로 해석되도록 보장하려면 |
FLOAT |
|
NULL 값은 NaN 값으로 인코딩됩니다. 출력에서는 NaN 값이 NULL로 해석됩니다. |
BOOLEAN |
Nullable 인자의 경우 |
|
VARCHAR |
|
Snowflake SQL과 Pandas는 모두 UTF-8 인코딩을 사용하여 문자열을 나타냅니다. |
BINARY |
|
|
DATE |
|
각각의 값은 시간 구성 요소가 없는 |
VARIANT |
|
각 베리언트 행은 인자에 대해 동적으로 Python 형식으로 변환되고 반환 값에 대해서는 그 반대로 변환됩니다. |
OBJECT |
|
|
ARRAY |
|
|
TIME |
|
각각의 값은 자정부터 오프셋으로 인코딩됩니다. NULL 값은 |
TIMESTAMP_LTZ |
|
현지 타임존을 사용하여 각각의 값을 UTC Unix Epoch에 상대적인 나노초 단위의 |
TIMESTAMP_NTZ |
|
각각의 값을 나노초 단위 |
TIMESTAMP_TZ |
|
각각의 값을 나노초 단위 |
GEOGRAPHY |
|
각각의 값을 GeoJSON 형식으로 지정한 다음, Python |
Pandas Series
또는 array
, NumPy array
, 일반 Python list
, 타입 지원 에 설명된 예상 형식을 포함하는 반복 가능한 모든 시퀀스와 같은 형식이 출력으로 허용됩니다. bool
, boolean
, int16
, int32
, int64
, Int16
, Int32
, Int64
또는 float64
는 내용을 memoryviews
로 노출하므로, dtype이 위와 같은 경우 Pandas Series
와 array
및 NumPy array
사용하는 것이 효율적입니다. 이는 각각의 값을 순차적으로 읽는 대신 내용을 복사할 수 있다는 뜻입니다.