目錄
RDD操作
文件類型
可能是本地或者hdfs,類型可能是jsom,text等
spark提供了讀取和保存saveas兩種類型api
sc.textFile("hdfs://hadoop102:9000/fruit.txt")
hdfsFile.saveAsTextFile("/fruitOut")
Sequence文件
SequenceFile文件是Hadoop用來存儲二進制形式的key-value對而設計的一種平面文件(Flat File)
SequenceFile文件只針對PairRDD,也就是k-v=結構
val seq = sc.sequenceFile[Int,Int]("file:///opt/module/spark/seqFile")
rdd.saveAsSequenceFile("file:///opt/module/spark/seqFile")
對象文件
對象保存要可以序列化
rdd.saveAsObjectFile("file:///opt/module/spark/objectFile")
讀取時指定類型,裏面的元素都是People
val objFile = sc.objectFile[People]("file:///opt/module/spark/objectFile")
MySQL數據庫
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.27</version>
</dependency>
讀取
import java.sql.DriverManager
import org.apache.spark.rdd.JdbcRDD
import org.apache.spark.{SparkConf, SparkContext}
object MysqlRDD {
def main(args: Array[String]): Unit = {
//1.創建spark配置信息
val sparkConf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("JdbcRDD")
//2.創建SparkContext
val sc = new SparkContext(sparkConf)
//3.定義連接mysql的參數
val driver = "com.mysql.jdbc.Driver"
val url = "jdbc:mysql://hadoop102:3306/rdd"
val userName = "root"
val passWd = "000000"
//創建JdbcRDD
val rdd = new JdbcRDD(sc, () => {
Class.forName(driver)
DriverManager.getConnection(url, userName, passWd)
},
"select * from `rddtable` where `id`>=?;",
1,
10,
1,
r => (r.getInt(1), r.getString(2))
)
//打印最後結果
println(rdd.count())
rdd.foreach(println)
sc.stop()
}
}
寫入
def main(args: Array[String]) {
val sparkConf = new SparkConf().setMaster("local[2]").setAppName("HBaseApp")
val sc = new SparkContext(sparkConf)
val data = sc.parallelize(List("Female", "Male","Female"))
data.foreachPartition(insertData)
}
def insertData(iterator: Iterator[String]): Unit = {
Class.forName ("com.mysql.jdbc.Driver").newInstance()
val conn = java.sql.DriverManager.getConnection("jdbc:mysql://hadoop102:3306/rdd", "root", "000000")
iterator.foreach(data => {
val ps = conn.prepareStatement("insert into rddtable(name) values (?)")
ps.setString(1, data)
ps.executeUpdate()
})
}
habse數據庫
由於 org.apache.hadoop.hbase.mapreduce.TableInputFormat 類的實現,Spark 可以通過Hadoop輸入格式訪問HBase。這個輸入格式會返回鍵值對數據,其中鍵的類型爲org. apache.hadoop.hbase.io.ImmutableBytesWritable,而值的類型爲org.apache.hadoop.hbase.client.
Result。
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.3.1</version>
</dependency>
讀取
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.HBaseConfiguration
import org.apache.hadoop.hbase.client.Result
import org.apache.hadoop.hbase.io.ImmutableBytesWritable
import org.apache.hadoop.hbase.mapreduce.TableInputFormat
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.hadoop.hbase.util.Bytes
object HBaseSpark {
def main(args: Array[String]): Unit = {
//創建spark配置信息
val sparkConf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("JdbcRDD")
//創建SparkContext
val sc = new SparkContext(sparkConf)
//構建HBase配置信息
val conf: Configuration = HBaseConfiguration.create()
conf.set("hbase.zookeeper.quorum", "hadoop102,hadoop103,hadoop104")
conf.set(TableInputFormat.INPUT_TABLE, "rddtable")
//從HBase讀取數據形成RDD
val hbaseRDD: RDD[(ImmutableBytesWritable, Result)] = sc.newAPIHadoopRDD(
conf,
classOf[TableInputFormat],
classOf[ImmutableBytesWritable],
classOf[Result])
val count: Long = hbaseRDD.count()
println(count)
//對hbaseRDD進行處理
hbaseRDD.foreach {
case (_, result) =>
val key: String = Bytes.toString(result.getRow)
val name: String = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name")))
val color: String = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("color")))
println("RowKey:" + key + ",Name:" + name + ",Color:" + color)
}
//關閉連接
sc.stop()
}
}
寫入
def main(args: Array[String]) {
//獲取Spark配置信息並創建與spark的連接
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("HBaseApp")
val sc = new SparkContext(sparkConf)
//創建HBaseConf
val conf = HBaseConfiguration.create()
val jobConf = new JobConf(conf)
jobConf.setOutputFormat(classOf[TableOutputFormat])
jobConf.set(TableOutputFormat.OUTPUT_TABLE, "fruit_spark")
//構建Hbase表描述器
val fruitTable = TableName.valueOf("fruit_spark")
val tableDescr = new HTableDescriptor(fruitTable)
tableDescr.addFamily(new HColumnDescriptor("info".getBytes))
//創建Hbase表
val admin = new HBaseAdmin(conf)
if (admin.tableExists(fruitTable)) {
admin.disableTable(fruitTable)
admin.deleteTable(fruitTable)
}
admin.createTable(tableDescr)
//定義往Hbase插入數據的方法
def convert(triple: (Int, String, Int)) = {
val put = new Put(Bytes.toBytes(triple._1))
put.addImmutable(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes(triple._2))
put.addImmutable(Bytes.toBytes("info"), Bytes.toBytes("price"), Bytes.toBytes(triple._3))
(new ImmutableBytesWritable, put)
}
//創建一個RDD
val initialRDD = sc.parallelize(List((1,"apple",11), (2,"banana",12), (3,"pear",13)))
//將RDD內容寫到HBase
val localData = initialRDD.map(convert)
localData.saveAsHadoopDataset(jobConf)
sparksql操作
- Spark SQL的默認數據源爲Parquet格式 數據源爲Parquet文件時,Spark SQL可以方便的執行所有的操作。修改配置項spark.sql.sources.default,可修改默認數據源格式當數據源格式
- 不是parquet格式文件時,需要手動指定數據源的格式。數據源格式需要指定全名(例如:org.apache.spark.sql.parquet),如果數據源格式爲內置格式,則只需要指定簡稱定json, parquet, jdbc, orc, libsvm, csv, text來指定數據的格式
- 可以通過SparkSession提供的read.load方法用於通用加載數據,使用write和save保存數據
- 可以直接運行SQL在文件上
寫數據的4個選項
Scala/Java | Any Language | Meaning |
---|---|---|
SaveMode.ErrorIfExists(default) | “error”(default) | 如果文件存在,則報錯 |
SaveMode.Append | “append” | 追加 |
SaveMode.Overwrite | “overwrite” | 覆寫 |
SaveMode.Ignore | “ignore” | 數據存在,則忽略 |
JSON文件
Spark SQL 能夠自動推測 JSON數據集的結構,並將它加載爲一個Dataset[Row]. 可以通過SparkSession.read.json()去加載一個 一個JSON 文件
import spark.implicits._
val path = "examples/src/main/resources/people.json"
val peopleDF = spark.read.json(path)
peopleDF.createOrReplaceTempView("people")
Parquet文件
Parquet是一種流行的列式存儲格式,可以高效地存儲具有嵌套字段的記錄。Parquet格式經常在Hadoop生態圈中被使用,它也支持Spark SQL的全部數據類型
importing spark.implicits._
import spark.implicits._
val peopleDF = spark.read.json("examples/src/main/resources/people.json")
peopleDF.write.parquet("hdfs://hadoop102:9000/people.parquet")
val parquetFileDF = spark.read.parquet("hdfs:// hadoop102:9000/people.parquet")
parquetFileDF.createOrReplaceTempView("parquetFile")
JDBC
Spark SQL可以通過JDBC從關係型數據庫中讀取數據的方式創建DataFrame,通過對DataFrame一系列的計算後,還可以將數據再寫回關係型數據庫中
讀數據
val connectionProperties = new Properties()
connectionProperties.put("user", "root")
connectionProperties.put("password", "000000")
val jdbcDF2 = spark.read
.jdbc("jdbc:mysql://hadoop102:3306/db_test", "rddtable", connectionProperties)
寫數據
jdbcDF.write.jdbc("jdbc:mysql://hadoop102:3306/rdd", "db", connectionProperties)
Hive數據庫
Apache Hive是Hadoop上的SQL引擎,Spark SQL編譯時可以包含Hive支持,也可以不包含。包含Hive支持的Spark SQL可以支持Hive表訪問、UDF(用戶自定義函數)以及 Hive 查詢語言(HiveQL/HQL)等。需要強調的一點是,如果要在Spark SQL中包含Hive的庫,並不需要事先安裝Hive。一般來說,最好還是在編譯Spark SQL時引入Hive支持,這樣就可以使用這些特性了。如果你下載的是二進制版本的 Spark,它應該已經在編譯時添加了 Hive 支持。
若要把Spark SQL連接到一個部署好的Hive上,你必須把hive-site.xml複製到 Spark的配置文件目錄中($SPARK_HOME/conf)。即使沒有部署好Hive,Spark SQL也可以運行。 需要注意的是,如果你沒有部署好Hive,Spark SQL會在當前的工作目錄中創建出自己的Hive 元數據倉庫,叫作 metastore_db。此外,如果你嘗試使用 HiveQL 中的 CREATE TABLE (並非 CREATE EXTERNAL TABLE)語句來創建表,這些表會被放在你默認的文件系統中的 /user/hive/warehouse 目錄中(如果你的 classpath 中有配好的 hdfs-site.xml,默認的文件系統就是 HDFS,否則就是本地文件系統)。
內嵌Hive應用
如果要使用內嵌的Hive,什麼都不用做,直接用就可以了。
可以通過添加參數初次指定數據倉庫地址:
--conf spark.sql.warehouse.dir=hdfs://hadoop102/spark-wearhouse
注意:如果你使用的是內部的Hive,在Spark2.0之後,spark.sql.warehouse.dir用於指定數據倉庫的地址,如果你需要是用HDFS作爲路徑,那麼需要將core-site.xml和hdfs-site.xml 加入到Spark conf目錄,否則只會創建master節點上的warehouse目錄,查詢時會出現文件找不到的問題,這是需要使用HDFS,則需要將metastore刪除,重啓集羣。
外部Hive應用
如果想連接外部已經部署好的Hive,需要通過以下幾個步驟。
- 將Hive中的hive-site.xml拷貝或者軟連接到Spark安裝目錄下的conf目錄下。
- 打開spark shell,注意帶上訪問Hive元數據庫的JDBC客戶端
$ bin/spark-shell --jars mysql-connector-java-5.1.27-bin.jar
運行Spark SQL CLI
Spark SQL CLI可以很方便的在本地運行Hive元數據服務以及從命令行執行查詢任務。在Spark目錄下執行如下命令啓動Spark SQL CLI:
./bin/spark-sql
代碼中使用Hive
(1)添加依賴:
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>1.2.1</version>
</dependency>
(2)創建SparkSession時需要添加hive支持(紅色部分)
val warehouseLocation: String = new File("spark-warehouse").getAbsolutePath
val spark = SparkSession
.builder()
.appName("Spark Hive Example")
.config("spark.sql.warehouse.dir", warehouseLocation)
.enableHiveSupport()
.getOrCreate()
注意:藍色部分爲使用內置Hive需要指定一個Hive倉庫地址。若使用的是外部Hive,則需要將hive-site.xml添加到ClassPath下。
sparkstreaming操作
文件數據源
- textFileStream會監控dataDirectory目錄並不斷處理移動進來的文件,記住目前不支持嵌套目錄
- 文件需要有相同的數據格式;
- 文件進入 dataDirectory的方式需要通過移動或者重命名來實現
- 一旦文件移動進目錄,則不能再修改,即便修改了也不會讀取新數據;
val ssc = new StreamingContext(sparkConf, Seconds(5))
val dirStream = ssc.textFileStream("hdfs://hadoop102:9000/fileStream")
啓動程序並向fileStream目錄上傳文件
[atguigu@hadoop102 data]$ hadoop fs -put ./a.tsv /fileStream
[atguigu@hadoop102 data]$ hadoop fs -put ./b.tsv /fileStream
自定義數據源
import java.io.{BufferedReader, InputStreamReader}
import java.net.Socket
import java.nio.charset.StandardCharsets
import org.apache.spark.storage.StorageLevel
import org.apache.spark.streaming.receiver.Receiver
class CustomerReceiver(host: String, port: Int) extends Receiver[String](StorageLevel.MEMORY_ONLY) {
//最初啓動的時候,調用該方法,作用爲:讀數據並將數據發送給Spark
override def onStart(): Unit = {
new Thread("Socket Receiver") {
override def run() {
receive()
}
}.start()
}
//讀數據並將數據發送給Spark
def receive(): Unit = {
//創建一個Socket
var socket: Socket = new Socket(host, port)
//定義一個變量,用來接收端口傳過來的數據
var input: String = null
//創建一個BufferedReader用於讀取端口傳來的數據
val reader = new BufferedReader(new InputStreamReader(socket.getInputStream, StandardCharsets.UTF_8))
//讀取數據
input = reader.readLine()
//當receiver沒有關閉並且輸入數據不爲空,則循環發送數據給Spark
while (!isStopped() && input != null) {
store(input)
input = reader.readLine()
}
//跳出循環則關閉資源
reader.close()
socket.close()
//重啓任務
restart("restart")
}
override def onStop(): Unit = {}
}
使用自定義的數據源採集數據
val ssc = new StreamingContext(sparkConf, Seconds(5))
val lineStream = ssc.receiverStream(new CustomerReceiver("hadoop102", 9999))