简介: 从Spark 2.0至Spark 2.4版本,目前支持数据源有4种,其中Kafka 数据源使用作为广泛,其他数据源主要用于开发测试程序。
1. Socket数据源
-
用nc -lk 端口号向Socket监听的端口发送数据,用于测试使用:
1.host
2.port 参数
-
Console 接收器
代码:
import org.apache.commons.lang3.StringUtils
import org.apache.spark.SparkConf
import org.apache.spark.sql.streaming.{
OutputMode, StreamingQuery, Trigger}
import org.apache.spark.sql.{
DataFrame, Dataset, Row, SparkSession}
/**
* @author liu a fu
* @date 2021/1/25 0025
* @version 1.0
* @DESC Structured Streaming模拟Socket初体验
* 1-初始化SParkSession
* 2-读取数据源
* 3-FlatMap
* 4-gruopBy
* 5-count
* 6-orderby
* 7-将结果写入
*/
object _01StructuredAndSocket {
def main(args: Array[String]): Unit = {
//1-环境准备
val conf: SparkConf = new SparkConf()
.setAppName(this.getClass.getSimpleName.stripSuffix("$"))
.setMaster("local[6]")
val spark: SparkSession = SparkSession
.builder()
.config(conf)
//注意如果默认情况下SparkSQL发生shuffle的分区个数为200个,这里设置分区个数小一些
.config("spark.sql.shuffle.partitions", 2)
.getOrCreate()
spark.sparkContext.setLogLevel("WARN")
import spark.implicits._
//2-读取数据源
// Returns a `DataStreamReader` that can be used to read streaming data in as a `DataFrame`.
val reviceData: DataFrame = spark
.readStream
.format("socket")
.option("host", "node1")
.option("port", 9999)
.load()
//reviceData.printSchema()
//root
// |-- value: string (nullable = true)
//3-FlatMap-注意这里的DataFrame不能直接使用split的方法,不知道泛型类型 DataFrame--->DataSet 做一个as[String]类型转换
//4-gruopBy
//5-count
//6-orderby
val valueDF: Dataset[Row] = reviceData
.as[String]
.filter(x => StringUtils.isNoneBlank(x))
.flatMap(_.split("\\s+"))
.groupBy($"value")
.count()
.orderBy($"count".desc)
//7-将结果写入
//.printSchema()
//root
// |-- value: string (nullable = true)
// |-- count: long (nullable = false)
val query: StreamingQuery = valueDF.writeStream
.format("console") //写入控制台
//Complete完全显示模式
//Append追加模式,显示更新的数据
//Update更新的方式显示数据
//- append:默认的追加模式,将新的数据输出!只支持简单查询,如果涉及的聚合就不支持了
//- complete:完整模式,将完整的数据输出,支持聚合和排序
//- update:更新模式,将有变化的数据输出,支持聚合但不支持排序,如果没有聚合就和append一样
.outputMode(OutputMode.Complete()) //Complete完全,无论是否更新全部显示,能够用于有聚合有排序的场景
.option("numRows", 10)
.option("truncate", false)
//这里ProcessingTime和ContinueTime两个时间一个时间是数据处理的时间-连续时间
.trigger(Trigger.ProcessingTime(0)) //设置0 尽可能快的处理
//Starts the execution of the streaming query
.start()
query.awaitTermination() //等待任意的异常发生程序结束
query.stop()
}
}
2. 文件数据源(了解)
- 将目录中写入的文件作为数据流读取,支持的文件格式为:text、csv、json、orc、parquet
import org.apache.spark.SparkConf
import org.apache.spark.sql.streaming.{
OutputMode, StreamingQuery, Trigger}
import org.apache.spark.sql.{
DataFrame, Dataset, Row, SparkSession}
import org.apache.spark.sql.types.{
DataTypes, StructType}
/**
* @author liu a fu
* @date 2021/1/25 0025
* @version 1.0
* @DESC Structured Streaming实时读取本地数据源文件 文件数据源
*/
object _01StrecturedFileLocal {
def main(args: Array[String]): Unit = {
//1-环境的初始化
val conf: SparkConf = new SparkConf()
.setAppName(this.getClass.getSimpleName.stripSuffix("$"))
.setMaster("local[*]")
.set("spark.sql.streaming.checkpointLocation", "path")
val spark: SparkSession = SparkSession
.builder()
.config(conf)
//注意如果默认情况下SparkSQL发生shuffle的分区个数为200个,这里设置分区个数小一些
.config("spark.sql.shuffle.partitions", 2)
.getOrCreate()
spark.sparkContext.setLogLevel("WARN")
import spark.implicits._
//2-读取数据源文件
val schema: StructType = new StructType()
.add("name", DataTypes.StringType, true)
.add("age", DataTypes.DoubleType, true)
.add("hobby", DataTypes.StringType, true)
val reviceDF: DataFrame = spark.readStream
.format("csv")
.option("sep", ";") //按照什么切分
.option("header", false)
.schema(schema)
.load("data/input/structured")
//reviceDF.printSchema()
//root
// |-- name: string (nullable = true)
// |-- age: double (nullable = true)
// |-- hobby: string (nullable = true)
//3-具体业务
//统计统计年龄小于25岁的爱好 并排序
val resultDS: Dataset[Row] = reviceDF
.filter($"age" < 25)
.groupBy($"hobby")
.count()
.orderBy($"count".desc)
//3-FlatMap
//4-gruopBy
//5-count
//6-orderby
//4-将结果写入
val query: StreamingQuery = resultDS
.writeStream
.format("console") //什么格式 控制台输出
.outputMode(OutputMode.Complete()) //输出模式
.trigger(Trigger.ProcessingTime(0)) //触发器,两个时间
.option("numRows", 10) //几行
.option("truncate", false) //是否截断输出
.start() //开启执行
query.awaitTermination() //直到有程序停止
query.stop() //停止
}
}