Python UDF ๋งŒ๋“ค๊ธฐยถ

์ด ํ•ญ๋ชฉ์—์„œ๋Š” Python UDF(์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜)๋ฅผ ๋งŒ๋“ค๊ณ  ์„ค์น˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์ด ํ•ญ๋ชฉ์˜ ๋‚ด์šฉ:

Python ์ฝ”๋“œ ์“ฐ๊ธฐยถ

Python ๋ชจ๋“ˆ ๋ฐ ํ•จ์ˆ˜ ์“ฐ๊ธฐยถ

์•„๋ž˜ ์‚ฌ์–‘์„ ๋”ฐ๋ฅด๋Š” ๋ชจ๋“ˆ์„ ์“ฐ์‹ญ์‹œ์˜ค.

  • ๋ชจ๋“ˆ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“ˆ์€ Python ์ •์˜ ๋ฐ ๋ฌธ์„ ํฌํ•จํ•˜๋Š” ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

  • ๋ชจ๋“ˆ ๋‚ด๋ถ€์— ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

  • ํ•จ์ˆ˜๊ฐ€ ์ธ์ž๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ๊ฐ ์ธ์ž๋Š” SQL-Python ํ˜•์‹ ๋งคํ•‘ ํ…Œ์ด๋ธ” ์˜ Python Data Type ์—ด์— ์ง€์ •๋œ ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ํ•จ์ˆ˜ ์ธ์ž๋Š” ์ด๋ฆ„์ด ์•„๋‹Œ ์œ„์น˜๋กœ ๋ฐ”์ธ๋”ฉ๋ฉ๋‹ˆ๋‹ค. UDF์— ์ „๋‹ฌ๋œ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” Python ํ•จ์ˆ˜์—์„œ ์ˆ˜์‹ ํ•œ ์ฒซ ๋ฒˆ์งธ ์ธ์ž์ž…๋‹ˆ๋‹ค.

  • ์ ์ ˆํ•œ ๋ฐ˜ํ™˜ ๊ฐ’์„ ์ง€์ •ํ•˜์‹ญ์‹œ์˜ค. Python UDF๋Š” ์Šค์นผ๋ผ ํ•จ์ˆ˜์—ฌ์•ผ ํ•˜๋ฏ€๋กœ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ํ•˜๋‚˜์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜ ๊ฐ’์˜ ํ˜•์‹์€ SQL-Python ํ˜•์‹ ๋งคํ•‘ ํ…Œ์ด๋ธ” ์˜ Python Data Type ์—ด์— ์ง€์ •๋œ ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜ ๊ฐ’์˜ ํ˜•์‹์€ CREATE FUNCTION ๋ฌธ์˜ RETURNS ์ ˆ์— ์ง€์ •๋œ SQL ๋ฐ์ดํ„ฐ ํƒ€์ž…๊ณผ ํ˜ธํ™˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ชจ๋“ˆ์—๋Š” ๋‘˜ ์ด์ƒ์˜ ํ•จ์ˆ˜๊ฐ€ ํฌํ•จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Snowflake์—์„œ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜๋Š” ๋™์ผํ•œ ๋ชจ๋“ˆ์˜ ๋‹ค๋ฅธ ํ•จ์ˆ˜ ๋˜๋Š” ๋‹ค๋ฅธ ๋ชจ๋“ˆ์˜ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํ•จ์ˆ˜(๋ฐ ํ•ด๋‹น ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœํ•˜๋Š” ๋ชจ๋“  ํ•จ์ˆ˜)๋Š” Python UDF์— ๋Œ€ํ•ด Snowflake๊ฐ€ ๋ถ€๊ณผํ•œ ์ œ์•ฝ ์กฐ๊ฑด ์„ ์ค€์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ 

๋ฒกํ„ฐํ™”๋œ Python UDF๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž…๋ ฅ ํ–‰ ๋ฐฐ์น˜๋ฅผ Pandas DataFrames ๋กœ ์ˆ˜์‹ ํ•˜๊ณ  ๊ฒฐ๊ณผ ๋ฐฐ์น˜๋ฅผ Pandas ๋ฐฐ์—ด ๋˜๋Š” Series ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” Python ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ฒกํ„ฐํ™”๋œ Python UDF ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

Snowflake์—์„œ ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐยถ

๋‹ค์Œ์„ ์ง€์ •ํ•˜๋ ค๋ฉด CREATE FUNCTION ๋ฌธ์„ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • UDF์— ์‚ฌ์šฉํ•  ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.

  • Python UDF๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ํ˜ธ์ถœํ•  Python ํ•จ์ˆ˜์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.

UDF์˜ ์ด๋ฆ„์€ Python์œผ๋กœ ์ž‘์„ฑ๋œ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜์˜ ์ด๋ฆ„๊ณผ ์ผ์น˜ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. CREATE FUNCTION ๋ฌธ์˜ HANDLER ์ ˆ์€ UDF ์ด๋ฆ„์„ Python ํ•จ์ˆ˜์™€ ์—ฐ๊ด€์‹œํ‚ต๋‹ˆ๋‹ค.

