Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

행 필터와 불리언 열 표현식

df.filter(condition)과 df.where(condition)는 같은 행 선택 기능입니다. 조건이 True인 행을 남기며 False나 NULL인 조건의 행은 남기지 않습니다. 계산 의미를 바꾸지 않는 범위에서 필요한 필터를 일찍 적용하면 이후 처리량을 줄일 수 있습니다.

범위 조건과 리터럴

from pyspark.sql import functions as F


def adults(df):
    return df.filter(F.col("age") >= 21)


def young_adults(df):
    return df.where((F.col("age") >= 21) & (F.col("age") < 35))


def chained_filters(df):
    return df.filter(F.col("age") >= 21).filter(F.col("age") < 35)

21은 포함하고 35는 제외합니다. 같은 조건을 나누어 호출하거나 &로 결합할 수 있습니다. 비교식은 괄호로 묶어 Python의 연산자 우선순위를 명확히 합니다.

열과 숫자/문자열을 비교하면 리터럴 표현식을 만들 수 있습니다. 이름이 열인지 고정 값인지 명시하려면 F.col()과 F.lit()을 구분합니다. Python 표현식 "X" == "Y"는 Spark에 전달되기 전에 False로 계산되므로 열 비교가 아닙니다.

from pyspark.sql import functions as F


def literal_match(df):
    return df.filter(F.col("X") == F.lit("Y"))


def column_match(df):
    return df.filter(F.col("X") == F.col("Y"))

논리식 결합

의미Column 표현식
ANDa & b
ORa | b
NOT~a
배타적 OR(a & ~b) | (~a & b)

Python의 and/or/not는 단일 Python 불리언을 평가하므로 분산 Column 조건의 결합에 사용하지 않습니다. 배타적 OR도 위의 불리언 정의식으로 작성합니다.

from pyspark.sql import functions as F


def selected_people(df):
    age_range = (F.col("age") >= 21) & (F.col("age") < 35)
    named_john = F.col("first_name") == "John"
    missing_last_name = F.col("last_name").isNull()
    return df.filter(age_range | named_john | missing_last_name)


def exactly_one_condition(df):
    adult = F.col("age") >= 21
    active = F.col("is_active_member")
    return df.filter((adult & ~active) | (~adult & active))

첫 함수는 나이 범위를 만족하거나 이름이 John이거나 성이 NULL인 행을 남깁니다. 두 번째는 두 조건 중 정확히 하나가 True인 행을 선택하며 NULL에는 SQL의 불리언 규칙을 적용합니다.

Python 반복문으로 작은 조건 목록을 조합할 수 있습니다. 다음 반복은 데이터 행을 수집하지 않고 a/b/c/d 중 한 접두사로 시작하는 조건식을 만듭니다.

from pyspark.sql import functions as F


def allowed_prefixes(df):
    column = F.col("column")
    condition = F.lit(False)
    for value in ["a", "b", "c", "d"]:
        condition = condition | column.startswith(value)
    return df.filter(condition)

LIKE와 정규식

Column.like(pattern)은 SQL LIKE 문자열 패턴, Column.rlike(pattern)은 정규식 패턴을 받습니다. PySpark 3.5의 이 Column 메서드에서는 문자열 패턴을 사용합니다. 다른 열에 들어 있는 패턴을 사용할 때는 함수형 F.like(value_column, pattern_column) 또는 F.rlike(value_column, pattern_column) 인터페이스와 구분합니다.

LIKE의 %는 0개 이상 문자, _는 정확히 한 문자입니다.

패턴의미
a%a로 시작
%aa로 끝남
%or%어느 위치에든 or 포함
_r%두 번째 글자가 r
a_%_%a로 시작하며 전체 길이가 최소 3
a%oa로 시작하고 o로 끝남
from pyspark.sql import functions as F


def names_starting_al(df):
    return df.filter(F.col("name").like("Al%"))


def formatted_phone_numbers(df):
    pattern = r"[0-9]{3}(?:.+)?[0-9]{3}(?:.+)?[0-9]{4}"
    return df.filter(F.col("phone").rlike(pattern))


def per_row_like_pattern(df):
    return df.filter(F.like(F.col("name"), F.col("pattern")))

Al%는 Alice와 일치합니다. 전화번호 예제는 412-512-1234, (555) 123-5123, 4121234444처럼 숫자 묶음 사이의 문자가 다른 문자열과 일치할 수 있습니다. 정규식이 전체 문자열에 맞아야 한다면 ^와 $ 경계를 사용합니다. 이 패턴은 전화번호 유효성의 모든 규칙을 검사하는 기능은 아닙니다.

시작, 끝과 포함 여부

Column.startswith(value), endswith(value), contains(value)는 문자열 값이나 다른 문자열 열로 비교할 수 있습니다. 정규식이나 LIKE 와일드카드를 해석하는 메서드는 아닙니다.

from pyspark.sql import functions as F


def required_id_parts(df):
    return df.filter(
        F.col("id").startswith("prefix-")
        & F.col("id").endswith("-suffix")
        & F.col("id").contains("string")
    )

substr

Column.substr(startPos, length)는 1부터 세는 시작 위치와 길이를 사용합니다. 정수 위치 또는 열 표현식으로 부분 문자열을 계산할 수 있습니다.

from pyspark.sql import functions as F


def first_three_letters(df):
    return df.select(F.col("name").substr(1, 3).alias("col"))


def middle_phone_prefix(df):
    return df.filter(F.col("phone").substr(5, 3) == "555")

Alice와 Bob의 첫 세 글자는 Ali와 Bob입니다. 두 번째 함수는 323-555-1234, 897-555-4126 같은 값에서 5~7번째 문자를 비교합니다.

isin과 between

Column.isin(*values)는 값 목록 또는 펼친 인자로 포함 여부를 검사합니다.

from pyspark.sql import functions as F


def selected_names(df):
    return df.filter(F.col("name").isin("Bob", "Mike"))


def selected_ages(df):
    return df.filter(F.col("age").isin([1, 2, 3]))

Column.between(lowerBound, upperBound)는 양쪽 경계를 포함합니다. 경계에 고정 값이나 열을 사용할 수 있습니다.

from pyspark.sql import functions as F


def age_bounds(df):
    return df.select(
        "name", "upperBound", "age",
        F.col("age").between(10, F.col("upperBound")).alias("age_within_range"),
    )
nameupperBoundageage_within_range
Taylor3035False
Sally4034True
Lucy2828True