Nếu bạn mạnh SQL thì đây là cách nhanh nhất để dùng Spark. DataFrame API và SQL thực ra chạy trên cùng một engine (Catalyst optimizer), cho ra cùng kết quả và cùng hiệu năng — chọn cái nào hoàn toàn tùy thói quen của bạn.
Spark không tự biết DataFrame của bạn tên là gì trong câu SQL. Muốn dùng spark.sql(...), trước hết phải đăng ký DataFrame thành một view — coi như đặt cho nó một cái tên bảng để câu lệnh SQL tham chiếu tới.
# đăng ký DataFrame thành view tạm sales.createOrReplaceTempView("sales") customers.createOrReplaceTempView("customers") # giờ có thể viết SQL thuần spark.sql(""" SELECT category, SUM(qty*unit_price) AS revenue FROM sales WHERE qty > 0 GROUP BY category ORDER BY revenue DESC """).show()
Vài điểm quan trọng về view:
global_temp, xuyên session trong cùng application. Khi query phải gọi đầy đủ: SELECT * FROM global_temp.sales.spark.sql(...) luôn trả về một DataFrame, nên bạn có thể tiếp tục .filter(), .show(), hay ghi ra file như bất kỳ DataFrame nào.Mọi thao tác trong DataFrame API đều có câu SQL tương ứng. Cả hai được Catalyst dịch về cùng một kế hoạch thực thi, nên đừng lo lắng về hiệu năng — chúng giống hệt nhau.
| DataFrame API | SQL tương ứng |
|---|---|
df.filter(df.qty > 0) | WHERE qty > 0 |
df.groupBy("category").agg(sum("amount")) | GROUP BY category + SUM(amount) |
a.join(b, "customer_id") | FROM a JOIN b ON ... |
df.orderBy(df.revenue.desc()) | ORDER BY revenue DESC |
df.withColumn("amount", col("qty")*col("unit_price")) | SELECT qty*unit_price AS amount |
df.select("region").distinct() | SELECT DISTINCT region |
JOIN trong Spark SQL viết y như SQL truyền thống. Ví dụ tính doanh thu theo vùng bằng cách ghép bảng sales với customers:
spark.sql(""" SELECT c.region, SUM(s.qty*s.unit_price) AS revenue FROM sales s JOIN customers c ON s.customer_id = c.customer_id GROUP BY c.region ORDER BY revenue DESC """).show()
Các kiểu JOIN bạn sẽ gặp:
NULL.NULL.s, c) giúp câu lệnh ngắn gọn và tránh nhập nhằng khi hai bảng có cột trùng tên.Khi logic dài, viết tất cả vào một câu SELECT lồng nhau rất khó đọc. CTE (Common Table Expression) — mệnh đề WITH — cho phép đặt tên cho từng bước trung gian, rồi dùng lại như một bảng:
spark.sql(""" WITH cat_rev AS ( SELECT category, SUM(qty*unit_price) AS rev FROM sales WHERE qty > 0 GROUP BY category ) SELECT * FROM cat_rev WHERE rev > 1000000 ORDER BY rev DESC """).show()
Ở đây cat_rev gom doanh thu theo nhóm hàng trước, rồi câu SELECT chính chỉ việc lọc những nhóm vượt mốc 1 triệu. CTE giúp query dễ đọc, tách bạch từng tầng logic, và bạn có thể nối nhiều CTE liên tiếp bằng dấu phẩy.
SELECT ngay trong FROM hoặc WHERE. CTE thường dễ đọc hơn subquery lồng sâu khi logic phức tạp.Window function tính toán trên một "cửa sổ" các dòng mà không gom chúng lại như GROUP BY. Ví dụ xếp hạng đơn hàng theo doanh thu trong từng nhóm sản phẩm:
spark.sql(""" SELECT order_id, category, amount, ROW_NUMBER() OVER ( PARTITION BY category ORDER BY amount DESC ) AS rn FROM ( SELECT *, qty*unit_price AS amount FROM sales WHERE qty > 0 ) """).show()
Cấu trúc cốt lõi là OVER (PARTITION BY ... ORDER BY ...):
WHERE rn <= 3.Vì hai cách cho cùng hiệu năng, lựa chọn chỉ là về sự thuận tiện và bảo trì:
spark.sql("...").explain() vẫn xem được kế hoạch thực thi y như khi gọi trên DataFrame — tiện để hiểu Spark tối ưu câu SQL của bạn ra sao.Đăng ký view cho sales và customers, rồi giải 3 bài sau bằng spark.sql(...):
GROUP BY theo cột phương thức, SUM(qty*unit_price), sắp xếp giảm dần.JOIN sales với customers, GROUP BY khách, ORDER BY tổng chi tiêu DESC rồi LIMIT 5.