데이터 타입
데이터 타입 (Data Types)
Flink SQL은 사용자에게 풍부한 네이티브 데이터 타입 집합을 제공합니다.
출처: 문서
본문
데이터 타입 (Data Type)
*데이터 타입(data type)*은 테이블 생태계에서 값의 논리적 타입을 설명합니다. 연산의 입력 및/또는 출력 타입을 선언하는 데 사용할 수 있습니다.
Flink의 데이터 타입은 SQL 표준의 data type 용어와 유사하지만, 스칼라 표현식을 효율적으로 처리하기 위해 값을의 nullability에 대한 정보도 포함합니다.
데이터 타입의 예:
INTINT NOT NULLINTERVAL DAY TO SECOND(3)ROW<myField INT, myOtherField TIMESTAMP(3)>
모든 사전 정의된 데이터 타입의 목록은 아래에서 찾을 수 있습니다.
Table API의 데이터 타입 (Data Types in the Table API)
Java/Scala
JVM 기반 API 사용자는 Table API 내에서, 또는 커넥터, catalog, 사용자 정의 함수를 정의할 때 org.apache.flink.table.types.DataType 인스턴스로 작업합니다.
DataType 인스턴스는 두 가지 책임이 있습니다:
- 논리적 타입의 선언 — 전송 또는 저장을 위한 구체적인 물리 표현을 의미하지는 않지만, JVM 기반/Python 언어와 테이블 생태계 사이의 경계를 정의합니다.
- 선택 사항: 플래너에게 데이터의 물리 표현에 대한 힌트 제공 — 다른 API와의 경계에서 유용합니다.
JVM 기반 언어의 경우 모든 사전 정의된 데이터 타입은 org.apache.flink.table.api.DataTypes에서 사용할 수 있습니다.
Python
Python API 사용자는 Python Table API 내에서, 또는 Python 사용자 정의 함수를 정의할 때 pyflink.table.types.DataType 인스턴스로 작업합니다.
DataType 인스턴스는 다음과 같은 책임이 있습니다:
- 논리적 타입의 선언 — 전송 또는 저장을 위한 구체적인 물리 표현을 의미하지는 않지만, Python 언어와 테이블 생태계 사이의 경계를 정의합니다.
Python 언어의 경우 이 타입들은 pyflink.table.types.DataTypes에서 사용할 수 있습니다.
Java(fluent API를 위해 star import를 권장합니다):
import static org.apache.flink.table.api.DataTypes.*;
DataType t = INTERVAL(DAY(), SECOND(3));
Scala:
import org.apache.flink.table.api.DataTypes._
val t: DataType = INTERVAL(DAY(), SECOND(3))
Python:
from pyflink.table.types import DataTypes
t = DataTypes.INTERVAL(DataTypes.DAY(), DataTypes.SECOND(3))
데이터 타입과 Python 타입 매핑 (Data Type and Python Type Mapping)
Python 사용자 정의 함수의 경우 입력은 데이터 타입에 해당하는 Python 객체로 변환되며, 사용자 정의 함수 결과의 타입도 정의된 데이터 타입과 일치해야 합니다.
벡터화된 Python UDF의 경우 입력 타입과 출력 타입은 pandas.Series입니다. pandas.Series의 요소 타입은 지정된 데이터 타입에 해당합니다.
| 데이터 타입 | Python 타입 | Pandas 타입 |
|---|---|---|
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 |
지원 안 함 |
INTERVAL DAY TO SECOND |
datetime.timedelta |
지원 안 함 |
ARRAY |
list |
numpy.ndarray |
MULTISET |
list |
지원 안 함 |
MAP |
dict |
지원 안 함 |
ROW |
pyflink.common.Row |
dict |
물리 힌트 (Physical Hints)
물리 힌트는 SQL 기반 타입 시스템이 끝나고 프로그래밍 특정 데이터 타입이 필요한 테이블 생태계의 경계에서 필요합니다. 힌트는 구현이 기대하는 데이터 형식을 나타냅니다.
예를 들어 데이터 소스는 논리적 TIMESTAMP에 대한 값을 기본값인 java.time.LocalDateTime 대신 java.sql.Timestamp 클래스를 사용해 생산한다고 표현할 수 있습니다. 이 정보로 런타임은 생산된 클래스를 내부 데이터 형식으로 변환할 수 있습니다. 반대로 데이터 싱크는 런타임에서 소비하는 데이터 형식을 선언할 수 있습니다.
브리징 변환 클래스를 선언하는 예제:
Java:
// 런타임에게 java.time.LocalDateTime 인스턴스를 생산/소비하지 말고
// java.sql.Timestamp를 사용하라고 지시
DataType t = DataTypes.TIMESTAMP(3).bridgedTo(java.sql.Timestamp.class);
// 런타임에게 박싱된 정수 배열을 생산/소비하지 말고
// 프리미티브 int 배열을 사용하라고 지시
DataType t = DataTypes.ARRAY(DataTypes.INT().notNull()).bridgedTo(int[].class);
Scala:
// 런타임에게 java.time.LocalDateTime 인스턴스를 생산/소비하지 말고
// java.sql.Timestamp를 사용하라고 지시
val t: DataType = DataTypes.TIMESTAMP(3).bridgedTo(classOf[java.sql.Timestamp])
// 런타임에게 박싱된 정수 배열을 생산/소비하지 말고
// 프리미티브 int 배열을 사용하라고 지시
val t: DataType = DataTypes.ARRAY(DataTypes.INT().notNull()).bridgedTo(classOf[Array[Int]])
주의: 물리 힌트는 보통 API가 확장될 때만 필요합니다. 사전 정의된 source/sink/함수 사용자는 이런 힌트를 정의할 필요가 없습니다. 테이블 프로그램 내의 힌트(예:
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 타입 집합을 지원합니다:
| 데이터 타입 | 데이터 타입에 대한 비고 |
|---|---|
CHAR |
|
VARCHAR |
|
STRING |
|
BOOLEAN |
|
BINARY |
|
VARBINARY |
|
BYTES |
|
DECIMAL |
고정 정밀도와 스케일을 지원합니다. |
DESCRIPTOR |
프로세스 테이블 함수(PTFs)에만 지원됩니다. |
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 타입으로의 브리징:
| Java 타입 | 입력 | 출력 | 비고 |
|---|---|---|---|
java.lang.String |
X | X | 기본값 |
byte[] |
X | X | UTF-8 인코딩을 가정합니다. |
org.apache.flink.table.data.StringData |
X | X | 내부 데이터 구조. |
Python: 지원되지 않음.
타입은 CHAR(n)으로 선언할 수 있으며, n은 코드 포인트 수입니다. n은 1과 2,147,483,647 사이(양쪽 포함)의 값이어야 합니다. 길이를 지정하지 않으면 n은 1입니다.
VARCHAR / STRING
가변 길이 문자 문자열의 데이터 타입입니다.
선언:
VARCHAR
VARCHAR(n)
STRING
DataTypes.VARCHAR(n)
DataTypes.STRING()
JVM 타입으로의 브리징:
| Java 타입 | 입력 | 출력 | 비고 |
|---|---|---|---|
java.lang.String |
X | X | 기본값 |
byte[] |
X | X | UTF-8 인코딩을 가정합니다. |
org.apache.flink.table.data.StringData |
X | X | 내부 데이터 구조. |
Python:
DataTypes.VARCHAR(n)
DataTypes.STRING()
주의:
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 타입으로의 브리징: byte[] (입력/출력, 기본값).
Python: 지원되지 않음.
타입은 BINARY(n)으로 선언할 수 있으며, n은 바이트 수입니다. n은 1과 2,147,483,647 사이(양쪽 포함)의 값이어야 합니다. 길이를 지정하지 않으면 n은 1입니다.
VARBINARY / BYTES
가변 길이 바이너리 문자열(=바이트 시퀀스)의 데이터 타입입니다.
선언:
VARBINARY
VARBINARY(n)
BYTES
DataTypes.VARBINARY(n)
DataTypes.BYTES()
Python:
DataTypes.VARBINARY(n)
DataTypes.BYTES()
JVM 타입으로의 브리징: byte[] (입력/출력, 기본값).
주의:
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
고정 정밀도와 스케일을 가진 10진수 숫자의 데이터 타입입니다.
선언:
DECIMAL
DECIMAL(p)
DECIMAL(p, s)
DEC
DEC(p)
DEC(p, s)
NUMERIC
NUMERIC(p)
NUMERIC(p, s)
DataTypes.DECIMAL(p, s)
JVM 타입으로의 브리징:
| Java 타입 | 입력 | 출력 | 비고 |
|---|---|---|---|
java.math.BigDecimal |
X | X | 기본값 |
org.apache.flink.table.data.DecimalData |
X | X | 내부 데이터 구조. |
Python:
DataTypes.DECIMAL(p, s)
주의:
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입니다.
참고: 정밀도와 스케일의 정의는 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(). Python: DataTypes.TINYINT(). JVM 브리징: java.lang.Byte(입력/출력, 기본값), byte(입력/출력 — 타입이 nullable이 아닐 때만 출력).
SMALLINT
-32,768부터 32,767까지의 값을 가진 2바이트 부호 있는 정수의 데이터 타입입니다.
선언: SMALLINT / DataTypes.SMALLINT(). JVM 브리징: java.lang.Short(기본값), short.
INT
-2,147,483,648부터 2,147,483,647까지의 값을 가진 4바이트 부호 있는 정수의 데이터 타입입니다.
선언: INT / INTEGER / DataTypes.INT(). JVM 브리징: java.lang.Integer(기본값), int.
INTEGER는 이 타입의 동의어입니다.
BIGINT
-9,223,372,036,854,775,808부터 9,223,372,036,854,775,807까지의 값을 가진 8바이트 부호 있는 정수의 데이터 타입입니다.
선언: BIGINT / DataTypes.BIGINT(). JVM 브리징: java.lang.Long(기본값), long.
근사 숫자 (Approximate Numerics)
FLOAT
4바이트 단정밀도 부동 소수점 숫자의 데이터 타입입니다. SQL 표준과 비교해 이 타입은 매개변수를 받지 않습니다.
선언: FLOAT / DataTypes.FLOAT(). JVM 브리징: java.lang.Float(기본값), float.
DOUBLE
8바이트 배정밀도 부동 소수점 숫자의 데이터 타입입니다.
선언: DOUBLE / DOUBLE PRECISION / DataTypes.DOUBLE(). JVM 브리징: java.lang.Double(기본값), double.
DOUBLE PRECISION은 이 타입의 동의어입니다.
날짜와 시간 (Date and Time)
DATE
year-month-day로 구성되고 0000-01-01부터 9999-12-31까지의 값을 가진 날짜의 데이터 타입입니다. SQL 표준과 비교해 범위는 연도 0000에서 시작합니다.
선언: DATE / DataTypes.DATE(). Python: DataTypes.DATE(). JVM 브리징: java.time.LocalDate(기본값), java.sql.Date, java.lang.Integer(epoch 이후 일 수).
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)
Python: DataTypes.TIME(p).
주의:
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 타입)로의 변환과 BIGINT로부터의 변환은 시간대를 의미하므로 지원되지 않습니다. 이 타입은 시간대가 없기 때문입니다. 더 java.time.Instant과 유사한 의미론이 필요하면 TIMESTAMP_LTZ를 사용하세요.
선언:
TIMESTAMP
TIMESTAMP(p)
TIMESTAMP WITHOUT TIME ZONE
TIMESTAMP(p) WITHOUT TIME ZONE
DataTypes.TIMESTAMP(p)
JVM 브리징: java.time.LocalDateTime(기본값), java.sql.Timestamp, org.apache.flink.table.data.TimestampData(내부).
Python: DataTypes.TIMESTAMP(p).
주의:
DataTypes.TIMESTAMP(p)에서 지정한precision은 현재3이어야 합니다.
타입은 TIMESTAMP(p)으로 선언할 수 있으며, p는 분수 초의 자릿수입니다. 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 표준과 비교해 윤초는 지원되지 않습니다. 의미론이 java.time.OffsetDateTime에 더 가깝기 때문입니다.
TIMESTAMP_LTZ와 비교해, 시간대 오프셋 정보가 모든 데이터에 물리적으로 저장됩니다. 모든 계산, 시각화, 외부 시스템과의 통신에 개별적으로 사용됩니다.
선언:
TIMESTAMP WITH TIME ZONE
TIMESTAMP(p) WITH TIME ZONE
DataTypes.TIMESTAMP_WITH_TIME_ZONE(p)
JVM 브리징: java.time.OffsetDateTime(기본값), java.time.ZonedDateTime(zone ID를 무시).
Python: 지원되지 않음.
타입은 TIMESTAMP(p) WITH TIME ZONE으로 선언할 수 있으며, p는 분수 초의 자릿수입니다. 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 브리징: java.time.Instant(기본값), java.lang.Integer(epoch 이후 초), java.lang.Long(epoch 이후 밀리초), java.sql.Timestamp, org.apache.flink.table.data.TimestampData(내부).
Python: DataTypes.TIMESTAMP_LTZ(p) / DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(p).
주의:
DataTypes.TIMESTAMP_LTZ(p)에서 지정한precision은 현재3이어야 합니다.
타입은 TIMESTAMP_LTZ(p)으로 선언할 수 있으며, p는 분수 초의 자릿수입니다. p는 0과 9 사이(양쪽 포함)의 값이어야 합니다. 정밀도를 지정하지 않으면 p는 6입니다.
TIMESTAMP(p) WITH LOCAL TIME ZONE은 이 타입의 동의어입니다.
INTERVAL YEAR TO MONTH
연-월 간격 타입 그룹의 데이터 타입입니다. 타입은 다음 해상도 중 하나로 매개변수화되어야 합니다:
- 연 간격,
- 연-월 간격,
- 또는 월 간격.
연-월 간격은 +years-months로 구성되며 -9999-11부터 +9999-11까지의 값을 가집니다. 값 표현은 모든 해상도 타입에서 동일합니다. 예를 들어 50의 월 간격은 항상 연-월 간격 형식(기본 연도 정밀도)으로 표현됩니다: +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 브리징: java.time.Period(days 부분은 무시, 기본값), java.lang.Integer(월 수).
Python: DataTypes.INTERVAL(DataTypes.YEAR()) 등의 조합.
타입은 위 조합으로 선언할 수 있으며, p는 연도의 자릿수(year precision)입니다. p는 1과 4 사이(양쪽 포함)의 값이어야 합니다. 연도 정밀도를 지정하지 않으면 p는 2입니다.
INTERVAL DAY TO SECOND
일-시간 간격 타입 그룹의 데이터 타입입니다. 타입은 나노초 정밀도까지 지원하는 다음 해상도 중 하나로 매개변수화되어야 합니다:
- 일 간격,
- 일-시간 간격,
- 일-분 간격,
- 일-초 간격,
- 시간 간격,
- 시간-분 간격,
- 시간-초 간격,
- 분 간격,
- 분-초 간격,
- 또는 초 간격.
일-시간 간격은 +days hours:minutes:seconds.fractional로 구성되며 -999999 23:59:59.999999999부터 +999999 23:59:59.999999999까지의 값을 가집니다. 값 표현은 모든 해상도 타입에서 동일합니다. 예를 들어 70의 초 간격은 항상 일-초 간격 형식(기본 정밀도)으로 표현됩니다: +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 브리징: java.time.Duration(기본값), java.lang.Long(밀리초 수).
Python: DataTypes.INTERVAL(DataTypes.DAY()) 등의 동일한 조합.
타입은 위 조합으로 선언할 수 있으며, 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 브리징: t[](하위 타입에 따라 다름, 기본값), java.util.List, java.util.List의 하위 클래스, org.apache.flink.table.data.ArrayData(내부).
Python: DataTypes.ARRAY(t).
타입은 ARRAY로 선언할 수 있으며, t는 포함된 요소의 데이터 타입입니다. t ARRAY는 SQL 표준에 더 가까운 동의어입니다. 예를 들어 INT ARRAY는 ARRAY<INT>와 동일합니다.
MAP
키(NULL 포함)를 값(NULL 포함)에 매핑하는 연관 배열의 데이터 타입입니다. 맵은 중복 키를 포함할 수 없습니다. 각 키는 최대 하나의 값에 매핑할 수 있습니다.
요소 타입에 대한 제한은 없습니다. 고유성을 보장하는 것은 사용자의 책임입니다. 맵 타입은 SQL 표준에 대한 확장입니다.
선언:
MAP<kt, vt>
DataTypes.MAP(kt, vt)
JVM 브리징: java.util.Map(기본값), java.util.Map의 하위 클래스, org.apache.flink.table.data.MapData(내부).
Python: DataTypes.MAP(kt, vt).
타입은 MAP으로 선언할 수 있으며, kt는 키 요소의 데이터 타입이고 vt는 값 요소의 데이터 타입입니다.
MULTISET
멀티셋(=bag)의 데이터 타입입니다. 집합과 달리 공통 하위 타입의 각 요소에 대해 여러 인스턴스를 허용합니다. 각 고유 값(NULL 포함)은 어떤 다중도(multiplicity)에 매핑됩니다.
요소 타입에 대한 제한은 없습니다. 고유성을 보장하는 것은 사용자의 책임입니다.
선언:
MULTISET<t>
t MULTISET
DataTypes.MULTISET(t)
JVM 브리징: java.util.Map(각 값을 정수 다중도에 할당, 기본값), java.util.Map의 하위 클래스, org.apache.flink.table.data.MapData(내부).
Python: DataTypes.MULTISET(t).
타입은 MULTISET으로 선언할 수 있으며, 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 브리징: org.apache.flink.types.Row(기본값), org.apache.flink.table.data.RowData(내부).
Python: DataTypes.ROW([DataTypes.FIELD(n0, t0), ...]) / DataTypes.ROW([DataTypes.FIELD(n0, t0, d0), ...]).
타입은 ROW로 선언할 수 있으며, n은 필드의 고유 이름, t는 필드의 논리적 타입, d는 필드의 설명입니다. ROW(...)는 SQL 표준에 더 가까운 동의어입니다. 예를 들어 ROW(myField INT, myOtherField BOOLEAN)은 ROW<myField INT, myOtherField BOOLEAN>과 동일합니다.
사용자 정의 데이터 타입 (User-Defined Data Types)
STRUCTURED
사용자 정의 객체의 데이터 타입입니다. "struct-like" 타입으로 간주될 수 있는 ROW와 비교해, structured types는 같은 필드 집합을 포함하더라도 구별됩니다. 예를 들어 Visit(amount DOUBLE)은 식별자 때문에 Interaction(amount DOUBLE)과 구별됩니다.
객체 지향 프로그래밍 언어의 클래스와 유사하게, structured types는 클래스 이름으로 식별되며 0개, 1개 또는 그 이상의 속성을 포함합니다. 각 속성은 이름, 타입, 선택적 설명을 가집니다. 어떤 속성 타입이 (전이적으로) 자신을 참조하는 방식으로 타입을 정의할 수는 없습니다.
Structured types는 시스템에 의해 내부적으로 적절한 데이터 구조로 변환됩니다. 직렬화와 동등성 검사는 논리적 타입을 기준으로 시스템이 관리합니다.
선언:
STRUCTURED<'c', n0 t0, n1 t1, ...>
STRUCTURED<'c', n0 t0, n1 t1 'd1', ...>
여기서 c는 클래스 이름, n은 필드의 고유 이름, t는 필드의 논리적 타입, d는 필드의 선택적 설명입니다.
Java/Scala: 보통 structured types는 인라인으로 정의되며 해당 구현 클래스에서 반사적으로 추출할 수 있습니다. 예를 들어 함수의 eval() 메서드 시그니처에서 그렇습니다. 이것은 테이블 프로그램을 프로그래밍 방식으로 정의할 때 유용합니다. 데이터 타입의 스키마를 수동으로 다시 정의하지 않고 기존 JVM 클래스를 재사용할 수 있게 해줍니다.
클래스 이름이 classpath의 클래스와 일치하면 시스템은 테이블 생태계의 경계에서(예: 함수나 커넥터로 브리징할 때) structured 객체를 JVM 객체로 변환합니다. 구현 클래스는 0-인자 생성자 또는 모든 속성을 할당하는 전체 생성자를 제공해야 합니다.
하지만 클래스 이름이 classpath에서 해석 가능할 필요는 없으며, 동일한 속성 집합을 가진 객체를 구별하는 데만 사용될 수 있습니다. 단, Table API와 UDF 호출에서 시스템은 클래스 이름을 실제 구현 클래스로 해석하려 시도합니다. 해석이 실패하면 Row가 대체물로 사용됩니다.
구현 클래스가 다음 요구 사항을 충족하면 일반 POJO(Plain Old Java Objects)에서 인라인 structured types를 만들 수 있습니다:
- 클래스는 전역적으로 접근 가능해야 하며, 즉
public,static, 그리고abstract가 아니어야 합니다. - 클래스는 0-인자 기본 생성자 또는 모든 필드를 할당하는 전체 생성자를 제공해야 합니다.
- 클래스의 모든 필드는
public선언 또는getField(),isField(),field()같은 일반 코딩 스타일을 따르는 getter로 읽을 수 있어야 합니다. - 클래스의 모든 필드는
public선언, 전체 할당 생성자, 또는setField(...),field(...)같은 일반 코딩 스타일을 따르는 setter로 쓸 수 있어야 합니다. - 모든 필드가 반사적 추출을 통해 암시적으로 또는
@DataTypeHint어노테이션을 사용해 명시적으로 데이터 타입에 매핑되어야 합니다. static또는transient로 선언된 필드는 무시됩니다.
반사적 추출은 필드 타입이 (전이적으로) 자신을 참조하지 않는 한 필드의 임의 중첩을 지원합니다.
선언된 필드 클래스(예: public int age;)는 이 문서의 모든 데이터 타입에 정의된 지원되는 JVM 브리징 클래스 목록(예: INT에 대한 java.lang.Integer 또는 int)에 포함되어야 합니다.
일부 클래스는 데이터 타입에 매핑하기 위해 어노테이션이 필요합니다(예: java.math.BigDecimal에 고정 정밀도와 스케일을 할당하기 위한 @DataTypeHint("DECIMAL(10, 2)")).
Python: 지원되지 않음.
Structured types는 보통 구현 클래스를 통해 선언됩니다:
// structured type으로 자격을 갖춘 간단한 POJO.
// 참고: 전체 할당 생성자가 없으면 필드 순서는 알파벳 순이 됩니다.
// 최종 데이터 타입:
// 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;
}
// 필드 순서를 정의하는 전체 할당 생성자가 있는 POJO.
// 최종 데이터 타입:
// 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;
}
}
// 반사적 추출을 지원하기 위해 @DataTypeHint 어노테이션을 사용하는 POJO.
// 최종 데이터 타입:
// STRUCTURED<'com.myorg.Customer', age INT NOT NULL, modelClass RAW(...), name STRING, totalBalance DECIMAL(10, 2)>
class Customer {
// 필드를 자동으로 추출
public int age;
public String name;
// 정밀도 정보로 추출 강화
public @DataTypeHint("DECIMAL(10, 2)") BigDecimal totalBalance;
// RAW 타입을 강제로 사용해 추출 강화
public @DataTypeHint("RAW") Class<?> modelClass;
}
또는 명시적 선언:
// 구현 클래스 제공
DataTypes.STRUCTURED(MyPojo.class, DataTypes.FIELD(n0, t0), DataTypes.FIELD(n1, t1), ...);
// 클래스 이름만 제공, 클래스는 classpath에 있을 때만 해석됨
DataTypes.STRUCTURED("com.myorg.MyPojo", DataTypes.FIELD(n0, t0), DataTypes.FIELD(n1, t1), ...);
// 전체 예제
DataTypes.STRUCTURED(
Customer.class,
DataTypes.FIELD("age", DataTypes.INT().notNull()),
DataTypes.FIELD("name", DataTypes.STRING())
);
또는 명시적 추출:
DataTypes.of(Class);
// 예를 들어:
DataTypes.of(Customer.class);
JVM 타입으로의 브리징: class(입력은 원래 클래스 또는 하위 클래스, 출력은 상위 클래스, 기본값), org.apache.flink.types.Row, org.apache.flink.table.data.RowData(내부).
Python: 지원되지 않음.
기타 데이터 타입 (Other Data Types)
BOOLEAN
TRUE, FALSE, UNKNOWN의 (가능한) 3값 논리를 가진 boolean 데이터 타입입니다.
선언: BOOLEAN / DataTypes.BOOLEAN(). Python: DataTypes.BOOLEAN(). JVM 브리징: java.lang.Boolean(기본값), boolean.
DESCRIPTOR
임의의, 검증되지 않은 컬럼 목록을 설명하기 위한 데이터 타입입니다. 이 타입은 DESCRIPTOR(c0, c1) 호출의 반환 타입입니다. 프로세스 테이블 함수(PTFs)의 인수에서 사용하기 위한 것입니다.
런타임은 이 타입을 지원하지 않습니다. 번역과 계획 중의 순수한 헬퍼 타입입니다. 테이블 컬럼은 이 타입으로 선언할 수 없습니다. 함수는 이 타입의 반환 타입을 선언할 수 없습니다.
선언: DESCRIPTOR / DataTypes.DESCRIPTOR(). JVM 브리징: org.apache.flink.types.ColumnList(기본값).
VARIANT
반정형(semi-structured) 데이터의 데이터 타입입니다.
이 타입은 ARRAY, MAP(STRING 타입의 키 포함), 스칼라 타입을 포함한 모든 반정형 데이터를 저장하는 것을 지원합니다. 필드의 데이터 타입은 JSON의 의미론에 가까운 데이터 구조에 저장됩니다. ROW와 STRUCTURED 타입과 비교해, VARIANT 타입은 높은 중첩과 진화하는 스키마를 지원하는 유연성을 가집니다.
VARIANT은 배열 안의 배열, 맵 안의 맵, 또는 둘의 조합 같은 깊게 중첩된 데이터 구조를 허용합니다. 이 기능은 데이터 복잡성과 중첩이 상당한 시나리오에서 VARIANT을 이상적으로 만듭니다.
VARIANT은 스키마 진화를 허용하며, 사전 스키마 정의 없이 바뀌거나 알 수 없는 스키마의 데이터를 저장할 수 있게 합니다. 예를 들어 데이터에 새 필드가 추가되면 테이블 스키마를 수정하지 않고 VARIANT 데이터에 직접 통합할 수 있습니다. 이것은 스키마가 시간이 지남에 따라 진화할 수 있는 동적 환경에서 특히 유용합니다.
선언: VARIANT / DataTypes.VARIANT().
Variant 타입은 보통 PARSE_JSON 함수에 의해 생성됩니다. 예:
SELECT PARSE_JSON('{"a":1,"b":["a","b","c"]}') AS v
JVM 브리징: org.apache.flink.types.variant.Variant(기본값).
BITMAP
RoaringBitmap을 사용해 32비트 정수를 압축된 형태로 저장하는 비트맵 데이터의 데이터 타입입니다.
비트맵 타입은 큰 정수 집합을 효율적으로 표현하고 쿼리하는 데 유용합니다. 다양한 내장 스칼라 함수와 집계 함수를 지원합니다. 비트맵 타입은 SQL 표준에 대한 확장입니다.
선언: BITMAP / DataTypes.BITMAP().
Bitmap 타입은 BITMAP_BUILD 함수를 사용해 ARRAY에서 만들 수 있습니다. 예:
SELECT BITMAP_BUILD(ARRAY[1, 2, 3, 4, 5])
JVM 브리징: org.apache.flink.types.bitmap.Bitmap(기본값).
RAW
임의의 직렬화된 타입의 데이터 타입입니다. 이 타입은 테이블 생태계 내에서 블랙박스이며 경계에서만 역직렬화됩니다. raw 타입은 SQL 표준에 대한 확장입니다.
선언:
RAW('class', 'snapshot')
DataTypes.RAW(class, serializer)
DataTypes.RAW(class)
JVM 브리징: class(입력은 원래 클래스 또는 하위 클래스, 출력은 상위 클래스, 기본값), byte[](출력), org.apache.flink.table.data.RawValueData(내부).
Python: 지원되지 않음.
타입은 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 같은 그러한 타입을 정의하는 포맷으로의 브리징에도 도움이 됩니다. 이 타입은 실제로 그리 유용하지 않으며 완전성을 위해 여기에 언급됩니다.
선언: NULL / DataTypes.NULL(). Python: 지원되지 않음. JVM 브리징: java.lang.Object(기본값), any class(모든 비프리미티브 타입).
캐스팅 (Casting)
Flink Table API와 SQL은 정의된 input 타입과 target 타입 사이의 캐스팅을 수행할 수 있습니다. 일부 캐스팅 연산은 입력 값과 무관하게 항상 성공하지만, 다른 것은 런타임에 실패할 수 있습니다(즉 대상 타입에 대한 값을 만들 방법이 없는 경우). 예를 들어 INT를 STRING으로 변환하는 것은 항상 가능하지만 STRING을 INT로 변환하는 것은 항상 가능하지 않습니다.
계획 단계에서 쿼리 유효성 검사기는 잘못된 타입 쌍에 대한 쿼리를 ValidationException으로 거부합니다(예: TIMESTAMP를 INTERVAL로 캐스팅하려 할 때). 런타임에 실패할 수 있는 유효한 타입 쌍은 쿼리 유효성 검사기가 받아들이지만, 사용자가 실패를 올바르게 처리해야 합니다.
Flink Table API와 SQL에서 캐스팅은 다음 두 내장 함수 중 하나를 사용해 수행할 수 있습니다:
CAST: SQL 표준이 정의하는 일반 캐스트 함수입니다. 캐스트 연산이 fallible하고 입력이 유효하지 않으면 작업이 실패할 수 있습니다. 타입 추론은 입력 타입의 nullability를 보존합니다.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"는 지원됨, "!"는 fallible, "N"은 지원되지 않음을 뜻합니다:
| 입력\대상 | 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 |
참고:
- 고정 길이 또는 가변 길이로의 모든 캐스팅은 타입 정의에 따라 trim과 pad도 수행합니다.
CAST/TRY_CAST대신TO_TIMESTAMP와TO_TIMESTAMP_LTZ를 사용해야 합니다.- 하위(children) 타입 쌍이 지원되는 경우에만 지원됩니다. 하위 타입 쌍이 fallible인 경우에만 fallible입니다.
RAW클래스와 serializer가 같을 때만 지원됩니다.INTERVAL이MONTH TO YEAR범위일 때만 지원됩니다.INTERVAL이DAY TO TIME범위일 때만 지원됩니다.- 무제한
VARBINARY(BYTES)에만 지원됩니다. trim이나 pad는 직렬화된 비트맵 데이터를 손상시키기 때문입니다.
또한 사용 함수가 CAST든 TRY_CAST든 NULL 값의 캐스트는 항상 NULL을 반환한다는 점에 유의하세요.
레거시 캐스팅 (Legacy casting)
Flink 1.15 이전의 캐스팅 동작은 table.exec.legacy-cast-behaviour를 enabled로 설정해 활성화할 수 있습니다. Flink 1.15에서 이 플래그는 기본적으로 비활성화되어 있습니다.
구체적으로 이는 다음을 수행합니다:
CHAR/VARCHAR/BINARY/VARBINARY로의 캐스팅에서 trim/padding을 비활성화합니다.CAST가 실패하지 않고NULL을 반환하며,TRY_CAST처럼 동작하지만 올바른 타입을 추론하지는 않습니다.- 일부
CHAR/VARCHAR/STRING으로의 캐스팅 형식이 약간 다른 결과를 만듭니다.
이 플래그의 사용은 권장하지 않으며, 새 프로젝트는 이 플래그를 비활성화된 상태로 유지하고 새 캐스팅 동작을 사용할 것을 강력히 제안합니다. 이 플래그는 다음 Flink 버전에서 제거될 예정입니다.
데이터 타입 추출 (Data Type Extraction)
Java/Scala
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]와 유사한 클래스 정보를 만듭니다.
| 클래스 | 데이터 타입 |
|---|---|
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 |
MAP |
structured type T |
익명 structured type T |
이 문서에서 언급된 다른 JVM 브리징 클래스는 @DataTypeHint 어노테이션이 필요합니다.
*데이터 타입 힌트(data type hints)*는 개별 함수 매개변수와 반환 타입, structured 클래스, 또는 structured 클래스의 필드의 기본 추출 로직을 매개변수화하거나 대체할 수 있습니다. 구현자는 @DataTypeHint 어노테이션을 선언해 기본 추출 로직을 어느 정도 수정할지 선택할 수 있습니다.
@DataTypeHint 어노테이션은 선택적 힌트 매개변수 집합을 제공합니다. 다음 예제에서 그 매개변수 중 일부를 보여줍니다. 더 많은 정보는 어노테이션 클래스의 문서에서 찾을 수 있습니다.
Java:
import org.apache.flink.table.annotation.DataTypeHint;
class User {
// 기본 변환 클래스 `java.lang.Integer`를 가진 INT 데이터 타입 정의
public @DataTypeHint("INT") Object o;
// 밀리초 정밀도의 TIMESTAMP 데이터 타입을 명시적 변환 클래스로 정의
public @DataTypeHint(value = "TIMESTAMP(3)", bridgedTo = java.sql.Timestamp.class) Object o;
// RAW 타입을 강제로 사용해 추출 강화
public @DataTypeHint("RAW") Class<?> modelClass;
// java.math.BigDecimal의 모든 발생(중첩 필드에서도)을 DECIMAL(12, 2)로 추출하도록 정의
public @DataTypeHint(defaultDecimalPrecision = 12, defaultDecimalScale = 2) AccountStatement stmt;
// 타입을 데이터 타입에 매핑할 수 없을 때 예외를 던지는 대신 항상 RAW 타입으로 처리하도록 정의
public @DataTypeHint(allowRawGlobally = HintFlag.TRUE) ComplexModel model;
}
Scala:
import org.apache.flink.table.annotation.DataTypeHint
class User {
// 기본 변환 클래스 `java.lang.Integer`를 가진 INT 데이터 타입 정의
@DataTypeHint("INT")
var o: AnyRef
// 밀리초 정밀도의 TIMESTAMP 데이터 타입을 명시적 변환 클래스로 정의
@DataTypeHint(value = "TIMESTAMP(3)", bridgedTo = java.sql.Timestamp.class)
var o: AnyRef
// RAW 타입을 강제로 사용해 추출 강화
@DataTypeHint("RAW")
var modelClass: Class[_]
// java.math.BigDecimal의 모든 발생(중첩 필드에서도)을 DECIMAL(12, 2)로 추출하도록 정의
@DataTypeHint(defaultDecimalPrecision = 12, defaultDecimalScale = 2)
var stmt: AccountStatement
// 타입을 데이터 타입에 매핑할 수 없을 때 예외를 던지는 대신 항상 RAW 타입으로 처리하도록 정의
@DataTypeHint(allowRawGlobally = HintFlag.TRUE)
var model: ComplexModel
}
Python: 지원되지 않음.