前言
一直在说Dataframe是Dataset的特例,DataFrame=Dataset[Row],可Row是什么东西呢?
什么是Row
顾名思义:就是一行数据
Row是org.apache.spark.sql包下的一个特质
简单的理解:
Row是一个类型,跟Car、Person这些的类型一样,所有的表结构信息都用Row来表示。
什么时候会用到这个Row呢?
煮个例子
通过读取文件创建一个DataFrame:
import spark.implicits._
val dfA: DataFrame = spark.read.textFile(path = "./data/infoA")
.map(_.split(","))
.map(x => (x(0), x(1)))
.toDF("tel", "name")
如果要把这个DataFrame转换为Dataset,只需要写个样例类,然后调用DataFrame的as方法:
case class User(tel: String, name: String)
import spark.implicits._
val dsA: Dataset[User] = spark.read.textFile(path = "./data/infoA")
.map(_.split(","))
.map(x => (x(0), x(1)))
.toDF("tel", "name")
.as[User]
这个列子想说明,如果返回的是DataFrame,那么其实可以看成是Dataset[Row]。
那么如何处理这个Row类型的Dataset呢?
先从官网举的几个"无用"的例子说起
- 在Java中可以使用 RowFactory.create() 来创建Row,在Scala中用 Row.apply() 创建
- Row可以通过几个字段来构建
import org.apache.spark.sql._
// Create a Row from values.
val row1 = Row(1, true, "a string", null)
// Create a Row from a Seq of values.
val row2 = Row.fromSeq(Seq(1, true, "a string", null))
- 如何访问Row的数据
import org.apache.spark.sql._
val row = Row(1, true, "a string", null)
// row: Row = [1,true,a string,null]
val firstValue = row(0)
// firstValue: Any = 1
val fourthValue = row(3)
// fourthValue: Any = null
// using the row from the previous example.
val firstValue = row.getInt(0)
// firstValue: Int = 1
val isNull = row.isNullAt(3)
// isNull: Boolean = true
- 在Scala中还可以进行模式匹配:
import org.apache.spark.sql._
val pairs = sql("SELECT key, value FROM src").rdd.map {
case Row(key: Int, value: String) =>
key -> value
}
上面的案例在开发中几乎没有用,写上纯属是为了进一步感受Row是个什么东西
Row在开发中可能用到的场景
说实话,基本上对于研发人员来说,真正使用Row的场景不多,因为现在使用spark进行开发一般都是:
spark.sql("SELECT * FROM TABLE A")
这样的句式返回的正是DataFrame或者说是Dataset[Row]
可如果想要处理这个Row,就有点难办了,比如我要把整个手机号存入到一个Array或者List中,一般都要把Row转为String,这个时候就用到了Row的mkString()方法
val dfA: DataFrame = spark.read.textFile(path = "./data/infoA")
.map(_.split(","))
.map(x => (x(0), x(1)))
.toDF("tel", "name")
val telArr: Array[String] = dfA.select("tel").map(row => row.mkString).collect()
val telList: List[String] = telArr.toList
val telSeq: Seq[String] = telArr.toSeq
println(telList)
println(telSeq)
结果:
List(13111111111, 13222222222, 13333333333, 13444444444, 13555555555, 13666666666, 13777777777, 13888888888, 13999999999)
WrappedArray(13111111111, 13222222222, 13333333333, 13444444444, 13555555555, 13666666666, 13777777777, 13888888888, 13999999999)