0
# Row Operations
1
2
Structured data representation and manipulation with type-safe access methods for distributed data processing. Row objects represent individual records in Spark SQL operations.
3
4
## Capabilities
5
6
### Row Interface
7
8
Core interface for representing structured data records.
9
10
```scala { .api }
11
/**
12
* Represents one row of output from a relational operator
13
*/
14
trait Row extends Serializable {
15
/** Number of elements in the row */
16
def length: Int
17
18
/** Alias for length */
19
def size: Int
20
21
/** Schema for the row (can be null) */
22
def schema: StructType
23
24
/** Returns value at position i */
25
def apply(i: Int): Any
26
27
/** Returns value at position i */
28
def get(i: Int): Any
29
30
/** Checks if value at position i is null */
31
def isNullAt(i: Int): Boolean
32
33
/** Generic accessor with type casting */
34
def getAs[T](i: Int): T
35
36
/** Generic accessor by field name */
37
def getAs[T](fieldName: String): T
38
39
/** Get field index by name */
40
def fieldIndex(name: String): Int
41
42
/** Make a copy of the row */
43
def copy(): Row
44
45
/** Convert row to sequence */
46
def toSeq: Seq[Any]
47
48
/** Get multiple field values as a map by field names */
49
def getValuesMap[T](fieldNames: Seq[String]): Map[String, T]
50
51
/** Check if any field in the row is null */
52
def anyNull: Boolean
53
54
/** Compact JSON representation */
55
def json: String
56
57
/** Pretty JSON representation */
58
def prettyJson: String
59
60
/** String representation without separator */
61
def mkString: String
62
63
/** String representation with separator */
64
def mkString(sep: String): String
65
66
/** String representation with start, separator, and end */
67
def mkString(start: String, sep: String, end: String): String
68
}
69
```
70
71
### Primitive Type Accessors
72
73
Type-safe accessors for primitive data types.
74
75
```scala { .api }
76
trait Row extends Serializable {
77
// Boolean access
78
def getBoolean(i: Int): Boolean
79
80
// Numeric accessors
81
def getByte(i: Int): Byte
82
def getShort(i: Int): Short
83
def getInt(i: Int): Int
84
def getLong(i: Int): Long
85
def getFloat(i: Int): Float
86
def getDouble(i: Int): Double
87
88
// String and binary
89
def getString(i: Int): String
90
91
// Decimal numbers
92
def getDecimal(i: Int): java.math.BigDecimal
93
}
94
```
95
96
### Date and Time Accessors
97
98
Specialized accessors for temporal data types.
99
100
```scala { .api }
101
trait Row extends Serializable {
102
// Date types
103
def getDate(i: Int): java.sql.Date
104
def getLocalDate(i: Int): java.time.LocalDate
105
106
// Timestamp types
107
def getTimestamp(i: Int): java.sql.Timestamp
108
def getInstant(i: Int): java.time.Instant
109
}
110
```
111
112
### Collection Accessors
113
114
Accessors for complex collection types.
115
116
```scala { .api }
117
trait Row extends Serializable {
118
// Sequence/List access
119
def getSeq[T](i: Int): Seq[T]
120
def getList[T](i: Int): java.util.List[T]
121
122
// Map access
123
def getMap[K, V](i: Int): scala.collection.Map[K, V]
124
def getJavaMap[K, V](i: Int): java.util.Map[K, V]
125
126
// Nested struct access
127
def getStruct(i: Int): Row
128
}
129
```
130
131
### Row Factory Methods
132
133
Factory methods for creating Row instances.
134
135
```scala { .api }
136
object Row {
137
/** Create row from variable arguments */
138
def apply(values: Any*): Row
139
140
/** Create row from sequence */
141
def fromSeq(values: Seq[Any]): Row
142
143
/** Create row from tuple */
144
def fromTuple(tuple: Product): Row
145
146
/** Pattern matching support */
147
def unapplySeq(row: Row): Some[Seq[Any]]
148
149
/** Empty row singleton */
150
def empty: Row
151
}
152
```
153
154
## Usage Examples
155
156
**Creating rows:**
157
158
```scala
159
import org.apache.spark.sql.Row
160
161
// Create from individual values
162
val row1 = Row("Alice", 25, true, 55000.50)
163
164
// Create from sequence
165
val values = Seq("Bob", 30, false, 65000.75)
166
val row2 = Row.fromSeq(values)
167
168
// Create from tuple
169
val tuple = ("Charlie", 35, true, 75000.00)
170
val row3 = Row.fromTuple(tuple)
171
172
// Empty row
173
val emptyRow = Row.empty
174
```
175
176
**Accessing row data by position:**
177
178
```scala
179
val row = Row("Alice", 25, true, 55000.50, null)
180
181
// Basic access
182
val name: String = row.getString(0)
183
val age: Int = row.getInt(1)
184
val active: Boolean = row.getBoolean(2)
185
val salary: Double = row.getDouble(3)
186
187
// Check for nulls
188
val hasNullValue: Boolean = row.isNullAt(4)
189
190
// Generic access with casting
191
val nameGeneric: String = row.getAs[String](0)
192
val ageGeneric: Int = row.getAs[Int](1)
193
194
// Raw access (returns Any)
195
val rawName: Any = row.get(0)
196
val rawAge: Any = row(1) // shorthand for get(1)
197
```
198
199
**Accessing row data by field name:**
200
201
```scala
202
import org.apache.spark.sql.types._
203
204
// Create schema
205
val schema = StructType(Array(
206
StructField("name", StringType, false),
207
StructField("age", IntegerType, false),
208
StructField("active", BooleanType, false),
209
StructField("salary", DoubleType, true)
210
))
211
212
// Assuming row has schema attached
213
val name: String = row.getAs[String]("name")
214
val age: Int = row.getAs[Int]("age")
215
val salary: Double = row.getAs[Double]("salary")
216
217
// Get field index
218
val nameIndex: Int = row.fieldIndex("name")
219
```
220
221
**Working with complex data types:**
222
223
```scala
224
// Row with nested data
225
val complexRow = Row(
226
"Alice",
227
Seq("reading", "hiking", "coding"),
228
Map("home" -> "123-456-7890", "work" -> "098-765-4321"),
229
Row("123 Main St", "Anytown", "12345") // nested struct
230
)
231
232
// Access collections
233
val hobbies: Seq[String] = complexRow.getSeq[String](1)
234
val phones: Map[String, String] = complexRow.getMap[String, String](2)
235
236
// Access nested struct
237
val address: Row = complexRow.getStruct(3)
238
val street: String = address.getString(0)
239
val city: String = address.getString(1)
240
val zip: String = address.getString(2)
241
242
// Access with Java collections
243
val hobbiesList: java.util.List[String] = complexRow.getList[String](1)
244
val phonesMap: java.util.Map[String, String] = complexRow.getJavaMap[String, String](2)
245
```
246
247
**Row introspection and conversion:**
248
249
```scala
250
val row = Row("Alice", 25, true)
251
252
// Basic properties
253
val length: Int = row.length // 3
254
val size: Int = row.size // 3
255
256
// Convert to other formats
257
val sequence: Seq[Any] = row.toSeq
258
val jsonCompact: String = row.json
259
val jsonPretty: String = row.prettyJson
260
261
// Copy row
262
val rowCopy: Row = row.copy()
263
264
// Get values as map by field names
265
val fieldNames = Seq("name", "age")
266
val valuesMap: Map[String, Any] = row.getValuesMap[Any](fieldNames)
267
println(s"Values: $valuesMap") // Map("name" -> "Alice", "age" -> 25)
268
269
// Check if any field is null
270
val hasAnyNull: Boolean = row.anyNull
271
println(s"Row has null values: $hasAnyNull")
272
273
// Pattern matching
274
row match {
275
case Row(name: String, age: Int, active: Boolean) =>
276
println(s"Person: $name, Age: $age, Active: $active")
277
case _ =>
278
println("Unexpected row structure")
279
}
280
281
// Destructuring with unapplySeq
282
val Row(name, age, active) = row
283
```
284
285
**Working with nullable values:**
286
287
```scala
288
val rowWithNulls = Row("Alice", null, 25, null)
289
290
// Safe null checking
291
if (!rowWithNulls.isNullAt(1)) {
292
val middleName: String = rowWithNulls.getString(1)
293
} else {
294
println("Middle name is null")
295
}
296
297
if (!rowWithNulls.isNullAt(3)) {
298
val bonus: Double = rowWithNulls.getDouble(3)
299
} else {
300
println("Bonus is null")
301
}
302
303
// Using Option-like patterns with getAs
304
val maybeBonus = if (rowWithNulls.isNullAt(3)) None else Some(rowWithNulls.getAs[Double](3))
305
```
306
307
**Error handling:**
308
309
```scala
310
val row = Row("Alice", 25)
311
312
try {
313
// This will throw IndexOutOfBoundsException
314
val nonExistent = row.getString(5)
315
} catch {
316
case _: IndexOutOfBoundsException =>
317
println("Field index out of bounds")
318
}
319
320
try {
321
// This will throw ClassCastException if types don't match
322
val wrongType: Boolean = row.getAs[Boolean](1) // age field as Boolean
323
} catch {
324
case _: ClassCastException =>
325
println("Type casting failed")
326
}
327
```