์ผ๋ฐ˜ Scala UDF ์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋”ฉ ์ง€์นจยถ

์ด ํ•ญ๋ชฉ์—์„œ๋Š” Scala์—์„œ ์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ์ง€์นจ์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์Šค์นผ๋ผ ํ•จ์ˆ˜ ์ฒ˜๋ฆฌ๊ธฐ์™€ ๊ด€๋ จ๋œ ์ •๋ณด๋Š” Scala๋กœ ์Šค์นผ๋ผ UDF ์ž‘์„ฑํ•˜๊ธฐ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐํ™”, ์ฝ”๋“œ ํŒจํ‚ค์ง•, ์ข…์†์„ฑ ๊ด€๋ฆฌ์— ๋Œ€ํ•œ ์ œ์•ˆ ์‚ฌํ•ญ์€ Scala UDF ์ฒ˜๋ฆฌ๊ธฐ ํ”„๋กœ์ ํŠธ ๋ฐ ํŒจํ‚ค์ง• ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

๋ชจ๋ฒ” ์‚ฌ๋ก€ยถ

  • ํ”Œ๋žซํผ ๋…๋ฆฝ์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์‹ญ์‹œ์˜ค.

    • ํŠน์ • CPU ์•„ํ‚คํ…์ฒ˜(์˜ˆ: x86)๋ฅผ ๊ฐ€์ •ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ํ”ผํ•˜์‹ญ์‹œ์˜ค.

    • ํŠน์ • ์šด์˜ ์ฒด์ œ๋ฅผ ๊ฐ€์ •ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ํ”ผํ•˜์‹ญ์‹œ์˜ค.

  • ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•˜์ง€๋งŒ, ํ˜ธ์ถœํ•˜๋Š” ๋ฉ”์„œ๋“œ์— ์ด๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋ฅผ ์ฒ˜๋ฆฌ๊ธฐ ํด๋ž˜์Šค์˜ ์ปดํŒจ๋‹ˆ์–ธ ์˜ค๋ธŒ์ ํŠธ์— ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ธ๋ผ์ธ ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ€๋Šฅํ•˜๋ฉด CREATE FUNCTION ๋˜๋Š” CREATE PROCEDURE TARGET_PATH ๋งค๊ฐœ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ง€์ •ํ•˜์‹ญ์‹œ์˜ค. ๊ทธ๋Ÿฌ๋ฉด ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ์ปดํŒŒ์ผํ•˜๋Š” ๋Œ€์‹  ์ด์ „์— ์ƒ์„ฑ๋œ ์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋“œ ์ถœ๋ ฅ์„ ์žฌ์‚ฌ์šฉํ•˜๋„๋ก Snowflake์— ์•Œ๋ ค์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ธ๋ผ์ธ ์ฒ˜๋ฆฌ๊ธฐ ์‚ฌ์šฉํ•˜๊ธฐ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ฒ˜๋ฆฌ๊ธฐ ์ž‘์„ฑํ•˜๊ธฐยถ

Scala๋กœ ์ž‘์„ฑ๋œ ์ฒ˜๋ฆฌ๊ธฐ๋กœ ์Šค์นผ๋ผ UDF๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฒ˜๋ฆฌ๊ธฐ๋Š” Scala UDF์— ์ „๋‹ฌ๋œ ๊ฐ ํ–‰์— ๋Œ€ํ•ด ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ํด๋ž˜์Šค์˜ ์ƒˆ ์ธ์Šคํ„ด์Šค๋Š” ๊ฐ ํ–‰์— ๋Œ€ํ•ด ๋งŒ๋“ค์–ด์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Snowflake๋Š” ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค์˜ ์ฒ˜๋ฆฌ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ๋‘ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ ์‹คํ–‰์„ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•ด, Snowflake ์ œํ•œ ์‹œ๊ฐ„ ์ž„๊ณ„๊ฐ’์€ ์ฒ˜๋ฆฌ๊ธฐ ํด๋ž˜์Šค ๋˜๋Š” ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„๊ณผ ์ฒ˜๋ฆฌ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค. Snowflake์—์„œ๋Š” ์ดˆ๊ธฐํ™”๊ฐ€ ๋” ์˜ค๋ž˜ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฐ€์ •ํ•˜์— ์ฒ˜๋ฆฌ๊ธฐ ํด๋ž˜์Šค ๋˜๋Š” ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•  ์‹œ๊ฐ„์„ ๋” ๋งŽ์ด ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” UDF๋ฅผ ๋กœ๋“œํ•˜๋Š” ์‹œ๊ฐ„, ๊ทธ๋ฆฌ๊ณ  ์ƒ์„ฑ์ž๊ฐ€ ์ •์˜๋œ ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ๊ธฐ ๋ฉ”์„œ๋“œ์˜ ํฌํ•จ ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹œ๊ฐ„์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

์˜ค๋ฅ˜ ์ฒ˜๋ฆฌยถ

์ผ๋ฐ˜์ ์ธ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊ธฐ์ˆ ๋กœ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ฒ˜๋ฆฌ๊ธฐ ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ ์˜ค๋ฅ˜๋ฅผ ํฌ์ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

์ฟผ๋ฆฌ๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  SQL ์˜ค๋ฅ˜๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ์™ธ๋ฅผ ํฌ์ฐฉํ•˜์ง€ ์•Š๊ณ  ๋ช…์‹œ์ ์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ:

if (x < 0) throw new IllegalArgumentException("x must be non-negative.")
Copy

