Unit 3: Using RDD for Creating Applications in Spark and Graph Analytics - Subjective Questions
INT315 — Cluster Computing • Practice Questions with Detailed Answers
20 questions
Define a Resilient Distributed Dataset (RDD) in Apache Spark. Explain its major features and discuss how these features support distributed data processing.
Resilient Distributed Dataset (RDD) is an immutable, distributed collection of objects that can be processed in parallel across a cluster.
Major features of RDDs:
- Immutability: Once an RDD is created, it cannot be modified. Any transformation produces a new RDD.
- Distributed partitioning: The data is divided into partitions and distributed across cluster nodes.
- Fault tolerance: Spark remembers the lineage of transformations and can recompute lost partitions instead of replicating all data.
- Lazy evaluation: Transformations are not executed immediately. They are evaluated only when an action is called.
- In-memory processing: Frequently used RDDs can be cached in memory to reduce disk access.
- Parallel processing: Operations are executed simultaneously on multiple partitions.
These properties make RDDs suitable for iterative algorithms, interactive queries, and large-scale analytics.
Explain the concept of RDD lineage and describe how lineage provides fault tolerance in Spark.
RDD lineage is the record of the sequence of transformations used to create an RDD from its source data. Spark stores this dependency information as a directed acyclic graph.
For example, if an input RDD is transformed using map and then filter, Spark records the relationship between the input RDD and the resulting RDD.
Fault-tolerance process:
- Each RDD remembers how it was derived.
- If a partition is lost because of node failure, Spark identifies the transformations required to recreate it.
- Only the lost partition is recomputed from the original data or its parent partitions.
- The entire dataset does not need to be replicated.
This approach is called lineage-based fault tolerance. It reduces storage overhead while allowing Spark to recover from failures efficiently.
Describe different ways of creating RDDs in Spark. Provide suitable examples using parallelized collections and external datasets.
RDDs can be created mainly in the following ways:
- From an existing collection: A local collection can be distributed using
parallelize.
val numbers = sc.parallelize(Seq(1, 2, 3, 4, 5))- From an external storage system: Spark can read text files, HDFS files, cloud storage objects, or other supported data sources.
val lines = sc.textFile("hdfs://server/data/input.txt")- From another RDD: Applying a transformation to an existing RDD creates a new RDD.
val words = lines.flatMap(line => line.split(" "))The parallelize method is useful for testing and small collections. Methods such as textFile are generally used for production data stored in distributed storage.
Explain RDD transformations and actions. Distinguish between them with appropriate examples.
RDD operations are classified as transformations or actions.
Transformations:
- Transformations create a new RDD from an existing RDD.
- They are evaluated lazily.
- Examples include
map,filter,flatMap,union, anddistinct.
val filtered = numbers.filter(x => x > 2)Actions:
- Actions trigger the execution of the transformation graph.
- They return a result to the driver program or write data to storage.
- Examples include
count,collect,reduce,first, andsaveAsTextFile.
val total = filtered.reduce((a, b) => a + b)The distinction is important because Spark delays computation until an action is requested. This allows Spark to optimize the complete execution plan before processing the data.
Explain the map, flatMap, and filter RDD functions. Compare their behavior using an example.
The map, flatMap, and filter functions are common one-to-one, one-to-many, and selection transformations.
map: Applies a function to every element and produces exactly one output element for each input element.
val doubled = numbers.map(x => x * 2)flatMap: Applies a function to every element and flattens the resulting collections into one RDD. It can produce zero, one, or many output elements per input.
val words = lines.flatMap(line => line.split(" "))filter: Retains only elements that satisfy a Boolean condition.
val evenNumbers = numbers.filter(x => x % 2 == 0)Thus, map changes each record, flatMap expands or flattens records, and filter removes records that do not satisfy a condition.
Describe the key pair RDD functions used for aggregation and explain how reduceByKey, groupByKey, and aggregateByKey differ.
A pair RDD contains records in the form (key, value) and supports key-based operations.
reduceByKey: Combines values having the same key using an associative and commutative function. It performs local combining before data shuffling, making it relatively efficient.
val totals = pairs.reduceByKey((a, b) => a + b)groupByKey: Groups all values associated with the same key. It may transfer a large amount of data during shuffling and is less efficient when aggregation is required.
val grouped = pairs.groupByKey()aggregateByKey: Uses a zero value and separate functions for combining values within a partition and merging results across partitions. It can produce a result type different from the input value type.
reduceByKey is suitable for simple associative reductions, groupByKey for situations requiring all values, and aggregateByKey for flexible partition-level aggregation.
Explain lazy evaluation in Spark. Derive the sequence of execution for an RDD program containing transformations followed by an action.
In Spark, lazy evaluation means that transformations are recorded but not executed immediately. Execution begins only when an action is invoked.
Consider the following program:
val lines = sc.textFile("data.txt")
val words = lines.flatMap(line => line.split(" "))
val validWords = words.filter(word => word.nonEmpty)
val count = validWords.count()Execution sequence:
textFiledefines the input RDD.flatMaprecords a transformation from lines to words.filterrecords another transformation.countis an action, so Spark starts execution.- Spark constructs a logical dependency graph from the input RDD to
validWords. - The graph is divided into stages according to shuffle boundaries.
- Tasks are created for partitions and sent to worker nodes.
- Partial counts are calculated and combined to produce the final result.
Lazy evaluation allows Spark to combine operations, avoid unnecessary computation, and optimize data movement.
Explain narrow and wide dependencies in RDDs. Compare their effects on stages, data movement, and performance.
Narrow dependency: Each child partition depends on a small number of parent partitions, usually one. Examples include map, filter, and mapValues.
Wide dependency: A child partition depends on multiple parent partitions. Data must be redistributed across the cluster. Examples include groupByKey, reduceByKey, and sortByKey.
Comparison:
- Narrow transformations usually do not require data shuffling.
- Wide transformations require a shuffle across executors.
- Spark can combine sequences of narrow transformations into one stage.
- A wide dependency usually creates a stage boundary.
- Narrow operations are generally faster and more fault tolerant because lost data can be recomputed locally.
- Wide operations may involve network transfer, disk spill, sorting, and increased execution time.
Understanding dependencies helps developers organize transformations and reduce unnecessary shuffles.
Discuss RDD persistence and caching. Explain the available storage levels and the situations in which caching is useful.
RDD persistence stores computed partitions for reuse. The cache() method is shorthand for persisting an RDD using the default storage level.
val data = sc.textFile("data.txt").filter(_.nonEmpty)
data.cache()
val firstResult = data.count()
val secondResult = data.filter(_.contains("Spark")).count()Common storage levels include:
- Memory-only: Stores partitions as deserialized objects in memory.
- Memory-and-disk: Stores partitions in memory and spills those that do not fit to disk.
- Disk-only: Stores partitions only on disk.
- Serialized levels: Store data in serialized form to reduce memory usage.
- Replicated levels: Keep additional copies for improved availability.
Caching is useful when an RDD is reused by multiple actions, especially in iterative machine learning or interactive analysis. It may be unnecessary for an RDD used only once because caching itself has memory and serialization overhead.
Describe important RDD actions and methods such as collect, count, take, first, reduce, and saveAsTextFile.
RDD actions initiate computation and produce results or side effects.
collect: Returns all elements to the driver. It should be used only when the result is small enough to fit in driver memory.count: Returns the number of elements in the RDD.take(n): Returns the first elements and is useful for inspecting data.first: Returns the first element of the RDD.reduce: Combines all elements using an associative and commutative function.
val sum = numbers.reduce((a, b) => a + b)saveAsTextFile: Writes RDD contents to a directory in the configured storage system.
lines.saveAsTextFile("output/lines")These methods have different memory and execution implications, so the action should be selected according to the size and purpose of the result.
Explain how to invoke and use the Spark shell. Describe the roles of the Spark context, Spark session, and command-line options.
The Spark shell is an interactive environment for executing Spark commands and testing applications.
Invocation examples:
spark-shell
pyspark
spark-shell --master local[2]spark-shellprovides a Scala-based interactive environment.pysparkprovides a Python-based interactive environment.--master local[2]runs Spark locally using two worker threads.
In older Spark versions, the shell automatically creates a Spark context, commonly referenced as sc. The Spark context coordinates RDD operations and communication with the cluster.
Modern Spark applications commonly use a Spark session, referenced as spark, which provides a unified entry point for DataFrame, SQL, and lower-level Spark functionality.
Typical shell workflow:
- Start the shell.
- Load data using
textFileor another input method. - Apply transformations.
- Invoke an action such as
countorcollect. - Inspect or save the result.
The shell is useful for learning, debugging, exploratory analysis, and validating transformations before writing a complete application.
Define shared variables in Spark. Explain broadcast variables and accumulators, including their uses and limitations.
Shared variables allow information to be shared efficiently between the driver and executor tasks.
Broadcast variables:
- A broadcast variable is a read-only value cached on each executor.
- It prevents the same large read-only data from being sent with every task.
- It is useful for lookup tables, configuration data, and small reference datasets.
val lookup = sc.broadcast(Map("A" -> 1, "B" -> 2))
val result = records.map(record => lookup.value.getOrElse(record, 0))Accumulators:
- An accumulator is a variable that tasks can add to, while only the driver reads its final value.
- It is useful for counters, error counts, and diagnostic information.
val errors = sc.longAccumulator("errors")Broadcast variables must not be modified by executors. Accumulators should not be used to control program logic because task retries and recomputation can affect update behavior. Both mechanisms should be used carefully in distributed applications.
Explain the architecture and basic data model of Spark GraphX. Describe vertices, edges, and the property graph.
Spark GraphX is a graph processing API built on Spark. It represents a graph as a property graph consisting of directed edges and properties attached to both vertices and edges.
Main components:
- Vertices: Identified by unique vertex IDs and associated with vertex properties.
- Edges: Directed connections between a source vertex and a destination vertex, with an edge property.
- Triplets: A combination of a source vertex, an edge, and a destination vertex.
- Vertex and edge RDDs: GraphX stores graph data using distributed RDD-based structures.
A graph can be represented conceptually as:
where is the set of vertices and is the set of directed edges.
For example, in a social network, users are vertices, friendships are edges, user profiles are vertex properties, and relationship types are edge properties. GraphX combines graph-parallel computation with Spark's distributed data processing capabilities.
Discuss the important features of Spark GraphX and explain how it differs from a general-purpose graph database.
Spark GraphX provides several features for large-scale graph analytics:
- Distributed graph processing: Graphs are partitioned and processed across a cluster.
- Integration with Spark: GraphX works with RDDs, DataFrames, Spark SQL, and other Spark libraries.
- Property graph model: Vertices and edges can store application-specific attributes.
- Graph operators: It provides operations such as
mapVertices,mapEdges, andmapTriplets. - Graph algorithms: It includes algorithms such as PageRank, connected components, triangle counting, and label propagation.
- Fault tolerance: Graph data benefits from Spark's RDD lineage mechanism.
- Reusable transformations: Graphs can be transformed and combined with non-graph datasets.
A graph database is primarily designed for low-latency transactional traversal and interactive queries. GraphX is designed mainly for batch and iterative analytics over very large graphs. Graph databases emphasize persistent indexed storage, whereas GraphX emphasizes distributed computation using Spark.
Explain the GraphX operations mapVertices, mapEdges, and mapTriplets with suitable examples.
GraphX provides transformation operations for modifying graph properties without changing the basic graph structure.
mapVertices: Applies a function to every vertex and produces a graph with updated vertex properties.
val updatedGraph = graph.mapVertices((id, property) => property.toUpperCase)mapEdges: Applies a function to every edge and updates edge properties.
val weightedGraph = graph.mapEdges(edge => edge.attr.toDouble)mapTriplets: Applies a function to every edge triplet. The function can inspect the source vertex, destination vertex, and edge, making it useful when an update depends on neighboring vertices.
val tripletGraph = graph.mapTriplets(triplet => triplet.srcAttr + triplet.dstAttr)These operations are transformations and therefore are evaluated lazily. They return new graph objects while preserving the immutability of the original graph.
Describe the aggregateMessages operation in GraphX. Explain the role of the message-sending and message-merging functions.
The aggregateMessages operation is used to exchange information between neighboring vertices and aggregate the received messages.
It contains two important functions:
- Message-sending function: Runs on each edge triplet and sends a message to the source vertex, destination vertex, or both.
- Message-merging function: Combines multiple messages received by the same vertex.
Conceptually, the operation performs the following steps:
- Inspect each edge and its endpoint properties.
- Generate messages based on a condition or computation.
- Route messages to destination vertices.
- Merge messages for each vertex using an associative function.
- Produce a vertex RDD containing the aggregated values.
For example, a graph can send each vertex's value to its neighbors and calculate the maximum neighboring value. aggregateMessages is more flexible and generally preferred over older message aggregation methods because it clearly separates message generation from message combination.
Explain the Pregel API in GraphX and describe how it can be used to implement an iterative graph algorithm.
The GraphX Pregel API provides a bulk-synchronous model for iterative graph computation. Computation proceeds in repeated supersteps.
Main functions:
- Vertex program: Updates a vertex using its current property and the aggregated message.
- Message-sending function: Sends messages along selected edges.
- Message-merging function: Combines messages received by a vertex.
Execution process:
- Vertices begin with initial properties.
- Active vertices receive messages.
- The vertex program computes new properties.
- Updated vertices send messages to neighboring vertices.
- The process repeats until no messages remain or a maximum iteration count is reached.
Pregel can implement algorithms such as shortest paths, connected components, and ranking. For example, in shortest-path computation, vertices send their known distance to neighbors, and each neighbor updates its distance when a smaller value is received. The process converges when no vertex can improve its value.
Compare the PageRank and connected components algorithms available in GraphX. Explain their purpose and typical applications.
PageRank:
- Assigns an importance score to each vertex.
- A vertex receives a higher score when it is linked by important vertices.
- Scores are iteratively updated until they stabilize or a specified number of iterations is reached.
- It is used for ranking web pages, recommending influential users, and identifying important entities.
Connected components:
- Assigns the same component identifier to vertices that are connected through paths.
- It identifies groups of mutually reachable vertices in an undirected interpretation of the graph.
- It is used for community discovery, network segmentation, and identifying isolated groups.
Difference: PageRank measures relative importance, while connected components identify membership in connected groups. PageRank is a ranking problem, whereas connected components is a graph partitioning problem.
Explain feature extraction and feature transformation in Spark. Distinguish between the two concepts and state why they are important in machine learning applications.
Feature extraction converts raw data into meaningful measurable attributes. For example, a text document can be converted into word-count or term-frequency features.
Feature transformation modifies existing features into a form that is more suitable for modeling. Examples include scaling, normalization, encoding categorical values, and reducing dimensionality.
Examples in Spark:
Tokenizersplits text into individual tokens.HashingTFconverts tokens into a numerical feature vector.IDFreduces the influence of common terms.StringIndexerconverts categorical labels into numeric indices.VectorAssemblercombines multiple columns into one feature vector.StandardScalerstandardizes feature values.
These processes are important because machine learning algorithms require numerical, consistent, and informative inputs. Proper extraction and transformation can improve model accuracy, convergence, and interpretability.
Describe the steps involved in transforming text data into feature vectors using Spark.
A typical Spark text-processing pipeline includes the following steps:
- Load the documents: Read text data from a distributed source.
- Tokenize the text: Split each document into individual words.
- Clean the tokens: Convert text to a common case and remove punctuation, stop words, or invalid tokens.
- Extract term frequencies: Use a method such as
HashingTFto represent each document as a vector of word frequencies. - Apply inverse document frequency: Use
IDFto reduce the weight of terms appearing in many documents. - Assemble features: Combine the resulting vector with other numerical attributes if required.
- Train a model: Supply the feature vector to a Spark machine learning algorithm.
The resulting representation is usually a sparse vector because most documents contain only a small portion of the total vocabulary. This pipeline converts unstructured text into numerical input suitable for classification, clustering, or recommendation.
Define a Resilient Distributed Dataset (RDD) in Apache Spark. Explain its major features and discuss how these features support distributed data processing.
Resilient Distributed Dataset (RDD) is an immutable, distributed collection of objects that can be processed in parallel across a cluster.
Major features of RDDs:
- Immutability: Once an RDD is created, it cannot be modified. Any transformation produces a new RDD.
- Distributed partitioning: The data is divided into partitions and distributed across cluster nodes.
- Fault tolerance: Spark remembers the lineage of transformations and can recompute lost partitions instead of replicating all data.
- Lazy evaluation: Transformations are not executed immediately. They are evaluated only when an action is called.
- In-memory processing: Frequently used RDDs can be cached in memory to reduce disk access.
- Parallel processing: Operations are executed simultaneously on multiple partitions.
These properties make RDDs suitable for iterative algorithms, interactive queries, and large-scale analytics.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →