SparkSQL의 Window함수 종류
아파치 스파크(Spark)에서 윈도우 함수(Window Function)는 SQL 표준에서 정의된 윈도우 함수와 유사한 기능을 제공하며, 데이터 분석 및 처리 시 그룹 내에서의 순위, 이전/다음 행과의 비교, 누적값 계산 등 다양한 패턴을 효율적으로 구현할 수 있음.
윈도우 함수는 GROUP BY 기반의 집계 함수로는 해결하기 어려운, 세분화된 계산 로직이 필요한 경우 자주 사용됨.
윈도우 스펙
윈도우 함수를 사용하기 위해서는 먼저 윈도우 스펙(Window Specification)을 정의해야 함.
윈도우 스펙은 다음 세 가지 요소로 구성됨.
1. PARTITION BY: 행을 어떤 기준으로 파티션(그룹) 지을 것인지 정의함.
2. ORDER BY: 파티션 내에서의 정렬 순서를 정의함.
3. 프레임(Frame) 지정: 어떤 범위(ROWS, RANGE)로 윈도우를 설정할지 정의함.
Spark에서는 Window 객체를 생성하거나 SQL문으로 작성할 때 다음과 같은 형태를 가짐.
<window_function> OVER (
[PARTITION BY partition_expr...]
[ORDER BY order_expr...]
[window_frame_clause]
)
또는 PySpark에서의 예시는 다음과 같이 작성할 수 있음.
from pyspark.sql.window import Window
import pyspark.sql.functions as F
window_spec = Window.partitionBy("컬럼1") \
.orderBy("컬럼2") \
.rowsBetween(Window.unboundedPreceding, Window.currentRow)
df.select(
"*",
F.row_number().over(window_spec).alias("row_num")
)
스파크에서 지원하는 프레임(Frame) 지정 방법은 크게 두 가지임.
1. ROWS: 물리적으로 지정된 행 기준으로 범위를 설정
예) ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
2. RANGE: 정렬 컬럼의 값에 기반하여 범위를 설정
예) RANGE BETWEEN INTERVAL 1 DAY PRECEDING AND CURRENT ROW
프레임을 생략하는 경우의 기본값은 다음과 같이 함수마다 다를 수 있지만, 일반적으로는 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW가 기본값이 됨.
윈도우 함수의 종류
Spark SQL에서 윈도우 함수는 크게 순위(Rank) 함수, 행(Row) 기반 함수, 집계(Aggregate) 함수 등으로 나누어볼 수 있음.
1. 순위(Ranking) 함수
순위 함수는 파티션 내에서 각 행의 순위를 매기는 데 사용됨.
Spark SQL에서 지원하는 대표적인 순위 함수는 아래와 같음.
1-1. ROW_NUMBER()
파티션 내에서 각 행의 순서를 1부터 시작하는 단순 번호로 매김.
동일 값(타이)이라도 순위가 중복되지 않고, 항상 고유한 번호를 부여함.
예) row_number() over (partition by region order by sales desc) as rn
1-2. RANK()
파티션 내에서 값이 동일한 행은 동일한 순위를 부여하고, 다음 순위는 건너뜀(순위에 공백 발생).
예) 데이터가 [10, 9, 9, 8]이라면 순위는 [1, 2, 2, 4]가 됨.
1-3. DENSE_RANK()
RANK()와 비슷하지만 순위에서 공백이 발생하지 않음.
위 예시 [10, 9, 9, 8]일 때, 순위는 [1, 2, 2, 3]이 됨.
1-4. PERCENT_RANK()
파티션 내에서의 순위를 0과 1 사이의 비율로 나타냄.
(RANK - 1) / (파티션 내 총 행 수 - 1) 공식으로 계산됨.
1-5. NTILE(n)
파티션 내의 행들을 n개의 버킷(bucket)으로 나누고 각 버킷 번호(1~n)를 부여함.
예) ntile(4)라면 파티션 내 행을 4등분하여 1, 2, 3, 4 버킷 번호를 매김.
2. 행(Row) 기반 함수
이 카테고리에 속하는 함수들은 이전 행, 다음 행의 값을 참조하거나, 첫 행, 마지막 행의 값을 참조하여 원하는 컬럼을 조회할 수 있게 도와줌.
시계열 분석 혹은 특정 기준으로 이전 값, 다음 값과 비교해서 차이를 계산할 때 흔히 사용됨.
2-1. LAG(column, offset=1, default=NULL)
현재 행 기준으로 이전 offset행의 컬럼 값을 반환함.
예) lag(sales, 1) over (partition by region order by date)는 현재 일자 기준 바로 전날의 판매량을 가져옴.
2-2. LEAD(column, offset=1, default=NULL)
현재 행 기준으로 다음 offset행의 컬럼 값을 반환함.
예) lead(sales, 1) over (partition by region order by date)는 현재 일자 기준 다음 날의 판매량을 가져옴.
2-3. FIRST_VALUE(column)
파티션 및 프레임 내에서 가장 첫 번째 행의 컬럼 값을 반환함.
프레임의 범위를 조정해 특정 구간에서의 첫 값을 가져올 수도 있음.
예) first_value(sales) over (partition by region order by date rows between unbounded preceding and current row)
2-4. LAST_VALUE(column)
파티션 및 프레임 내에서 가장 마지막 행의 컬럼 값을 반환함.
예) last_value(sales) over (partition by region order by date rows between current row and unbounded following)
2-5. NTH_VALUE(column, n)
파티션 및 프레임 내에서 n번째 행의 컬럼 값을 반환함.
예) nth_value(sales, 2) over (partition by region order by date)는 2번째 행의 판매량을 반환함.
2-6. CUME_DIST() (Cumulative Distribution)
파티션 내에서 현재 행까지의 누적 비율을 계산함.
공식적으로는 (순위 값) / (파티션 내 전체 행 수) 형태와 유사하게 계산됨.
3. 집계(Aggregate) 함수의 윈도우 버전
Spark SQL에서 제공되는 SUM, AVG, MIN, MAX, COUNT 등은 기본적으로 GROUP BY를 통해 그룹 단위로 계산하지만, 윈도우 스펙과 함께 사용하면 그룹을 나누지 않고 분석할 수 있음.
예를 들어 다음과 같은 코드가 가능함.
SUM(column) OVER (
PARTITION BY region
ORDER BY date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
이 함수는 region 별로 날짜가 증가하는 순서대로 정렬된 상태에서, 현재 행까지의 누적 합계를 반환함.
주요 예시는 다음과 같음.
1. SUM(...) : 누적 합계 (또는 특정 프레임 내 합계)
2. AVG(...) : 누적 평균
3. MIN(...) / MAX(...) : 구간별 최솟값, 최댓값
4. COUNT(...) : 구간별 개수
윈도우 프레임 지정의 세부 옵션
1. ROWS vs RANGE
1-1. ROWS: 현재 행을 기준으로 물리적 행 단위로 범위를 지정함.
예) ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING → 현재 행을 기준으로 앞뒤 한 행씩만 포함.
1-2. RANGE: 현재 행의 정렬 컬럼의 값을 기준으로 범위를 지정함.
예) RANGE BETWEEN INTERVAL 1 DAY PRECEDING AND CURRENT ROW → 날짜나 시간 컬럼이 존재할 때, 현재 행의 날짜로부터 1일 이전부터 현재 행까지를 포함
2. UNBOUNDED PRECEDING, UNBOUNDED FOLLOWING, CURRENT ROW
프레임 구간 설정에서 가장 많이 사용되는 예약어들임.
2-1. UNBOUNDED PRECEDING: 파티션의 시작(맨 처음) 행까지
2-2. UNBOUNDED FOLLOWING: 파티션의 끝(맨 마지막) 행까지
2-3. CURRENT ROW: 현재 행
예시:
SUM(column) OVER (
PARTITION BY region
ORDER BY date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
이는 region별로 날짜 순서로 정렬했을 때, 가장 처음 행부터 현재 행까지의 합계를 의미함.
윈도우 함수 활용 시 주의사항
1. ORDER BY 누락
윈도우 함수에서 순위 함수나 LAG/LEAD 등을 사용 시에는 반드시 ORDER BY 절이 있어야 의미 있는 결과가 나옴.
(집계 함수만 쓰는 경우엔 파티션만 지정해도 동작하지만, 일반적으로 순서가 중요할 땐 꼭 지정해야 함.)
2. 프레임(Frame) 기본 범위
특정 함수들은 ORDER BY 절만 사용하면 기본 프레임이 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW가 됨.
원하는 계산 범위가 있다면 반드시 적절한 프레임을 지정해줘야 함.
3. 성능
윈도우 함수는 GROUP BY 없이도 여러 계산을 동시 처리하기 때문에 편리하지만, 대용량 데이터에서는 파티션의 개수, 정렬 비용이 커질 수 있음.
파티션이나 클러스터링(Partitioning, Bucketing)을 고려하여 최적화하는 것이 중요함.
4. 결과 해석
RANK(), DENSE_RANK(), ROW_NUMBER()의 차이와 LAG(), LEAD()의 오프셋(offset) 등을 제대로 이해하고 사용해야 올바른 결과를 얻을 수 있음.
정리
Spark SQL에서 제공하는 윈도우 함수는 데이터 분석 시 매우 강력하고 유연한 기능을 제공함.
특히 순위(Rank) 함수, 행(Row) 기반 함수, 누적/구간 집계(Aggregate) 함수를 윈도우 스펙과 함께 사용하는 방법을 이해하면, 기존의 GROUP BY만으로 해결하기 힘든 세밀한 계산을 간단한 SQL 쿼리로 작성할 수 있음.
핵심 포인트는 다음과 같음.
1. 윈도우 함수를 사용하려면 파티션, 정렬, 프레임을 적절히 설정해야 함.
2. 순위 함수(RANK, DENSE_RANK, ROW_NUMBER 등), 분석 함수(LEAD, LAG, FIRST_VALUE 등), 집계 함수(SUM, AVG, MIN 등)를 OVER ( ... )와 함께 적용함.
3. 성능과 정확한 해석을 위해, 파티션 및 프레임을 올바르게 이해하고 지정하는 것이 중요함.
이처럼 Spark SQL 윈도우 함수는 OLAP(Online Analytical Processing)나 시계열/트렌드 분석 시 핵심적인 도구가 되며, 적절하게 사용하면 다차원적인 분석이 용이해짐.
전문적인 성능 최적화 관점에서는, 데이터 스키마 설계(파티션, 파일 포맷), 클러스터링 전략, Shuffle 최적화 등이 함께 고려되어야 함.
'Data Engineering > Spark' 카테고리의 다른 글
[Spark] Pyspark에서 repartition(), coalesce() 사용 (0) | 2025.03.29 |
---|---|
[Spark] Disk Spill (0) | 2025.03.28 |
[Spark] Apache Spark 구조 (2) | 2025.03.15 |
[Spark] Apache Iceberg (2) | 2025.03.14 |
[Spark] Apache ORC 파일 구조 (0) | 2025.03.09 |
SparkSQL의 Window함수 종류
아파치 스파크(Spark)에서 윈도우 함수(Window Function)는 SQL 표준에서 정의된 윈도우 함수와 유사한 기능을 제공하며, 데이터 분석 및 처리 시 그룹 내에서의 순위, 이전/다음 행과의 비교, 누적값 계산 등 다양한 패턴을 효율적으로 구현할 수 있음.
윈도우 함수는 GROUP BY 기반의 집계 함수로는 해결하기 어려운, 세분화된 계산 로직이 필요한 경우 자주 사용됨.
윈도우 스펙
윈도우 함수를 사용하기 위해서는 먼저 윈도우 스펙(Window Specification)을 정의해야 함.
윈도우 스펙은 다음 세 가지 요소로 구성됨.
1. PARTITION BY: 행을 어떤 기준으로 파티션(그룹) 지을 것인지 정의함.
2. ORDER BY: 파티션 내에서의 정렬 순서를 정의함.
3. 프레임(Frame) 지정: 어떤 범위(ROWS, RANGE)로 윈도우를 설정할지 정의함.
Spark에서는 Window 객체를 생성하거나 SQL문으로 작성할 때 다음과 같은 형태를 가짐.
<window_function> OVER (
[PARTITION BY partition_expr...]
[ORDER BY order_expr...]
[window_frame_clause]
)
또는 PySpark에서의 예시는 다음과 같이 작성할 수 있음.
from pyspark.sql.window import Window
import pyspark.sql.functions as F
window_spec = Window.partitionBy("컬럼1") \
.orderBy("컬럼2") \
.rowsBetween(Window.unboundedPreceding, Window.currentRow)
df.select(
"*",
F.row_number().over(window_spec).alias("row_num")
)
스파크에서 지원하는 프레임(Frame) 지정 방법은 크게 두 가지임.
1. ROWS: 물리적으로 지정된 행 기준으로 범위를 설정
예) ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
2. RANGE: 정렬 컬럼의 값에 기반하여 범위를 설정
예) RANGE BETWEEN INTERVAL 1 DAY PRECEDING AND CURRENT ROW
프레임을 생략하는 경우의 기본값은 다음과 같이 함수마다 다를 수 있지만, 일반적으로는 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW가 기본값이 됨.
윈도우 함수의 종류
Spark SQL에서 윈도우 함수는 크게 순위(Rank) 함수, 행(Row) 기반 함수, 집계(Aggregate) 함수 등으로 나누어볼 수 있음.
1. 순위(Ranking) 함수
순위 함수는 파티션 내에서 각 행의 순위를 매기는 데 사용됨.
Spark SQL에서 지원하는 대표적인 순위 함수는 아래와 같음.
1-1. ROW_NUMBER()
파티션 내에서 각 행의 순서를 1부터 시작하는 단순 번호로 매김.
동일 값(타이)이라도 순위가 중복되지 않고, 항상 고유한 번호를 부여함.
예) row_number() over (partition by region order by sales desc) as rn
1-2. RANK()
파티션 내에서 값이 동일한 행은 동일한 순위를 부여하고, 다음 순위는 건너뜀(순위에 공백 발생).
예) 데이터가 [10, 9, 9, 8]이라면 순위는 [1, 2, 2, 4]가 됨.
1-3. DENSE_RANK()
RANK()와 비슷하지만 순위에서 공백이 발생하지 않음.
위 예시 [10, 9, 9, 8]일 때, 순위는 [1, 2, 2, 3]이 됨.
1-4. PERCENT_RANK()
파티션 내에서의 순위를 0과 1 사이의 비율로 나타냄.
(RANK - 1) / (파티션 내 총 행 수 - 1) 공식으로 계산됨.
1-5. NTILE(n)
파티션 내의 행들을 n개의 버킷(bucket)으로 나누고 각 버킷 번호(1~n)를 부여함.
예) ntile(4)라면 파티션 내 행을 4등분하여 1, 2, 3, 4 버킷 번호를 매김.
2. 행(Row) 기반 함수
이 카테고리에 속하는 함수들은 이전 행, 다음 행의 값을 참조하거나, 첫 행, 마지막 행의 값을 참조하여 원하는 컬럼을 조회할 수 있게 도와줌.
시계열 분석 혹은 특정 기준으로 이전 값, 다음 값과 비교해서 차이를 계산할 때 흔히 사용됨.
2-1. LAG(column, offset=1, default=NULL)
현재 행 기준으로 이전 offset행의 컬럼 값을 반환함.
예) lag(sales, 1) over (partition by region order by date)는 현재 일자 기준 바로 전날의 판매량을 가져옴.
2-2. LEAD(column, offset=1, default=NULL)
현재 행 기준으로 다음 offset행의 컬럼 값을 반환함.
예) lead(sales, 1) over (partition by region order by date)는 현재 일자 기준 다음 날의 판매량을 가져옴.
2-3. FIRST_VALUE(column)
파티션 및 프레임 내에서 가장 첫 번째 행의 컬럼 값을 반환함.
프레임의 범위를 조정해 특정 구간에서의 첫 값을 가져올 수도 있음.
예) first_value(sales) over (partition by region order by date rows between unbounded preceding and current row)
2-4. LAST_VALUE(column)
파티션 및 프레임 내에서 가장 마지막 행의 컬럼 값을 반환함.
예) last_value(sales) over (partition by region order by date rows between current row and unbounded following)
2-5. NTH_VALUE(column, n)
파티션 및 프레임 내에서 n번째 행의 컬럼 값을 반환함.
예) nth_value(sales, 2) over (partition by region order by date)는 2번째 행의 판매량을 반환함.
2-6. CUME_DIST() (Cumulative Distribution)
파티션 내에서 현재 행까지의 누적 비율을 계산함.
공식적으로는 (순위 값) / (파티션 내 전체 행 수) 형태와 유사하게 계산됨.
3. 집계(Aggregate) 함수의 윈도우 버전
Spark SQL에서 제공되는 SUM, AVG, MIN, MAX, COUNT 등은 기본적으로 GROUP BY를 통해 그룹 단위로 계산하지만, 윈도우 스펙과 함께 사용하면 그룹을 나누지 않고 분석할 수 있음.
예를 들어 다음과 같은 코드가 가능함.
SUM(column) OVER (
PARTITION BY region
ORDER BY date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
이 함수는 region 별로 날짜가 증가하는 순서대로 정렬된 상태에서, 현재 행까지의 누적 합계를 반환함.
주요 예시는 다음과 같음.
1. SUM(...) : 누적 합계 (또는 특정 프레임 내 합계)
2. AVG(...) : 누적 평균
3. MIN(...) / MAX(...) : 구간별 최솟값, 최댓값
4. COUNT(...) : 구간별 개수
윈도우 프레임 지정의 세부 옵션
1. ROWS vs RANGE
1-1. ROWS: 현재 행을 기준으로 물리적 행 단위로 범위를 지정함.
예) ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING → 현재 행을 기준으로 앞뒤 한 행씩만 포함.
1-2. RANGE: 현재 행의 정렬 컬럼의 값을 기준으로 범위를 지정함.
예) RANGE BETWEEN INTERVAL 1 DAY PRECEDING AND CURRENT ROW → 날짜나 시간 컬럼이 존재할 때, 현재 행의 날짜로부터 1일 이전부터 현재 행까지를 포함
2. UNBOUNDED PRECEDING, UNBOUNDED FOLLOWING, CURRENT ROW
프레임 구간 설정에서 가장 많이 사용되는 예약어들임.
2-1. UNBOUNDED PRECEDING: 파티션의 시작(맨 처음) 행까지
2-2. UNBOUNDED FOLLOWING: 파티션의 끝(맨 마지막) 행까지
2-3. CURRENT ROW: 현재 행
예시:
SUM(column) OVER (
PARTITION BY region
ORDER BY date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
이는 region별로 날짜 순서로 정렬했을 때, 가장 처음 행부터 현재 행까지의 합계를 의미함.
윈도우 함수 활용 시 주의사항
1. ORDER BY 누락
윈도우 함수에서 순위 함수나 LAG/LEAD 등을 사용 시에는 반드시 ORDER BY 절이 있어야 의미 있는 결과가 나옴.
(집계 함수만 쓰는 경우엔 파티션만 지정해도 동작하지만, 일반적으로 순서가 중요할 땐 꼭 지정해야 함.)
2. 프레임(Frame) 기본 범위
특정 함수들은 ORDER BY 절만 사용하면 기본 프레임이 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW가 됨.
원하는 계산 범위가 있다면 반드시 적절한 프레임을 지정해줘야 함.
3. 성능
윈도우 함수는 GROUP BY 없이도 여러 계산을 동시 처리하기 때문에 편리하지만, 대용량 데이터에서는 파티션의 개수, 정렬 비용이 커질 수 있음.
파티션이나 클러스터링(Partitioning, Bucketing)을 고려하여 최적화하는 것이 중요함.
4. 결과 해석
RANK(), DENSE_RANK(), ROW_NUMBER()의 차이와 LAG(), LEAD()의 오프셋(offset) 등을 제대로 이해하고 사용해야 올바른 결과를 얻을 수 있음.
정리
Spark SQL에서 제공하는 윈도우 함수는 데이터 분석 시 매우 강력하고 유연한 기능을 제공함.
특히 순위(Rank) 함수, 행(Row) 기반 함수, 누적/구간 집계(Aggregate) 함수를 윈도우 스펙과 함께 사용하는 방법을 이해하면, 기존의 GROUP BY만으로 해결하기 힘든 세밀한 계산을 간단한 SQL 쿼리로 작성할 수 있음.
핵심 포인트는 다음과 같음.
1. 윈도우 함수를 사용하려면 파티션, 정렬, 프레임을 적절히 설정해야 함.
2. 순위 함수(RANK, DENSE_RANK, ROW_NUMBER 등), 분석 함수(LEAD, LAG, FIRST_VALUE 등), 집계 함수(SUM, AVG, MIN 등)를 OVER ( ... )와 함께 적용함.
3. 성능과 정확한 해석을 위해, 파티션 및 프레임을 올바르게 이해하고 지정하는 것이 중요함.
이처럼 Spark SQL 윈도우 함수는 OLAP(Online Analytical Processing)나 시계열/트렌드 분석 시 핵심적인 도구가 되며, 적절하게 사용하면 다차원적인 분석이 용이해짐.
전문적인 성능 최적화 관점에서는, 데이터 스키마 설계(파티션, 파일 포맷), 클러스터링 전략, Shuffle 최적화 등이 함께 고려되어야 함.
'Data Engineering > Spark' 카테고리의 다른 글
[Spark] Pyspark에서 repartition(), coalesce() 사용 (0) | 2025.03.29 |
---|---|
[Spark] Disk Spill (0) | 2025.03.28 |
[Spark] Apache Spark 구조 (2) | 2025.03.15 |
[Spark] Apache Iceberg (2) | 2025.03.14 |
[Spark] Apache ORC 파일 구조 (0) | 2025.03.09 |