SparkSQL(五)——数据源
通用加载保存方法
Spark SQL的默认数据源为Parquet格式。数据源为Parquet文件时,Spark SQL可以方便的执行所有的操作。修改配置项spark.sql.sources.default,可修改默认数据源格式。
此时,可以使用spark.read.load和spar.write.save方法,分别从parquet格式的文件中读取出/或者写入数据。
scala> val df = spark.read.load("file:///home/chxy/spark/users.parquet")
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
df: org.apache.spark.sql.DataFrame = [name: string, favorite_color: string ... 1 more field]
df.write.save("file:///home/chxy/spark/out")
19/10/11 20:04:05 WARN hadoop.ParquetRecordReader: Can not initialize counter due to context is not a instance of TaskInputOutputContext, but is org.apache.hadoop.mapreduce.task.TaskAttemptContextImpl
查看保存的文件及其格式,发现生成了parquet格式的文件。
当数据源格式不是parquet格式文件时,需要手动指定数据源的格式。数据源格式需要指定全名(例如:org.apache.spark.sql.parquet),如果数据源格式为内置格式,则只需要指定简称如json, parquet, jdbc, orc, libsvm, csv, text来指定数据的格式。这里有两种方式:
1)是什么格式就用什么方式,比如读取json格式,就使用spark.read.json,写入json格斯,就使用spark.write.json
scala> df.write.json("file:///home/chxy/spark/out2")
19/10/11 20:13:35 WARN hadoop.ParquetRecordReader: Can not initialize counter due to context is not a instance of TaskInputOutputContext, but is org.apache.hadoop.mapreduce.task.TaskAttemptContextImpl
2)在load方法前,调用format格式化成指定的文件格式
scala> val df2 = spark.read.format("json").load("file:///home/chxy/spark/user.json")
df2: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
scala> df2.write.format("json").save("file:///home/chxy/spark/out3")
文件保存选项
可以采用SaveMode执行存储操作,SaveMode定义了对数据的处理模式。需要注意的是,这些保存模式不使用任何锁定,不是原子操作。此外,当使用Overwrite方式执行时,在输出新数据之前原数据就已经被删除。SaveMode的api如下:
final class SaveMode extends Enum[SaveMode]:它是一个枚举类,各字段含义如下:
“error”(default):已存在则报错
“append”:追加
“overwrite”:覆写
“ignore”:存在则忽略
演示如下:
//没有指定模式,采用默认的error,保存文件到同一个目录会报错
scala> df2.write.format("json").save("file:///home/chxy/spark/out3") org.apache.spark.sql.AnalysisException: path file:/home/chxy/spark/out3 already exists.; //指定保存模式为append scala> df2.write.format("json").mode("append").save("file:///home/chxy/spark/out3")
JDBC
Spark SQL可以通过JDBC从关系型数据库中读取数据的方式创建DataFrame,通过对DataFrame一系列的计算后,还可以将数据再写回关系型数据库中。
注意:在sparkshell中操作,需要将相关的数据库驱动放到spark的类路径下(spark/jars)。
从数据库读数据:
def main(args: Array[String]): Unit = {
//创建SparkConf()并设置App名称
val conf = new SparkConf().setAppName("sparlsql").setMaster("local[*]")
val spark = SparkSession.builder().config(conf).getOrCreate()
//从数据库读取数据并形成dataframe
val df: DataFrame = spark.read
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/sensor?serverTimezone=UTC")
.option("dbtable", "rddtable")
.option("user", "root")
.option("password", "613692")
.load()
df.show()
//将dataframe数据存入mysql数据库,并且指定写入模式
df.write
.format("jdbc")
.mode("overwrite")
.option("url", "jdbc:mysql://localhost:3306/sensor?serverTimezone=UTC")
.option("dbtable", "rddtable")
.option("user", "root")
.option("password", "613692")
.save()
spark.stop()
}
可以正确地获取到数据库中的数据。
但是将数据存入数据库的时候,出现问题:
1)当把写入模式指定为overwrite的时候,发现数据库被清空,因此不建议使用;
2) 当按照文档的写法,不指定任何保存模式的时候,会抛出异常:
Exception in thread "main" org.apache.spark.sql.AnalysisException: Table or view 'rddtable' already exists. SaveMode: ErrorIfExist。说明由于rddtable的存在,无法再往此表中插入数据,因此当把数据插入到一个新表,可以使用,插入到一个已存在的表,也不建议使用。
3)当把保存模式指定为append的时候,可以正常地往已存在的表中插入数据。
Hive数据库
内嵌hive应用
spark中已经包含了一个hive,可以直接通过spark sql语句来使用这个hive,即spark.sql("hql语句")。
scala> spark.sql("create table xxx(id int,name string) ").show
19/10/11 21:58:45 WARN metastore.HiveMetaStore: Location: file:/opt/module/spark/spark-warehouse/xxx specified for non-external table:xxx
可以看到,它内建的hive仓库位于 file:/opt/module/spark/spark-warehouse/xxx。可以通过添加参数初次指定数据仓库地址confspark.sql.warehouse.dir=hdfs://hadoop102/spark-wearhouse。
外部hive应用
如果想连接外部已经部署好的Hive,需要通过以下几个步骤
1)将数据库驱动拷贝到spark的类路径下(spark/jars)
2)将Hive中的hive-site.xml拷贝或者软连接到Spark安装目录下的conf目录下
3) 打开spark shell,注意带上访问Hive元数据库的JDBC客户端
$ bin/spark-shell --jars mysql-connector-java-5.1.27-bin.jar
在代码中使用hive
1)添加依赖
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>2.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hive/hive-exec -->
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>1.2.1</version>
</dependency>
2)将hive-siste.xml添加到项目的resource目录下
3)编写连接hive的代码
def main(args: Array[String]): Unit = {
//创建sparksession,并使其支持hive连接
val spark = SparkSession
.builder()
.appName("Spark Hive Example")
.enableHiveSupport()
.getOrCreate()
spark.sql("show tables")
spark.stop()
}
4)打成jar包,见博客https://www.cnblogs.com/chxyshaodiao/p/12402437.html
5)发布到Hadoop集群运行
bin/spark-submit \ --class sparksql.Demo5 \ --master yarn \ myjars/spark3.jar
但是在yarn模式下并未见到结果输出!

浙公网安备 33010602011771号