๋””๋ฒ„๊น…ํ•  ๋•Œ SQL ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ…์ŠคํŠธ์— ๊ฐ’์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜์‹ญ์‹œ์˜ค.

  • ์ „์ฒด Scala ๋ฉ”์„œ๋“œ ๋ณธ๋ฌธ์„ try-catch ๋ธ”๋ก์— ๋„ฃ์Šต๋‹ˆ๋‹ค.

  • ํฌ์ฐฉ๋œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ์ธ์ž ๊ฐ’์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

  • ํ™•์žฅ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋…ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋ ค๋ฉด JAR ํŒŒ์ผ์„ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์— ๋ฐฐํฌํ•˜๊ธฐ ์ „์— ์ธ์ž ๊ฐ’์„ ์ œ๊ฑฐํ•˜์‹ญ์‹œ์˜ค.

๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒํ•˜๊ธฐยถ

์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ UDF์˜ ๋งค๊ฐœ ๋ณ€์ˆ˜ ๋ฐ ๋ฐ˜ํ™˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…(SQL์—์„œ)๊ณผ ์ž˜ ๋งคํ•‘๋˜๋Š” ๋งค๊ฐœ ๋ณ€์ˆ˜ ๋ฐ ๋ฐ˜ํ™˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…(์ฒ˜๋ฆฌ๊ธฐ ์–ธ์–ด์—์„œ)์„ ์„ ์–ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

UDF๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ Snowflake๋Š” UDF์˜ ์ธ์ž๋ฅผ SQL ๋งค๊ฐœ ๋ณ€์ˆ˜ ์œ ํ˜•์—์„œ ์ฒ˜๋ฆฌ๊ธฐ์˜ ๋งค๊ฐœ ๋ณ€์ˆ˜ ์œ ํ˜•์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ๋•Œ Snowflake๋Š” ๋ฐ˜ํ™˜ ๊ฐ’์„ ์ฒ˜๋ฆฌ๊ธฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์—์„œ UDF์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

Snowflake๋Š” SQL ์œ ํ˜•๊ณผ Scala ์œ ํ˜• ๊ฐ„์— ์ง€์›๋˜๋Š” ๋งคํ•‘์— ๋”ฐ๋ผ ์œ ํ˜• ๊ฐ„์— ๊ฐ’์„ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋งคํ•‘์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ SQL-Scala ๋ฐ์ดํ„ฐ ํƒ€์ž… ๋งคํ•‘ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

Scala ๋ณ€์ˆ˜์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์„ ํƒํ•  ๋•Œ Snowflake์—์„œ ์ „์†ก(๋ฐ ๋ฐ˜ํ™˜)๋  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ฐ€๋Šฅํ•œ ์ตœ๋Œ“๊ฐ’ ๋ฐ ์ตœ์†Ÿ๊ฐ’์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค.

CREATE FUNCTION ์œผ๋กœ UDF ๋งŒ๋“ค๊ธฐยถ

CREATE FUNCTION ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ SQL๋กœ UDF๋ฅผ ๋งŒ๋“ค์–ด ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ํ•ธ๋“ค๋Ÿฌ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ช…๋ น ์ฐธ์กฐ๋Š” CREATE FUNCTION ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

CREATE OR REPLACE FUNCTION <name> ( [ <arguments> ] )
  RETURNS <type>
  LANGUAGE SCALA
  [ IMPORTS = ( '<imports>' ) ]
  RUNTIME_VERSION = 2.12
  [ PACKAGES = ( '<package_name>' [, '<package_name>' . . .] ) ]
  [ TARGET_PATH = '<stage_path_and_file_name_to_write>' ]
  HANDLER = '<handler_class>.<handler_method>'
  [ AS '<scala_code>' ]
Copy

์ž‘์„ฑํ•œ ํ•ธ๋“ค๋Ÿฌ ์ฝ”๋“œ๋ฅผ UDF์™€ ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด CREATE FUNCTION ์‹คํ–‰ ์‹œ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜์‹ญ์‹œ์˜ค.

  • LANGUAGE๋ฅผ SCALA์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  • ํ•ธ๋“ค๋Ÿฌ ํด๋ž˜์Šค๊ฐ€ ์Šคํ…Œ์ด์ง€์™€ ๊ฐ™์€ ์™ธ๋ถ€ ์œ„์น˜์— ์žˆ๋Š” ๊ฒฝ์šฐ IMPORTS ์ ˆ ๊ฐ’์„ ํ•ธ๋“ค๋Ÿฌ ํด๋ž˜์Šค์˜ ๊ฒฝ๋กœ์™€ ์ด๋ฆ„์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  • RUNTIME_VERSION์„ ์ฝ”๋“œ์—์„œ ํ•„์š”ํ•œ Scala ๋Ÿฐํƒ€์ž„ ๋ฒ„์ „์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  • PACKAGES ์ ˆ ๊ฐ’์„ ํ•ธ๋“ค๋Ÿฌ ํด๋ž˜์Šค์— ํ•„์š”ํ•œ ํ•˜๋‚˜ ์ด์ƒ์˜ ํŒจํ‚ค์ง€(์žˆ๋Š” ๊ฒฝ์šฐ)์˜ ์ด๋ฆ„์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  • HANDLER ์ ˆ ๊ฐ’์„ ์ฒ˜๋ฆฌ๊ธฐ ์˜ค๋ธŒ์ ํŠธ์™€ ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  • ์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋“œ๊ฐ€ CREATE FUNCTION๊ณผ ํ•จ๊ป˜ ์ธ๋ผ์ธ์œผ๋กœ ์ง€์ •๋œ ๊ฒฝ์šฐ AS '<scala_code>' ์ ˆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.