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模式下并未见到结果输出!

posted @ 2020-03-03 15:28  盛夏群岛  阅读(1331)  评论(0)    收藏  举报