Data Types
Data Types (데이터 타입)
Flink SQL은 사용자에게 풍부한 기본 데이터 타입 집합을 제공해요. 데이터 타입은 테이블 생태계에서 값의 논리적 유형을 나타내며, 연산의 입력/출력 타입을 선언하는 데 사용돼요.
출처: Data Types
본문
Data Type
데이터 타입은 테이블 생태계에서 값의 논리적 유형을 나타내요. 연산의 입력 및/또는 출력 타입을 선언하는 데 사용할 수 있어요.
Flink의 데이터 타입은 SQL 표준의 데이터 타입 용어와 비슷하지만, 스칼라 식을 효율적으로 처리하기 위해 값의 null 허용 여부에 대한 정보도 포함해요.
데이터 타입의 예는 다음과 같아요:
INTINT NOT NULLINTERVAL DAY TO SECOND(3)ROW<myField ARRAY<BOOLEAN>, myOtherField TIMESTAMP(3)>
모든 사전 정의 데이터 타입의 목록은 아래에서 확인할 수 있어요.
Table API의 데이터 타입
JVM 기반 API 사용자는 Table API에서 또는 커넥터, 카탈로그, 사용자 정의 함수를 정의할 때 org.apache.flink.table.types.DataType 인스턴스를 사용해요.
DataType 인스턴스는 두 가지 역할을 해요:
- 논리적 타입 선언 — 전송이나 저장을 위한 구체적인 물리적 표현을 의미하지 않지만, JVM 기반/Python 언어와 테이블 생태계 사이의 경계를 정의해요.
- 선택사항: 플래너에게 데이터의 물리적 표현에 대한 힌트 제공 — 다른 API와의 경계에서 유용해요.
JVM 기반 언어의 경우 모든 사전 정의 데이터 타입이 org.apache.flink.table.api.DataTypes에 있어요.
Python API 사용자는 Python Table API에서 또는 Python 사용자 정의 함수를 정의할 때 pyflink.table.types.DataType 인스턴스를 사용해요.
DataType 인스턴스는 다음과 같은 역할을 해요:
- 논리적 타입 선언 — 전송이나 저장을 위한 구체적인 물리적 표현을 의미하지 않지만, Python 언어와 테이블 생태계 사이의 경계를 정의해요.
Python 언어의 경우 해당 타입들은 pyflink.table.types.DataTypes에서 사용할 수 있어요.
"플루언트 API를 위해 테이블 프로그램에 star import를 추가하는 것이 권장돼요"라는 안내 표시 아래 예시 코드가 있어요:
import static org.apache.flink.table.api.DataTypes.*;
DataType t = INTERVAL(DAY(), SECOND(3));
import org.apache.flink.table.api.DataTypes._
val t: DataType = INTERVAL(DAY(), SECOND(3))
from pyflink.table.types import DataTypes
t = DataTypes.INTERVAL(DataTypes.DAY(), DataTypes.SECOND(3))
데이터 타입과 Python 타입 매핑
Python 사용자 정의 함수의 경우 입력은 데이터 타입에 해당하는 Python 객체로 변환되며, 사용자 정의 함수 결과의 타입도 정의된 데이터 타입과 일치해야 해요.
vectorized Python UDF의 경우 입력 타입과 출력 타입은 pandas.Series예요. pandas.Series의 요소 타입은 지정된 데이터 타입에 해당해요.
| Data Type | Python Type | Pandas Type |
|---|---|---|
BOOLEAN |
bool |
numpy.bool_ |
TINYINT |
int |
numpy.int8 |
SMALLINT |
int |
numpy.int16 |
INT |
int |
numpy.int32 |
BIGINT |
int |
numpy.int64 |
FLOAT |
float |
numpy.float32 |
DOUBLE |
float |
numpy.float64 |
VARCHAR |
str |
str |
VARBINARY |
bytes |
bytes |
DECIMAL |
decimal.Decimal |
decimal.Decimal |
DATE |
datetime.date |
datetime.date |
TIME |
datetime.time |
datetime.time |
TIMESTAMP |
datetime.datetime |
datetime.datetime |
TIMESTAMP_LTZ |
datetime.datetime |
datetime.datetime |
INTERVAL YEAR TO MONTH |
int |
Not supported |
INTERVAL DAY TO SECOND |
datetime.timedelta |
Not supported |
ARRAY |
list |
numpy.ndarray |
MULTISET |
list |
Not supported |
MAP |
dict |
Not supported |
ROW |
pyflink.common.Row |
dict |
물리적 힌트 (Physical Hints)
물리적 힌트는 SQL 기반 타입 시스템이 끝나고 프로그래밍 특화 데이터 타입이 필요한 테이블 생태계의 경계에서 필요해요. 힌트는 구현이 기대하는 데이터 형식을 나타내요.
예를 들어, 데이터 소스는 논리적 TIMESTAMP에 대한 값을 기본값인 java.time.LocalDateTime 대신 java.sql.Timestamp 클래스를 사용해 생성한다고 표현할 수 있어요. 이 정보로 런타임은 생성된 클래스를 내부 데이터 형식으로 변환할 수 있어요. 반대로 데이터 싱크는 런타임에서 소비하는 데이터 형식을 선언할 수 있어요.
bridging 변환 클래스를 선언하는 몇 가지 예시는 다음과 같아요:
// tell the runtime to not produce or consume java.time.LocalDateTime instances
// but java.sql.Timestamp
DataType t = DataTypes.TIMESTAMP(3).bridgedTo(java.sql.Timestamp.class);
// tell the runtime to not produce or consume boxed integer arrays
// but primitive int arrays
DataType t = DataTypes.ARRAY(DataTypes.INT().notNull()).bridgedTo(int[].class);
// tell the runtime to not produce or consume java.time.LocalDateTime instances
// but java.sql.Timestamp
val t: DataType = DataTypes.TIMESTAMP(3).bridgedTo(classOf[java.sql.Timestamp])
// tell the runtime to not produce or consume boxed integer arrays
// but primitive int arrays
val t: DataType = DataTypes.ARRAY(DataTypes.INT().notNull()).bridgedTo(classOf[Array[Int]])
Attention 물리적 힌트는 일반적으로 API가 확장되는 경우에만 필요하다는 점에 유의하세요. 사전 정의된 소스/싱크/함수를 사용하는 사용자는 그런 힌트를 정의할 필요가 없어요. 테이블 프로그램 내의 힌트(예: field.cast(TIMESTAMP(3).bridgedTo(Timestamp.class)))는 무시돼요.
List of Data Types (데이터 타입 목록)
이 섹션은 모든 사전 정의 데이터 타입을 나열해요.
JVM 기반 Table API의 경우 해당 타입들은 org.apache.flink.table.api.DataTypes에서도 사용할 수 있어요. Python Table API의 경우 pyflink.table.types.DataTypes에서 사용할 수 있어요.
기본 플래너는 다음 SQL 타입 집합을 지원해요:
| Data Type | Remarks for Data Type |
|---|---|
CHAR |
|
VARCHAR |
|
STRING |
|
BOOLEAN |
|
BINARY |
|
VARBINARY |
|
BYTES |
|
DECIMAL |
고정 정밀도와 스케일을 지원해요. |
DESCRIPTOR |
프로세스 테이블 함수(PTF)에서만 지원돼요. |
TINYINT |
|
SMALLINT |
|
INTEGER |
|
BIGINT |
|
FLOAT |
|
DOUBLE |
|
DATE |
|
TIME |
0 정밀도만 지원해요. |
TIMESTAMP |
|
TIMESTAMP_LTZ |
|
INTERVAL |
MONTH와 SECOND(3) 간격만 지원해요. |
ARRAY |
|
MULTISET |
|
MAP |
|
ROW |
|
RAW |
|
| Structured types | 아직 사용자 정의 함수에서만 노출돼요. |
VARIANT |
|
BITMAP |
문자 문자열 (Character Strings)
CHAR
고정 길이 문자 문자열의 데이터 타입이에요.
선언
CHAR
CHAR(n)
DataTypes.CHAR(n)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.lang.String |
X | X | Default |
byte[] |
X | X | UTF-8 인코딩을 가정해요. |
org.apache.flink.table.data.StringData |
X | X | 내부 데이터 구조. |
Not supported.
타입은 CHAR(n)으로 선언할 수 있는데, n은 코드 포인트 수예요. n은 1과 2,147,483,647 사이(양쪽 포함)의 값이어야 해요. 길이가 지정되지 않으면 n은 1과 같아요.
VARCHAR / STRING
가변 길이 문자 문자열의 데이터 타입이에요.
선언
VARCHAR
VARCHAR(n)
STRING
DataTypes.VARCHAR(n)
DataTypes.STRING()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.lang.String |
X | X | Default |
byte[] |
X | X | UTF-8 인코딩을 가정해요. |
org.apache.flink.table.data.StringData |
X | X | 내부 데이터 구조. |
DataTypes.VARCHAR(n)
DataTypes.STRING()
Attention DataTypes.VARCHAR(n)에 지정된 최대 코드 포인트 수 n은 현재 2,147,483,647이어야 해요.
타입은 VARCHAR(n)으로 선언할 수 있는데, n은 최대 코드 포인트 수예요. n은 1과 2,147,483,647 사이(양쪽 포함)의 값이어야 해요. 길이가 지정되지 않으면 n은 1과 같아요.
STRING은 VARCHAR(2147483647)의 동의어예요.
바이너리 문자열 (Binary Strings)
BINARY
고정 길이 바이너리 문자열(=바이트 시퀀스)의 데이터 타입이에요.
선언
BINARY
BINARY(n)
DataTypes.BINARY(n)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
byte[] |
X | X | Default |
Not supported.
타입은 BINARY(n)으로 선언할 수 있는데, n은 바이트 수예요. n은 1과 2,147,483,647 사이(양쪽 포함)의 값이어야 해요. 길이가 지정되지 않으면 n은 1과 같아요.
VARBINARY / BYTES
가변 길이 바이너리 문자열(=바이트 시퀀스)의 데이터 타입이에요.
선언
VARBINARY
VARBINARY(n)
BYTES
DataTypes.VARBINARY(n)
DataTypes.BYTES()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
byte[] |
X | X | Default |
DataTypes.VARBINARY(n)
DataTypes.BYTES()
Attention DataTypes.VARBINARY(n)에 지정된 최대 바이트 수 n은 현재 2,147,483,647이어야 해요.
타입은 VARBINARY(n)으로 선언할 수 있는데, n은 최대 바이트 수예요. n은 1과 2,147,483,647 사이(양쪽 포함)의 값이어야 해요. 길이가 지정되지 않으면 n은 1과 같아요.
BYTES는 VARBINARY(2147483647)의 동의어예요.
정확 수치 (Exact Numerics)
DECIMAL
고정 정밀도와 스케일을 가진 십진수의 데이터 타입이에요.
선언
DECIMAL
DECIMAL(p)
DECIMAL(p, s)
DEC
DEC(p)
DEC(p, s)
NUMERIC
NUMERIC(p)
NUMERIC(p, s)
DataTypes.DECIMAL(p, s)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.math.BigDecimal |
X | X | Default |
org.apache.flink.table.data.DecimalData |
X | X | 내부 데이터 구조. |
DataTypes.DECIMAL(p, s)
Attention DataTypes.DECIMAL(p, s)에 지정된 precision과 scale은 현재 각각 38과 18이어야 해요.
타입은 DECIMAL(p, s)으로 선언할 수 있는데, p는 숫자의 자릿수(precision)이고 s는 소수점 오른쪽 자릿수(scale)예요. p는 1과 38 사이(양쪽 포함)의 값이어야 해요. s는 0과 p 사이(양쪽 포함)의 값이어야 해요. p의 기본값은 10이에요. s의 기본값은 0이에요.
Note: 정밀도와 스케일의 정의는 SQL 표준과 Java의 BigDecimal 사이에서 일치하지 않아요. 예를 들어 정확한 값 0.011은 SQL에서 DECIMAL(4, 3)으로 취급되지만, BigDecimal 표현은 정밀도 2, 스케일 3이에요.
NUMERIC(p, s)와 DEC(p, s)는 이 타입의 동의어예요.
TINYINT
-128에서 127 사이의 값을 가진 1바이트 부호 있는 정수의 데이터 타입이에요.
선언
TINYINT
DataTypes.TINYINT()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.lang.Byte |
X | X | Default |
byte |
X | (X) | 타입이 nullable이 아닐 때만 출력. |
DataTypes.TINYINT()
SMALLINT
-32,768에서 32,767 사이의 값을 가진 2바이트 부호 있는 정수의 데이터 타입이에요.
선언
SMALLINT
DataTypes.SMALLINT()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.lang.Short |
X | X | Default |
short |
X | (X) | 타입이 nullable이 아닐 때만 출력. |
DataTypes.SMALLINT()
INT
-2,147,483,648에서 2,147,483,647 사이의 값을 가진 4바이트 부호 있는 정수의 데이터 타입이에요.
선언
INT
INTEGER
DataTypes.INT()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.lang.Integer |
X | X | Default |
int |
X | (X) | 타입이 nullable이 아닐 때만 출력. |
DataTypes.INT()
INTEGER는 이 타입의 동의어예요.
BIGINT
-9,223,372,036,854,775,808에서 9,223,372,036,854,775,807 사이의 값을 가진 8바이트 부호 있는 정수의 데이터 타입이에요.
선언
BIGINT
DataTypes.BIGINT()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.lang.Long |
X | X | Default |
long |
X | (X) | 타입이 nullable이 아닐 때만 출력. |
DataTypes.BIGINT()
근사 수치 (Approximate Numerics)
FLOAT
4바이트 단정밀도 부동소수점 숫자의 데이터 타입이에요.
SQL 표준과 달리 이 타입은 매개변수를 받지 않아요.
선언
FLOAT
DataTypes.FLOAT()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.lang.Float |
X | X | Default |
float |
X | (X) | 타입이 nullable이 아닐 때만 출력. |
DataTypes.FLOAT()
DOUBLE
8바이트 배정밀도 부동소수점 숫자의 데이터 타입이에요.
선언
DOUBLE
DOUBLE PRECISION
DataTypes.DOUBLE()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.lang.Double |
X | X | Default |
double |
X | (X) | 타입이 nullable이 아닐 때만 출력. |
DataTypes.DOUBLE()
DOUBLE PRECISION은 이 타입의 동의어예요.
날짜와 시간 (Date and Time)
DATE
0000-01-01에서 9999-12-31 사이의 값을 가진 year-month-day로 구성된 날짜의 데이터 타입이에요.
SQL 표준과 달리 범위는 연도 0000에서 시작해요.
선언
DATE
DataTypes.DATE()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.time.LocalDate |
X | X | Default |
java.sql.Date |
X | X | |
java.lang.Integer |
X | X | epoch 이후 일수. |
int |
X | (X) | epoch 이후 일수. 타입이 nullable이 아닐 때만 출력. |
DataTypes.DATE()
TIME
hour:minute:second[.fractional]로 구성되고 최대 나노초 정밀도를 가지며 00:00:00.000000000에서 23:59:59.999999999 사이의 값을 가진 시간대 없는 시간의 데이터 타입이에요.
SQL 표준과 달리 윤초(23:59:60과 23:59:61)는 지원되지 않는데, 이는 의미론이 java.time.LocalTime에 더 가깝기 때문이에요. 시간대 있는 시간은 제공되지 않아요.
선언
TIME
TIME(p)
DataTypes.TIME(p)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.time.LocalTime |
X | X | Default |
java.sql.Time |
X | X | |
java.lang.Integer |
X | X | 하루의 밀리초 수. |
int |
X | (X) | 하루의 밀리초 수. 타입이 nullable이 아닐 때만 출력. |
java.lang.Long |
X | X | 하루의 나노초 수. |
long |
X | (X) | 하루의 나노초 수. 타입이 nullable이 아닐 때만 출력. |
DataTypes.TIME(p)
Attention DataTypes.TIME(p)에 지정된 precision은 현재 0이어야 해요.
타입은 TIME(p)으로 선언할 수 있는데, p는 소수 초의 자릿수(precision)예요. p는 0과 9 사이(양쪽 포함)의 값이어야 해요. 정밀도가 지정되지 않으면 p는 0과 같아요.
TIMESTAMP
year-month-day hour:minute:second[.fractional]로 구성되고 최대 나노초 정밀도를 가지며 0000-01-01 00:00:00.000000000에서 9999-12-31 23:59:59.999999999 사이의 값을 가진 시간대 없는 타임스탬프의 데이터 타입이에요.
SQL 표준과 달리 윤초(23:59:60과 23:59:61)는 지원되지 않는데, 이는 의미론이 java.time.LocalDateTime에 더 가깝기 때문이에요.
BIGINT(JVM long 타입)로/로부터의 변환은 시간대를 의미하므로 지원되지 않아요. 하지만 이 타입은 시간대 자유예요. 더 java.time.Instant와 같은 의미론이 필요하면 TIMESTAMP_LTZ를 사용하세요.
선언
TIMESTAMP
TIMESTAMP(p)
TIMESTAMP WITHOUT TIME ZONE
TIMESTAMP(p) WITHOUT TIME ZONE
DataTypes.TIMESTAMP(p)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.time.LocalDateTime |
X | X | Default |
java.sql.Timestamp |
X | X | |
org.apache.flink.table.data.TimestampData |
X | X | 내부 데이터 구조. |
DataTypes.TIMESTAMP(p)
Attention DataTypes.TIMESTAMP(p)에 지정된 precision은 현재 3이어야 해요.
타입은 TIMESTAMP(p)으로 선언할 수 있는데, p는 소수 초의 자릿수(precision)예요. p는 0과 9 사이(양쪽 포함)의 값이어야 해요. 정밀도가 지정되지 않으면 p는 6과 같아요.
TIMESTAMP(p) WITHOUT TIME ZONE은 이 타입의 동의어예요.
TIMESTAMP WITH TIME ZONE
year-month-day hour:minute:second[.fractional] zone으로 구성되고 최대 나노초 정밀도를 가지며 0000-01-01 00:00:00.000000000 +14:59에서 9999-12-31 23:59:59.999999999 -14:59 사이의 값을 가진 시간대 있는 타임스탬프의 데이터 타입이에요.
SQL 표준과 달리 윤초(23:59:60과 23:59:61)는 지원되지 않는데, 이는 의미론이 java.time.OffsetDateTime에 더 가깝기 때문이에요.
TIMESTAMP_LTZ와 달리 시간대 오프셋 정보는 모든 데이터에 물리적으로 저장돼요. 모든 계산, 시각화 또는 외부 시스템과의 통신에 개별적으로 사용돼요.
선언
TIMESTAMP WITH TIME ZONE
TIMESTAMP(p) WITH TIME ZONE
DataTypes.TIMESTAMP_WITH_TIME_ZONE(p)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.time.OffsetDateTime |
X | X | Default |
java.time.ZonedDateTime |
X | 존 ID를 무시해요. |
Not supported.
타입은 TIMESTAMP(p) WITH TIME ZONE으로 선언할 수 있는데, p는 소수 초의 자릿수(precision)예요. p는 0과 9 사이(양쪽 포함)의 값이어야 해요. 정밀도가 지정되지 않으면 p는 6과 같아요.
TIMESTAMP_LTZ
year-month-day hour:minute:second[.fractional] zone으로 구성되고 최대 나노초 정밀도를 가지며 0000-01-01 00:00:00.000000000 +14:59에서 9999-12-31 23:59:59.999999999 -14:59 사이의 값을 가진 로컬 시간대가 있는 타임스탬프의 데이터 타입이에요.
윤초(23:59:60과 23:59:61)는 의미론이 java.time.OffsetDateTime에 더 가깝기 때문에 지원되지 않아요.
TIMESTAMP WITH TIME ZONE과 달리 시간대 오프셋 정보는 모든 데이터에 물리적으로 저장되지 않아요. 대신 이 타입은 테이블 생태계의 경계에서 UTC 시간대의 java.time.Instant 의미론을 가정해요. 모든 데이터는 계산과 시각화를 위해 현재 세션에 구성된 로컬 시간대로 해석돼요.
이 타입은 구성된 세션 시간대에 따라 UTC 타임스탬프를 해석할 수 있게 함으로써, 시간대 자유 타임스탬프 타입과 시간대 필수 타임스탬프 타입 사이의 간극을 메워요.
선언
TIMESTAMP_LTZ
TIMESTAMP_LTZ(p)
TIMESTAMP WITH LOCAL TIME ZONE
TIMESTAMP(p) WITH LOCAL TIME ZONE
DataTypes.TIMESTAMP_LTZ(p)
DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(p)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.time.Instant |
X | X | Default |
java.lang.Integer |
X | X | epoch 이후 초 수. |
int |
X | (X) | epoch 이후 초 수. 타입이 nullable이 아닐 때만 출력. |
java.lang.Long |
X | X | epoch 이후 밀리초 수. |
long |
X | (X) | epoch 이후 밀리초 수. 타입이 nullable이 아닐 때만 출력. |
java.sql.Timestamp |
X | X | epoch 이후 밀리초 수. |
org.apache.flink.table.data.TimestampData |
X | X | 내부 데이터 구조. |
DataTypes.TIMESTAMP_LTZ(p)
DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(p)
Attention DataTypes.TIMESTAMP_LTZ(p)에 지정된 precision은 현재 3이어야 해요.
타입은 TIMESTAMP_LTZ(p)으로 선언할 수 있는데, p는 소수 초의 자릿수(precision)예요. p는 0과 9 사이(양쪽 포함)의 값이어야 해요. 정밀도가 지정되지 않으면 p는 6과 같아요.
TIMESTAMP(p) WITH LOCAL TIME ZONE은 이 타입의 동의어예요.
INTERVAL YEAR TO MONTH
year-month 인터벌 타입 그룹의 데이터 타입이에요.
타입은 다음 해상도 중 하나로 매개변수화되어야 해요:
- 년 단위 인터벌,
- 년에서 월까지의 인터벌,
- 또는 월 단위 인터벌.
year-month 인터벌은 +years-months로 구성되고 -9999-11에서 +9999-11 사이의 값을 가져요.
값 표현은 모든 해상도 타입에서 동일해요. 예를 들어 50의 월 인터벌은 항상 (기본 연도 정밀도를 가진) year-to-month 인터벌 형식으로 표현돼요: +04-02.
선언
INTERVAL YEAR
INTERVAL YEAR(p)
INTERVAL YEAR(p) TO MONTH
INTERVAL MONTH
DataTypes.INTERVAL(DataTypes.YEAR())
DataTypes.INTERVAL(DataTypes.YEAR(p))
DataTypes.INTERVAL(DataTypes.YEAR(p), DataTypes.MONTH())
DataTypes.INTERVAL(DataTypes.MONTH())
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.time.Period |
X | X | days 부분을 무시해요. Default |
java.lang.Integer |
X | X | 월 수. |
int |
X | (X) | 월 수. 타입이 nullable이 아닐 때만 출력. |
DataTypes.INTERVAL(DataTypes.YEAR())
DataTypes.INTERVAL(DataTypes.YEAR(p))
DataTypes.INTERVAL(DataTypes.YEAR(p), DataTypes.MONTH())
DataTypes.INTERVAL(DataTypes.MONTH())
타입은 위 조합으로 선언할 수 있는데, p는 연도의 자릿수(year precision)예요. p는 1과 4 사이(양쪽 포함)의 값이어야 해요. year precision이 지정되지 않으면 p는 2와 같아요.
INTERVAL DAY TO SECOND
day-time 인터벌 타입 그룹의 데이터 타입이에요.
타입은 최대 나노초 정밀도로 다음 해상도 중 하나로 매개변수화되어야 해요:
- 일 단위 인터벌,
- 일에서 시까지 인터벌,
- 일에서 분까지 인터벌,
- 일에서 초까지 인터벌,
- 시 단위 인터벌,
- 시에서 분까지 인터벌,
- 시에서 초까지 인터벌,
- 분 단위 인터벌,
- 분에서 초까지 인터벌,
- 또는 초 단위 인터벌.
day-time 인터벌은 +days hours:months:seconds.fractional로 구성되고 -999999 23:59:59.999999999에서 +999999 23:59:59.999999999 사이의 값을 가져요. 값 표현은 모든 해상도 타입에서 동일해요. 예를 들어 70의 초 인터벌은 항상 (기본 정밀도를 가진) days-to-seconds 인터벌 형식으로 표현돼요: +00 00:01:10.000000.
선언
INTERVAL DAY
INTERVAL DAY(p1)
INTERVAL DAY(p1) TO HOUR
INTERVAL DAY(p1) TO MINUTE
INTERVAL DAY(p1) TO SECOND(p2)
INTERVAL HOUR
INTERVAL HOUR TO MINUTE
INTERVAL HOUR TO SECOND(p2)
INTERVAL MINUTE
INTERVAL MINUTE TO SECOND(p2)
INTERVAL SECOND
INTERVAL SECOND(p2)
DataTypes.INTERVAL(DataTypes.DAY())
DataTypes.INTERVAL(DataTypes.DAY(p1))
DataTypes.INTERVAL(DataTypes.DAY(p1), DataTypes.HOUR())
DataTypes.INTERVAL(DataTypes.DAY(p1), DataTypes.MINUTE())
DataTypes.INTERVAL(DataTypes.DAY(p1), DataTypes.SECOND(p2))
DataTypes.INTERVAL(DataTypes.HOUR())
DataTypes.INTERVAL(DataTypes.HOUR(), DataTypes.MINUTE())
DataTypes.INTERVAL(DataTypes.HOUR(), DataTypes.SECOND(p2))
DataTypes.INTERVAL(DataTypes.MINUTE())
DataTypes.INTERVAL(DataTypes.MINUTE(), DataTypes.SECOND(p2))
DataTypes.INTERVAL(DataTypes.SECOND())
DataTypes.INTERVAL(DataTypes.SECOND(p2))
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.time.Duration |
X | X | Default |
java.lang.Long |
X | X | 밀리초 수. |
long |
X | (X) | 밀리초 수. 타입이 nullable이 아닐 때만 출력. |
DataTypes.INTERVAL(DataTypes.DAY())
DataTypes.INTERVAL(DataTypes.DAY(p1))
DataTypes.INTERVAL(DataTypes.DAY(p1), DataTypes.HOUR())
DataTypes.INTERVAL(DataTypes.DAY(p1), DataTypes.MINUTE())
DataTypes.INTERVAL(DataTypes.DAY(p1), DataTypes.SECOND(p2))
DataTypes.INTERVAL(DataTypes.HOUR())
DataTypes.INTERVAL(DataTypes.HOUR(), DataTypes.MINUTE())
DataTypes.INTERVAL(DataTypes.HOUR(), DataTypes.SECOND(p2))
DataTypes.INTERVAL(DataTypes.MINUTE())
DataTypes.INTERVAL(DataTypes.MINUTE(), DataTypes.SECOND(p2))
DataTypes.INTERVAL(DataTypes.SECOND())
DataTypes.INTERVAL(DataTypes.SECOND(p2))
타입은 위 조합으로 선언할 수 있는데, p1은 일의 자릿수(day precision)이고 p2는 소수 초의 자릿수(fractional precision)예요. p1은 1과 6 사이(양쪽 포함)의 값이어야 해요. p2는 0과 9 사이(양쪽 포함)의 값이어야 해요. p1이 지정되지 않으면 기본적으로 2와 같아요. p2가 지정되지 않으면 기본적으로 6과 같아요.
구성 데이터 타입 (Constructed Data Types)
ARRAY
같은 하위 타입을 가진 요소의 배열 데이터 타입이에요.
SQL 표준과 달리 배열의 최대 카디널리티는 지정할 수 없고 2,147,483,647으로 고정돼요. 또한 모든 유효한 타입이 하위 타입으로 지원돼요.
선언
ARRAY<t>
t ARRAY
DataTypes.ARRAY(t)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
t[] |
(X) | (X) | 하위 타입에 따라 다름. Default |
java.util.List<t> |
X | X | |
subclass of java.util.List<t> |
X | ||
org.apache.flink.table.data.ArrayData |
X | X | 내부 데이터 구조. |
DataTypes.ARRAY(t)
타입은 ARRAY<t>으로 선언할 수 있는데, t는 포함된 요소의 데이터 타입이에요.
t ARRAY는 SQL 표준에 더 가까운 동의어예요. 예를 들어 INT ARRAY는 ARRAY<INT>와 동일해요.
MAP
키(NULL 포함)를 값(NULL 포함)에 매핑하는 연관 배열의 데이터 타입이에요. 맵은 중복 키를 포함할 수 없고, 각 키는 최대 하나의 값에 매핑돼요.
요소 타입에 제한은 없어요. 고유성을 보장하는 것은 사용자의 책임이에요.
맵 타입은 SQL 표준의 확장이에요.
선언
MAP<kt, vt>
DataTypes.MAP(kt, vt)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.util.Map<kt, vt> |
X | X | Default |
subclass of java.util.Map<kt, vt> |
X | ||
org.apache.flink.table.data.MapData |
X | X | 내부 데이터 구조. |
DataTypes.MAP(kt, vt)
타입은 MAP<kt, vt>으로 선언할 수 있는데, kt는 키 요소의 데이터 타입이고 vt는 값 요소의 데이터 타입이에요.
MULTISET
멀티셋(=가방)의 데이터 타입이에요. 집합과 달리 공통 하위 타입을 가진 각 요소에 대해 여러 인스턴스를 허용해요. 각 고유 값(NULL 포함)은 어떤 다중도에 매핑돼요.
요소 타입에 제한은 없어요. 고유성을 보장하는 것은 사용자의 책임이에요.
선언
MULTISET<t>
t MULTISET
DataTypes.MULTISET(t)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.util.Map<t, java.lang.Integer> |
X | X | 각 값을 정수 다중도에 할당해요. Default |
subclass of java.util.Map<t, java.lang.Integer>> |
X | ||
org.apache.flink.table.data.MapData |
X | X | 내부 데이터 구조. |
DataTypes.MULTISET(t)
타입은 MULTISET<t>으로 선언할 수 있는데, t는 포함된 요소의 데이터 타입이에요.
t MULTISET는 SQL 표준에 더 가까운 동의어예요. 예를 들어 INT MULTISET는 MULTISET<INT>와 동일해요.
ROW
필드 시퀀스의 데이터 타입이에요.
필드는 필드 이름, 필드 타입, 선택적 설명으로 구성돼요. 테이블의 행의 가장 특정한 타입은 행 타입이에요. 이 경우 행의 각 열은 열과 같은 서수 위치를 가진 행 타입의 필드에 대응해요.
SQL 표준과 달리 선택적 필드 설명은 복잡한 구조를 다루기 쉽게 해줘요.
행 타입은 다른 비표준 준수 프레임워크에서 알려진 STRUCT 타입과 비슷해요.
선언
ROW<n0 t0, n1 t1, ...>
ROW<n0 t0 'd0', n1 t1 'd1', ...>
ROW(n0 t0, n1 t1, ...)
ROW(n0 t0 'd0', n1 t1 'd1', ...)
DataTypes.ROW(DataTypes.FIELD(n0, t0), DataTypes.FIELD(n1, t1), ...)
DataTypes.ROW(DataTypes.FIELD(n0, t0, d0), DataTypes.FIELD(n1, t1, d1), ...)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
org.apache.flink.types.Row |
X | X | Default |
org.apache.flink.table.data.RowData |
X | X | 내부 데이터 구조. |
DataTypes.ROW([DataTypes.FIELD(n0, t0), DataTypes.FIELD(n1, t1), ...])
DataTypes.ROW([DataTypes.FIELD(n0, t0, d0), DataTypes.FIELD(n1, t1, d1), ...])
타입은 ROW<n0 t0 'd0', n1 t1 'd1', ...>으로 선언할 수 있는데, n은 필드의 고유 이름, t는 필드의 논리적 타입, d는 필드의 설명이에요.
ROW(...)는 SQL 표준에 더 가까운 동의어예요. 예를 들어 ROW(myField INT, myOtherField BOOLEAN)은 ROW<myField INT, myOtherField BOOLEAN>과 동일해요.
사용자 정의 데이터 타입 (User-Defined Data Types)
STRUCTURED
사용자 정의 객체의 데이터 타입이에요.
"구조 유사" 타입으로 간주될 수 있는 ROW와 달리 구조화 타입은 같은 필드 집합을 포함하더라도 구별할 수 있어요. 예를 들어 Visit(amount DOUBLE)은 식별자 때문에 Interaction(amount DOUBLE)과 다르답니다.
객체 지향 프로그래밍 언어의 클래스와 비슷하게 구조화 타입은 클래스 이름으로 식별되며 0개, 하나 이상의 속성을 포함해요. 각 속성은 이름, 타입, 선택적 설명을 가져요. 타입은 속성 타입 중 하나가 (전이적으로) 자신을 참조하는 방식으로 정의될 수 없어요.
구조화 타입은 시스템에 의해 내부적으로 적절한 데이터 구조로 변환돼요. 직렬화와 동등성 검사는 논리적 타입을 기반으로 시스템이 관리해요.
STRUCTURED<'c', n0 t0, n1 t1, ...>
STRUCTURED<'c', n0 t0, n1 t1 'd1', ...>
타입은 STRUCTURED<'c', n0 t0 'd0', n1 t1 'd1', ...>으로 선언할 수 있는데, c는 클래스 이름, n은 필드의 고유 이름, t는 필드의 논리적 타입, d는 필드의 선택적 설명이에요.
보통 구조화 타입은 인라인으로 정의되며 해당 구현 클래스에서 리플렉션으로 추출할 수 있어요. 예를 들어 함수의 eval() 메서드 시그니처에서 그런 방식이에요. 이는 테이블 프로그램을 프로그래밍 방식으로 정의할 때 유용해요. 데이터 타입의 스키마를 수동으로 다시 정의하지 않고 기존 JVM 클래스를 재사용할 수 있게 해주거든요.
클래스 이름이 클래스패스의 클래스와 일치하면 시스템은 테이블 생태계 경계에서 구조화 객체를 JVM 객체로 변환해요 (예: 함수나 커넥터에 bridging할 때). 구현 클래스는 0-인자 생성자 또는 모든 속성을 할당하는 전체 생성자를 제공해야 해요.
하지만 클래스 이름은 클래스패스에서 확인할 필요가 없고, 동일한 속성 집합을 가진 객체를 구별하는 데만 사용될 수 있어요. 그러나 Table API와 UDF 호출에서 시스템은 클래스 이름을 실제 구현 클래스로 확인하려 시도해요. 확인이 실패하면 Row가 폴백으로 사용돼요.
구현 클래스가 다음 요구 사항을 충족하면 일반 POJO(Plain Old Java Objects)에서 인라인 구조화 타입을 만들 수 있어요:
- 클래스는 전역적으로 접근 가능해야 하는데, 즉
public,static,abstract가 아니어야 해요. - 클래스는 0-인자 기본 생성자 또는 모든 필드를 할당하는 전체 생성자를 제공해야 해요.
- 클래스의 모든 필드는
public선언 또는getField(),isField(),field()같은 일반적인 코딩 스타일을 따르는 getter로 읽을 수 있어야 해요. - 클래스의 모든 필드는
public선언, 완전 할당 생성자 또는setField(...),field(...)같은 일반적인 코딩 스타일을 따르는 setter로 쓸 수 있어야 해요. - 모든 필드는 리플렉션 추출을 통해 암시적으로 또는
@DataTypeHintannotations를 사용해 명시적으로 데이터 타입에 매핑되어야 해요. static또는transient로 선언된 필드는 무시돼요.
리플렉션 추출은 필드 타입이 (전이적으로) 자신을 참조하지 않는 한 필드의 임의 중첩을 지원해요.
선언된 필드 클래스(예: public int age;)는 이 문서에서 모든 데이터 타입에 대해 정의된 지원되는 JVM bridging 클래스 목록에 포함되어야 해요 (예: INT에 대한 java.lang.Integer 또는 int).
일부 클래스의 경우 클래스를 데이터 타입에 매핑하려면 어노테이션이 필요해요 (예: java.math.BigDecimal에 고정 정밀도와 스케일을 할당하는 @DataTypeHint("DECIMAL(10, 2)")).
선언
구조화 타입은 보통 구현 클래스를 통해 선언돼요:
// A simple POJO that qualifies as a structured type.
// Note: Without a fully assigning constructor, the order of fields will be alphabetical.
// The final data type will be:
// STRUCTURED<'com.myorg.Customer', active BOOLEAN, id INT NOT NULL, name STRING, properties MAP<STRING, STRING>>
class Customer {
public int id;
public String name;
public Map<String, String> properties;
public boolean active;
}
// A POJO with a fully assigning constructor defining the field order.
// The final data type will be:
// STRUCTURED<'com.myorg.Customer', id INT NOT NULL, name STRING, properties MAP<STRING, STRING>, active BOOLEAN>
class Customer {
public int id;
public String name;
public Map<String, String> properties;
public boolean active;
public Customer(int id, String name, Map<String, String> properties, boolean active) {
this.id = id;
this.name = name;
this.properties = properties;
this.active = active;
}
}
// A POJO that uses the @DataTypeHint annotations for supporting the reflective extraction.
// The final data type will be:
// STRUCTURED<'com.myorg.Customer', age INT NOT NULL, modelClass RAW(...), name STRING, totalBalance DECIMAL(10, 2)>
class Customer {
// extract fields automatically
public int age;
public String name;
// enrich the extraction with precision information
public @DataTypeHint("DECIMAL(10, 2)") BigDecimal totalBalance;
// enrich the extraction with forcing using RAW types
public @DataTypeHint("RAW") Class<?> modelClass;
}
또는 명시적 선언을 통해:
// Provide an implementation class
DataTypes.STRUCTURED(MyPojo.class, DataTypes.FIELD(n0, t0), DataTypes.FIELD(n1, t1), ...);
// Provide a class name only, the class is resolved only if available in the classpath
DataTypes.STRUCTURED("com.myorg.MyPojo", DataTypes.FIELD(n0, t0), DataTypes.FIELD(n1, t1), ...);
// Full example
DataTypes.STRUCTURED(
Customer.class,
DataTypes.FIELD("age", DataTypes.INT().notNull()),
DataTypes.FIELD("name", DataTypes.STRING())
);
또는 명시적 추출을 통해:
DataTypes.of(Class);
// For example:
DataTypes.of(Customer.class);
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
| class | X | X | 원래 클래스 또는 하위 클래스(입력) 또는 상위 클래스(출력). Default |
org.apache.flink.types.Row |
X | X | 구조화 타입을 행으로 나타내요. |
org.apache.flink.table.data.RowData |
X | X | 내부 데이터 구조. |
Not supported.
기타 데이터 타입 (Other Data Types)
BOOLEAN
TRUE, FALSE, UNKNOWN의 (가능한) 삼값 논리를 가진 부울의 데이터 타입이에요.
선언
BOOLEAN
DataTypes.BOOLEAN()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.lang.Boolean |
X | X | Default |
boolean |
X | (X) | 타입이 nullable이 아닐 때만 출력. |
DataTypes.BOOLEAN()
DESCRIPTOR
임의의, 검증되지 않은 열 목록을 설명하기 위한 데이터 타입이에요.
이 타입은 DESCRIPTOR(`c0`, `c1`) 호출의 반환 타입이에요. 이 타입은 프로세스 테이블 함수(PTF)의 인자에 사용되도록 의도됐어요.
런타임은 이 타입을 지원하지 않아요. 이는 변환 및 플래닝 중의 순수 헬퍼 타입이에요. 테이블 열은 이 타입으로 선언될 수 없어요. 함수는 이 타입의 반환 타입을 선언할 수 없어요.
선언
DESCRIPTOR
DataTypes.DESCRIPTOR()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
org.apache.flink.types.ColumnList |
X | X | Default |
VARIANT
반구조화 데이터의 데이터 타입이에요.
이 타입은 ARRAY, MAP(STRING 타입의 키를 가진), 스칼라 타입을 포함한 모든 반구조화 데이터 저장을 지원해요. 필드의 데이터 타입은 데이터 구조에 저장되며, 이는 JSON의 의미론에 가까워요. ROW와 STRUCTURED 타입과 달리 VARIANT 타입은 고도로 중첩되고 진화하는 스키마를 지원할 수 있는 유연성을 가져요.
VARIANT는 배열 안의 배열, 맵 안의 맵, 또는 둘의 조합과 같은 깊게 중첩된 데이터 구조를 허용해요. 이 능력은 데이터 복잡성과 중첩이 중요한 시나리오에서 VARIANT를 이상적으로 만들어요.
VARIANT는 스키마 진화를 허용하므로, 사전 스키마 정의 없이 변경되거나 알 수 없는 스키마를 가진 데이터 저장을 가능하게 해요. 예를 들어 데이터에 새 필드가 추가되면 테이블 스키마를 수정하지 않고 VARIANT 데이터에 직접 통합할 수 있어요. 이는 스키마가 시간이 지남에 따라 진화할 수 있는 동적 환경에서 특히 유용해요.
선언
VARIANT
Variant 타입은 보통 PARSE_JSON 함수에 의해 생성돼요. 예를 들어:
SELECT PARSE_JSON('{"a":1,"b":["a","b","c"]}') AS v
DataTypes.VARIANT()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
org.apache.flink.types.variant.Variant |
X | X | Default |
BITMAP
RoaringBitmap을 사용해 32비트 정수를 압축된 형태로 저장하는 비트맵 데이터의 데이터 타입이에요.
비트맵 타입은 큰 정수 집합을 효율적으로 표현하고 쿼리하는 데 유용해요. 다양한 내장 [스칼라 함수]({{< ref "docs/sql/functions/built-in-functions" >}}#bitmap-functions)와 [집계 함수]({{< ref "docs/sql/functions/built-in-functions" >}}#bitmap-aggregate-functions)를 지원해요.
비트맵 타입은 SQL 표준의 확장이에요.
선언
BITMAP
비트맵 타입은 BITMAP_BUILD 함수를 사용해 ARRAY<INT>에서 만들 수 있어요. 예를 들어:
SELECT BITMAP_BUILD(ARRAY[1, 2, 3, 4, 5])
DataTypes.BITMAP()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
org.apache.flink.types.bitmap.Bitmap |
X | X | Default |
RAW
임의의 직렬화된 타입의 데이터 타입이에요. 이 타입은 테이블 생태계 내에서 블랙박스이며 경계에서만 역직렬화돼요.
raw 타입은 SQL 표준의 확장이에요.
선언
RAW('class', 'snapshot')
DataTypes.RAW(class, serializer)
DataTypes.RAW(class)
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
| class | X | X | 원래 클래스 또는 하위 클래스(입력) 또는 상위 클래스(출력). Default |
byte[] |
X | ||
org.apache.flink.table.data.RawValueData |
X | X | 내부 데이터 구조. |
Not supported.
타입은 RAW('class', 'snapshot')으로 선언할 수 있는데, class는 원래 클래스이고 snapshot은 Base64 인코딩된 직렬화된 TypeSerializerSnapshot이에요. 보통 타입 문자열은 직접 선언되지 않고 타입을 저장하는 동안 생성돼요.
API에서 RAW 타입은 Class + TypeSerializer를 직접 제공하거나 Class를 전달해 프레임워크가 거기서 Class + TypeSerializer를 추출하도록 하여 선언할 수 있어요.
NULL
유형 없는 NULL 값을 나타내기 위한 데이터 타입이에요.
null 타입은 SQL 표준의 확장이에요. null 타입은 NULL 외에 다른 값이 없으므로, JVM 의미론과 유사하게 모든 nullable 타입으로 캐스팅될 수 있어요.
이 타입은 NULL 리터럴을 사용하는 API 호출에서 알 수 없는 타입을 나타내는 데 도움이 되며, JSON이나 Avro와 같이 그런 타입을 정의하는 형식으로의 bridging에도 도움이 돼요.
이 타입은 실제로는 그다지 유용하지 않으며 완전성을 위해 여기서 언급할 뿐이에요.
선언
NULL
DataTypes.NULL()
JVM 타입으로의 Bridging
| Java Type | Input | Output | Remarks |
|---|---|---|---|
java.lang.Object |
X | X | Default |
| any class | (X) | 비원시 유형. |
Not supported.
Casting (캐스팅)
Flink Table API와 SQL은 정의된 input 타입과 target 타입 사이에서 캐스팅을 수행할 수 있어요. 일부 캐스팅 연산은 입력 값에 관계없이 항상 성공할 수 있지만, 다른 것은 런타임에 실패할 수 있어요 (즉, 대상 타입에 대한 값을 만들 방법이 없는 경우). 예를 들어 INT를 STRING으로 변환하는 것은 항상 가능하지만, STRING을 INT로 변환하는 것은 항상 가능하지는 않아요.
플래닝 단계에서 쿼리 검증기는 ValidationException으로 잘못된 타입 쌍에 대한 쿼리를 거부해요. 예를 들어 TIMESTAMP를 INTERVAL로 캐스팅하려고 할 때 그렇답니다. 런타임에 실패할 수 있는 유효한 타입 쌍은 쿼리 검증기가 수용하지만, 사용자가 실패를 올바르게 처리해야 해요.
Flink Table API와 SQL에서 캐스팅은 다음 두 내장 함수 중 하나를 사용해 수행할 수 있어요:
CAST: SQL 표준에서 정의된 일반 캐스팅 함수예요. 캐스팅 연산이 실패 가능하고 제공된 입력이 유효하지 않으면 잡이 실패할 수 있어요. 타입 추론은 입력 타입의 null 허용 여부를 보존해요.TRY_CAST: 캐스팅 연산이 실패할 경우NULL을 반환하는 일반 캐스팅 함수의 확장이에요. 반환 타입은 항상 nullable이에요.
예를 들어:
CAST('42' AS INT) --- returns 42 of type INT NOT NULL
CAST(NULL AS VARCHAR) --- returns NULL of type VARCHAR
CAST('non-number' AS INT) --- throws an exception and fails the job
TRY_CAST('42' AS INT) --- returns 42 of type INT
TRY_CAST(NULL AS VARCHAR) --- returns NULL of type VARCHAR
TRY_CAST('non-number' AS INT) --- returns NULL of type INT
COALESCE(TRY_CAST('non-number' AS INT), 0) --- returns 0 of type INT NOT NULL
아래 매트릭스는 지원되는 캐스팅 쌍을 나타내는데, "Y"는 지원됨, "!"는 실패 가능, "N"은 지원되지 않음을 의미해요:
| Input\Target | CHAR¹/VARCHAR¹/STRING |
BINARY¹/VARBINARY¹/BYTES |
BOOLEAN |
DECIMAL |
TINYINT |
SMALLINT |
INTEGER |
BIGINT |
FLOAT |
DOUBLE |
DATE |
TIME |
TIMESTAMP |
TIMESTAMP_LTZ |
INTERVAL |
ARRAY |
MULTISET |
MAP |
ROW |
STRUCTURED |
RAW |
VARIANT |
BITMAP |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
CHAR/VARCHAR/STRING |
Y | ! | ! | ! | ! | ! | ! | ! | ! | ! | ! | ! | ! | ! | N | N | N | N | N | N | N | N | N |
BINARY/VARBINARY/BYTES |
Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
BOOLEAN |
Y | N | Y | Y | Y | Y | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N |
DECIMAL |
Y | N | Y | Y | Y | Y | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N |
TINYINT |
Y | N | Y | Y | Y | Y | Y | Y | Y | Y | N | N | N² | N² | N | N | N | N | N | N | N | N | N |
SMALLINT |
Y | N | Y | Y | Y | Y | Y | Y | Y | Y | N | N | N² | N² | N | N | N | N | N | N | N | N | N |
INTEGER |
Y | N | Y | Y | Y | Y | Y | Y | Y | Y | N | N | N² | N² | Y⁵ | N | N | N | N | N | N | N | N |
BIGINT |
Y | N | Y | Y | Y | Y | Y | Y | Y | Y | N | N | N² | N² | Y⁶ | N | N | N | N | N | N | N | N |
FLOAT |
Y | N | Y | Y | Y | Y | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N |
DOUBLE |
Y | N | Y | Y | Y | Y | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N |
DATE |
Y | N | N | N | N | N | N | N | N | N | Y | N | Y | Y | N | N | N | N | N | N | N | N | N |
TIME |
Y | N | N | N | N | N | N | N | N | N | N | Y | Y | Y | N | N | N | N | N | N | N | N | N |
TIMESTAMP |
Y | N | N | N | N | N | N | N | N | N | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N |
TIMESTAMP_LTZ |
Y | N | N | N | N | N | N | N | N | N | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N |
INTERVAL |
Y | N | N | N | N | N | Y⁵ | Y⁶ | N | N | N | N | N | N | Y | N | N | N | N | N | N | N | N |
ARRAY |
Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | !³ | N | N | N | N | N | N | N |
MULTISET |
Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | !³ | N | N | N | N | N | N |
MAP |
Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | !³ | N | N | N | N | N |
ROW |
Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | !³ | N | N | N | N |
STRUCTURED |
Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | !³ | N | N | N |
RAW |
Y | ! | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | Y⁴ | N | N |
VARIANT |
N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
BITMAP |
Y | Y⁷ | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
메모:
- 고정 길이 또는 가변 길이로의 모든 캐스팅은 타입 정의에 따라 트리밍과 패딩도 수행해요.
CAST/TRY_CAST대신TO_TIMESTAMP와TO_TIMESTAMP_LTZ를 사용해야 해요.- 자식 타입 쌍이 지원될 때만 지원돼요. 자식 타입 쌍이 실패 가능할 때 실패 가능해요.
RAW클래스와 직렬 변환기가 같을 때만 지원돼요.INTERVAL이MONTH TO YEAR범위일 때만 지원돼요.INTERVAL이DAY TO TIME범위일 때만 지원돼요.- 제한 없는
VARBINARY(BYTES)에 대해서만 지원되는데, 트리밍이나 패딩은 직렬화된 비트맵 데이터를 손상시키기 때문이에요.
또한 NULL 값의 캐스팅은 사용된 함수가 CAST든 TRY_CAST든 항상 NULL을 반환한다는 점에 유의하세요.
레거시 캐스팅
Flink 1.15 이전 캐스팅 동작은 table.exec.legacy-cast-behaviour를 enabled로 설정하여 활성화할 수 있어요. Flink 1.15에서는 이 플래그가 기본적으로 비활성화돼 있어요.
특히 이는 다음을 수행해요:
CHAR/VARCHAR/BINARY/VARBINARY로 캐스팅할 때 트리밍/패딩 비활성화CAST는 실패하지 않고NULL을 반환하며, 올바른 타입을 추론하지 않고TRY_CAST처럼 동작해요CHAR/VARCHAR/STRING으로의 일부 캐스팅 형식은 약간 다른 결과를 생성해요.
{{< hint warning >}} 이 플래그의 사용은 권장하지 않으며, 새 프로젝트의 경우 이 플래그를 비활성화된 상태로 유지하고 새 캐스팅 동작을 사용하는 것을 강력히 권장해요. 이 플래그는 다음 Flink 버전에서 제거될 예정이에요. {{< /hint >}}
Data Type Extraction (데이터 타입 추출)
API의 많은 위치에서 Flink는 반복적인 수동 스키마 작업을 피하기 위해 리플렉션을 사용해 클래스 정보에서 데이터 타입을 자동으로 추출하려 시도해요. 하지만 논리적 정보가 누락될 수 있기 때문에 리플렉션으로 데이터 타입을 추출하는 것이 항상 성공하는 것은 아니에요. 따라서 추출 논리를 지원하기 위해 클래스나 필드 선언 근처에 추가 정보를 추가해야 할 수도 있어요.
다음 표는 추가 정보 없이 데이터 타입에 암시적으로 매핑될 수 있는 클래스를 나열해요.
Scala로 클래스를 구현하려면 Scala의 프리미티브 대신 박스형 타입 (예: java.lang.Integer)을 사용하는 것이 권장돼요. Scala의 프리미티브(예: Int 또는 Double)는 JVM 프리미티브(예: int/double)로 컴파일되고 아래 표와 같이 NOT NULL 의미론을 초래해요. 또한 제네릭에 사용되는 Scala 프리미티브(예: java.util.Map[Int, Double])는 컴파일 중에 소거되어 java.util.Map[java.lang.Object, java.lang.Object]와 유사한 클래스 정보를 초래해요.
| Class | Data Type |
|---|---|
java.lang.String |
STRING |
java.lang.Boolean |
BOOLEAN |
boolean |
BOOLEAN NOT NULL |
java.lang.Byte |
TINYINT |
byte |
TINYINT NOT NULL |
java.lang.Short |
SMALLINT |
short |
SMALLINT NOT NULL |
java.lang.Integer |
INT |
int |
INT NOT NULL |
java.lang.Long |
BIGINT |
long |
BIGINT NOT NULL |
java.lang.Float |
FLOAT |
float |
FLOAT NOT NULL |
java.lang.Double |
DOUBLE |
double |
DOUBLE NOT NULL |
java.sql.Date |
DATE |
java.time.LocalDate |
DATE |
java.sql.Time |
TIME(0) |
java.time.LocalTime |
TIME(9) |
java.sql.Timestamp |
TIMESTAMP(9) |
java.time.LocalDateTime |
TIMESTAMP(9) |
java.time.OffsetDateTime |
TIMESTAMP(9) WITH TIME ZONE |
java.time.Instant |
TIMESTAMP_LTZ(9) |
java.time.Duration |
INTERVAL SECOND(9) |
java.time.Period |
INTERVAL YEAR(4) TO MONTH |
byte[] |
BYTES |
T[] |
ARRAY<T> |
java.util.Map<K, V> |
MAP<K, V> |
structured type T |
anonymous structured type T |
이 문서에서 언급된 다른 JVM bridging 클래스는 @DataTypeHint 어노테이션이 필요해요.
데이터 타입 힌트는 개별 함수 매개변수와 반환 타입, 구조화 클래스, 또는 구조화 클래스의 필드의 기본 추출 논리를 매개변수화하거나 대체할 수 있어요. 구현자는 @DataTypeHint 어노테이션을 선언하여 기본 추출 논리가 수정되어야 하는 정도를 선택할 수 있어요.
@DataTypeHint 어노테이션은 선택적 힌트 매개변수 집합을 제공해요. 그중 일부 매개변수는 다음 예시에 나와 있어요. 자세한 정보는 어노테이션 클래스의 문서에서 확인할 수 있어요.
import org.apache.flink.table.annotation.DataTypeHint;
class User {
// defines an INT data type with a default conversion class `java.lang.Integer`
public @DataTypeHint("INT") Object o;
// defines a TIMESTAMP data type of millisecond precision with an explicit conversion class
public @DataTypeHint(value = "TIMESTAMP(3)", bridgedTo = java.sql.Timestamp.class) Object o;
// enrich the extraction with forcing using a RAW type
public @DataTypeHint("RAW") Class<?> modelClass;
// defines that all occurrences of java.math.BigDecimal (also in nested fields) will be
// extracted as DECIMAL(12, 2)
public @DataTypeHint(defaultDecimalPrecision = 12, defaultDecimalScale = 2) AccountStatement stmt;
// defines that whenever a type cannot be mapped to a data type, instead of throwing
// an exception, always treat it as a RAW type
public @DataTypeHint(allowRawGlobally = HintFlag.TRUE) ComplexModel model;
}
import org.apache.flink.table.annotation.DataTypeHint
class User {
// defines an INT data type with a default conversion class `java.lang.Integer`
@DataTypeHint("INT")
var o: AnyRef
// defines a TIMESTAMP data type of millisecond precision with an explicit conversion class
@DataTypeHint(value = "TIMESTAMP(3)", bridgedTo = java.sql.Timestamp.class)
var o: AnyRef
// enrich the extraction with forcing using a RAW type
@DataTypeHint("RAW")
var modelClass: Class[_]
// defines that all occurrences of java.math.BigDecimal (also in nested fields) will be
// extracted as DECIMAL(12, 2)
@DataTypeHint(defaultDecimalPrecision = 12, defaultDecimalScale = 2)
var stmt: AccountStatement
// defines that whenever a type cannot be mapped to a data type, instead of throwing
// an exception, always treat it as a RAW type
@DataTypeHint(allowRawGlobally = HintFlag.TRUE)
var model: ComplexModel
}
Not supported.