Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

DataFrame 조인

left.join(right, on, how)는 다른 DataFrame이나 자기 자신과 행을 연결합니다. on에는 공통 열 이름, 열 이름 목록 또는 불리언 조건식을 전달할 수 있습니다.

같은 이름의 키

def left_join(left, right):
    return left.join(right, "key", "left")


def multi_key_join(left, right):
    return left.join(right, ["column1", "column2", "column3"], "left")

문자열 이름으로 공통 키를 지정하면 결과의 키 열은 하나로 합쳐집니다. 두 입력에서 키 이름이 다르면 먼저 이름을 맞춘 뒤 이 형식을 사용할 수 있습니다. 왼쪽 조인은 일치하는 오른쪽 행이 없어도 왼쪽 행을 남깁니다. 오른쪽에 같은 키가 여러 개면 왼쪽 행이 여러 결과와 결합할 수 있습니다.

키 외 열 이름 충돌

키 이외의 같은 이름은 자동으로 하나로 합쳐지지 않습니다. 조인 전에 필요 없는 열을 제거하거나 이름을 바꿉니다. 전체 열에 접두사를 붙이는 다음 함수는 하나의 select에서 이름을 정합니다.

from pyspark.sql import functions as F


def prefix_columns(df, prefix="some_prefix_"):
    return df.select(*[
        F.col("`" + name.replace("`", "``") + "`").alias(prefix + name)
        for name in df.columns
    ])

키까지 이름이 바뀌므로 조인 조건에서도 새 이름을 사용해야 합니다. 이미 조인해 중복 이름이 생긴 뒤에는 단순 이름 참조가 모호할 수 있습니다.

여러 관계를 결합한 조인

다음 조건은 ID가 같고 왼쪽 start가 오른쪽 end보다 빠르며, 왼쪽 X가 some_value이면 오른쪽 Y가 some_other_value여야 한다는 규칙입니다. X가 그 값이 아닌 경우 Y에 대한 조건은 True로 둡니다.

from pyspark.sql import functions as F


def conditional_left_join(left, right):
    left = left.alias("l")
    right = right.alias("r")
    same_id = F.col("l.ID") == F.col("r.ID")
    date_order = F.col("l.start") < F.col("r.end")
    conditional_match = F.when(
        F.col("l.X") == "some_value",
        F.col("r.Y") == "some_other_value",
    ).otherwise(True)
    joined = left.join(right, same_id & date_order & conditional_match, "left")
    return joined.select(
        "l.*", F.col("r.end").alias("right_end"), F.col("r.Y").alias("right_y")
    )

입력에는 예제의 ID/start/X 및 ID/end/Y 열이 있어야 합니다. 결과는 왼쪽 열 전체와 필요한 오른쪽 end/Y를 충돌 없는 이름으로 선택합니다. 불리언 조건으로 조인한 뒤에는 결과에 남길 키와 열을 명시하는 편이 분명합니다.

Cross join

crossJoin()은 두 입력의 모든 행 조합을 만듭니다. 행 수가 각각 N과 M이면 결과는 N×M이므로 메모리와 계산량이 크게 늘 수 있습니다. 조인 직후 조건으로 대부분의 행을 제거하려는 목적이면 그 조건을 join의 on에 넣습니다.

Foundry 저장소의 Spark 설정에서 CROSS_JOIN_ENABLED 프로필을 가져오고 configure에 적용합니다. 다음 예제에서 상품 표와 지역 표의 열 이름은 서로 겹치지 않아야 합니다.

from transforms.api import Input, Output, configure, transform_df


@configure(profile=["CROSS_JOIN_ENABLED"])
@transform_df(
    Output("/Example Project/Outputs/product_regions"),
    products=Input("/Example Project/Inputs/products"),
    regions=Input("/Example Project/Inputs/regions"),
)
def compute(products, regions):
    return products.crossJoin(regions)