UDF์˜ ์ด๋ฆ„์„ ์„ ํƒํ•  ๋•Œ ํ”„๋กœ์‹œ์ €์™€ UDF์˜ ๋ช…๋ช… ๋ฐ ์˜ค๋ฒ„๋กœ๋”ฉ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

CREATE FUNCTION ๋ฌธ์˜ ๋ณธ๋ฌธ ๋‚ด์—์„œ ํ•จ์ˆ˜ ์ธ์ž๋Š” ์ด๋ฆ„์ด ์•„๋‹Œ ์œ„์น˜๋กœ ๋ฐ”์ธ๋”ฉ๋ฉ๋‹ˆ๋‹ค. CREATE FUNCTION ๋ฌธ์—์„œ ์„ ์–ธ๋œ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” Python ํ•จ์ˆ˜์— ์ „๋‹ฌ๋œ ์ฒซ ๋ฒˆ์งธ ์ธ์ž์ž…๋‹ˆ๋‹ค.

์ธ์ž์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ SQL-Python ๋ฐ์ดํ„ฐ ํƒ€์ž… ๋งคํ•‘ ์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

runtime_version ์„ ์ฝ”๋“œ์—์„œ ํ•„์š”ํ•œ Python ๋Ÿฐํƒ€์ž„ ๋ฒ„์ „์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ง€์›๋˜๋Š” Python ๋ฒ„์ „์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • 3.9

  • 3.10

  • 3.11

  • 3.12

์ธ๋ผ์ธ ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š” UDFs์™€ ์Šคํ…Œ์ด์ง€์—์„œ ์—…๋กœ๋“œ๋œ ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š” UDFsยถ

Python UDF์— ๋Œ€ํ•œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์Šคํ…Œ์ด์ง€์—์„œ ์—…๋กœ๋“œ๋จ: CREATE FUNCTION ๋ฌธ์€ ์Šคํ…Œ์ด์ง€ ์—์„œ ๊ธฐ์กด Python ์†Œ์Šค ์ฝ”๋“œ์˜ ์œ„์น˜๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • ์ธ๋ผ์ธ: CREATE FUNCTION ๋ฌธ์€ Python ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

์ธ๋ผ์ธ Python UDF ๋งŒ๋“ค๊ธฐยถ

์ธ๋ผ์ธ UDF์˜ ๊ฒฝ์šฐ, CREATE FUNCTION ๋ฌธ์˜ ์ผ๋ถ€๋กœ์„œ Python ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ ๋ฌธ์€ ์ฃผ์–ด์ง„ ์ •์ˆ˜์— 1์„ ๋”ํ•˜๋Š” ์ธ๋ผ์ธ Python UDF๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

CREATE OR REPLACE FUNCTION addone(i INT)
  RETURNS INT
  LANGUAGE PYTHON
  RUNTIME_VERSION = '3.9'
  HANDLER = 'addone_py'
AS $$
def addone_py(i):
 return i+1
$$;
Copy

Python ์†Œ์Šค ์ฝ”๋“œ๋Š” AS ์ ˆ์— ์ง€์ •๋ฉ๋‹ˆ๋‹ค. ์†Œ์Šค ์ฝ”๋“œ๋Š” ์ž‘์€๋”ฐ์˜ดํ‘œ๋‚˜ ํ•œ ์Œ์˜ ๋‹ฌ๋Ÿฌ ๊ธฐํ˜ธ($$)๋กœ ๋ฌถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์†Œ์Šค ์ฝ”๋“œ์— ์ž‘์€๋”ฐ์˜ดํ‘œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ, ์ผ๋ฐ˜์ ์œผ๋กœ ์ด์ค‘ ๋‹ฌ๋Ÿฌ ๊ธฐํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค.

UDF๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

SELECT addone(10);
Copy

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

+------------+
| ADDONE(10) |
|------------|
|         11 |
+------------+

Python ์†Œ์Šค ์ฝ”๋“œ๋Š” ๋‘˜ ์ด์ƒ์˜ ๋ชจ๋“ˆ, ๊ทธ๋ฆฌ๊ณ  ํ•œ ๋ชจ๋“ˆ์— ๋‘˜ ์ด์ƒ์˜ ํ•จ์ˆ˜๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ HANDLER ์ ˆ์€ ํ˜ธ์ถœํ•  ๋ชจ๋“ˆ๊ณผ ํ•จ์ˆ˜๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

์ธ๋ผ์ธ Python UDF๋Š” IMPORTS ์ ˆ์— ํฌํ•จ๋œ ๋ชจ๋“ˆ์˜ ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CREATE FUNCTION ๋ฌธ์˜ ๊ตฌ๋ฌธ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ CREATE FUNCTION ์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

๋” ๋งŽ์€ ์˜ˆ์ œ๋Š” ์ธ๋ผ์ธ Python UDF ์˜ˆ์ œ ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์Šคํ…Œ์ด์ง€์—์„œ ์—…๋กœ๋“œ๋œ ์ฝ”๋“œ๋กœ Python UDF ๋งŒ๋“ค๊ธฐยถ

