Notebooks — feature_engineering-movielens-spark-iceberg¶
Auto-extracted from jupyter/notebook.ipynb and zeppelin/notebook.zpln.
Both notebooks implement identical logic in PySpark and Scala.
1. Section map¶
| Subsection | Scala (Zeppelin) | PySpark (Jupyter) |
|---|---|---|
| 2.1 Setup | ✓ | ✓ |
| 2.2 Read | ✓ | ✓ |
| 2.3 Transform | ✓ | ✓ |
| 2.4 Write | ✓ | ✓ |
| 2.5 Verify | ✓ | ✓ |
2. Walkthrough¶
2.1 Setup¶
Scala (Zeppelin):
import spark.implicits._
import org.apache.spark.sql.functions._
// spark pre-bound (Spark Connect + lakehouse catalog)
PySpark (Jupyter):
from pyspark.sql import SparkSession
from pyspark.sql import functions as F
spark = SparkSession.builder.remote("sc://spark-connect:15002").getOrCreate()
2.2 Read¶
Scala (Zeppelin):
val ratings = spark.read.option("header", true).option("inferSchema", true).csv("s3a://landing/movielens/ratings.csv")
PySpark (Jupyter):
ratings = spark.read.option("header", True).option("inferSchema", True).csv("s3a://landing/movielens/ratings.csv")
2.3 Transform¶
Scala (Zeppelin):
val userFeatures = ratings.groupBy($"userId").agg(avg($"rating").as("avg_rating"), count("*").as("num_ratings"))
val movieFeatures = ratings.groupBy($"movieId").agg(avg($"rating").as("movie_avg"), count("*").as("popularity"))
PySpark (Jupyter):
userFeatures = ratings.groupBy("userId").agg(F.avg("rating").alias("avg_rating"), F.count("*").alias("num_ratings"))
movieFeatures = ratings.groupBy("movieId").agg(F.avg("rating").alias("movie_avg"), F.count("*").alias("popularity"))
2.4 Write¶
Scala (Zeppelin):
userFeatures.writeTo("lakehouse.gold.ml_user_features").using("iceberg").createOrReplace()
movieFeatures.writeTo("lakehouse.gold.ml_movie_features").using("iceberg").createOrReplace()
PySpark (Jupyter):
userFeatures.writeTo("lakehouse.gold.ml_user_features").using("iceberg").createOrReplace()
movieFeatures.writeTo("lakehouse.gold.ml_movie_features").using("iceberg").createOrReplace()
2.5 Verify¶
Scala (Zeppelin):
PySpark (Jupyter):
spark.table("lakehouse.gold.ml_movie_features").orderBy(F.desc("popularity")).show(10, truncate=False)
3. Scala / PySpark parity¶
Both notebooks share the same numbered sections and produce identical Iceberg tables; only the language and interpreter differ.
4. How to run¶
Open the scenario's zeppelin/notebook.zpln on the Atlas Zeppelin UI or jupyter/notebook.ipynb on JupyterHub, then run all paragraphs/cells top to bottom.