A data engineering team is building a Gold layer aggregation pipeline. They have a Silver layer PySpark DataFrame silver_orders_df with columns customer_id, order_date, product_category, order_total, and is_returned (BOOLEAN). The business requires a summary DataFrame with the following per-customer, per-category metrics: (1) total number of orders, (2) total revenue from non-returned orders only, (3) percentage of orders that were returned (return rate as a decimal between 0 and 1), and (4) the rank of each customer within each product category by total revenue (rank 1 = highest revenue). Null order_total values should be treated as 0 in all revenue calculations. Which PySpark implementation is correct?
Show answer & explanation
Correct answer: C
WHY C: count('*') counts all rows including those with null values, giving the correct total order count. ~col('is_returned') is the PySpark bitwise NOT for boolean negation, correctly identifying non-returned orders. coalesce(col('order_total'), lit(0)) substitutes null revenue with 0. col('is_returned').cast('int') converts BOOLEAN True/False to 1/0 for summing, and dividing by count('*') gives the return rate as a decimal. rank() is correct for ranking with gaps on ties (vs dense_rank which has no gaps). WHY NOT A: avg('is_returned') does compute the mean of True/False cast to 1/0 in some contexts, but is_returned is a BOOLEAN column and avg() on a boolean column may not behave consistently across Spark versions. More critically, sum(coalesce('order_total', lit(0))) passes a string literal to coalesce instead of col('order_total') — this is ambiguous and likely to fail at runtime. WHY NOT B: col('is_returned') == False uses Python == comparison which should instead use .eqNullSafe() or col('is_returned') == lit(False) for proper boolean comparison. Also, dense_rank() assigns consecutive ranks without gaps on ties, while rank() is more commonly expected for 'rank by highest revenue' scenarios where tied records share a rank and the next rank is skipped. WHY NOT D: Pre-filtering with .filter(col('is_returned') == False) before the groupBy removes all returned orders from the dataset, so total_orders would count only non-returned orders rather than all orders. The return_rate is hardcoded to 0.0, which ignores the actual return data entirely.