๋‹ค์Œ ๋ฌธ์€ ์Šคํ…Œ์ด์ง€ ์—์„œ ์—…๋กœ๋“œ๋œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•œ Python UDF๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํŒŒ์ผ์„ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” ์Šคํ…Œ์ด์ง€๋Š” UDF ์†Œ์œ ์ž ๊ฐ€ ์ฝ์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ZIP ํŒŒ์ผ์ด ์ž์ฒด ํฌํ•จ๋˜์–ด์•ผ ํ•˜๋ฉฐ ์‹คํ–‰ํ•  ์ถ”๊ฐ€ ์„ค์ • ์Šคํฌ๋ฆฝํŠธ์— ์˜์กดํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์†Œ์Šค ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋œ sleepy.py ๋ผ๋Š” Python ํŒŒ์ผ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งŒ๋“ญ๋‹ˆ๋‹ค.

def snore(n):   # return a series of n snores
  result = []
  for a in range(n):
    result.append("Zzz")
  return result
Copy

SnowSQL(CLI ํด๋ผ์ด์–ธํŠธ) ๋ฅผ ์‹œ์ž‘ํ•˜๊ณ  PUT ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ์ผ์„ ๋กœ์ปฌ ํŒŒ์ผ ์‹œ์Šคํ…œ์—์„œ @~ ๋ผ๋Š” ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์Šคํ…Œ์ด์ง€๋กœ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. (PUT ๋ช…๋ น์€ Snowflake GUI๋ฅผ ํ†ตํ•ด ์‹คํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.)

put
file:///Users/Me/sleepy.py
@~/
auto_compress = false
overwrite = true
;
Copy

ํŒŒ์ผ์„ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ์ด๋ฆ„์„ ๋ฐ”๊พธ๋ฉด ๋” ์ด์ƒ UDF๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ์„ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” UDF๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋Š” ๋™์•ˆ ์—…๋ฐ์ดํŠธํ•˜์‹ญ์‹œ์˜ค. ์ด์ „ ํŒŒ์ผ์ด ์•„์ง ์Šคํ…Œ์ด์ง€์— ์žˆ๋Š” ๊ฒฝ์šฐ, PUT ๋ช…๋ น์— OVERWRITE=TRUE ์ ˆ์ด ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

UDF๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ด ํ•ธ๋“ค๋Ÿฌ๋Š” ๋ชจ๋“ˆ๊ณผ ํ•จ์ˆ˜๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

CREATE OR REPLACE FUNCTION dream(i INT)
  RETURNS VARIANT
  LANGUAGE PYTHON
  RUNTIME_VERSION = '3.9'
  HANDLER = 'sleepy.snore'
  IMPORTS = ('@~/sleepy.py')
Copy

UDF๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

SELECT dream(3);
Copy
+----------+
| DREAM(3) |
|----------|
| [        |
|   "Zzz", |
|   "Zzz", |
|   "Zzz"  |
| ]        |
+----------+

์—ฌ๋Ÿฌ ๊ฐ€์ ธ์˜ค๊ธฐ ํŒŒ์ผ ์ง€์ •ํ•˜๊ธฐยถ

๋‹ค์Œ์€ ์—ฌ๋Ÿฌ ๊ฐ€์ ธ์˜ค๊ธฐ ํŒŒ์ผ์„ ์ง€์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

CREATE OR REPLACE FUNCTION multiple_import_files(s STRING)
  RETURNS STRING
  LANGUAGE PYTHON
  RUNTIME_VERSION = 3.9
  IMPORTS = ('@python_udf_dep/bar/python_imports_a.zip', '@python_udf_dep/foo/python_imports_b.zip')
  HANDLER = 'compute'
AS $$
def compute(s):
  return s
$$;
Copy

์ฐธ๊ณ 

์ง€์ •๋œ ๊ฐ€์ ธ์˜ค๊ธฐ ํŒŒ์ผ ์ด๋ฆ„์€ ์„œ๋กœ ๋‹ฌ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด imports=('@python_udf_dep/bar/python_imports.zip', '@python_udf_dep/foo/python_imports.zip') ์€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜์— ๋Œ€ํ•œ ๊ถŒํ•œ ๋ถ€์—ฌํ•˜๊ธฐยถ

ํ•จ์ˆ˜ ์†Œ์œ ์ž ์ด์™ธ์˜ ์—ญํ• ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ ค๋ฉด ์†Œ์œ ์ž๊ฐ€ ์—ญํ• ์— ์ ์ ˆํ•œ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Python UDF์— ๋Œ€ํ•œ GRANT ๋ฌธ์€ JavaScript UDF์™€ ๊ฐ™์€ ๋‹ค๋ฅธ UDF์— ๋Œ€ํ•œ GRANT ๋ฌธ๊ณผ ๋ณธ์งˆ์ ์œผ๋กœ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ:

GRANT USAGE ON FUNCTION my_python_udf(number, number) TO my_role;
Copy