一、数据源
Spark SQL的默认数据源格式为parquet格式。数据源为Parquet文件时,SparkSQL 可以方便地进行读取,甚至可以直接在Parquet 文件上执行查询操作。修改配置项spark.sqlsources.default,可以修改默认数据源格式。
当数据源不是parquet格式文件时,需要手动指定数据源的格式。
数据源格式需指定全名(如org.apachesparksl.parquet)
如果数据源为内置格式,则只需指定简称(json, parquet,jdbc, ore, libsvm, csv, text )即可。
1. Parquet
Parquet存储的优势:
(I)可以跳过不符合条件的数据,只读取需要的数据,降低IO数据量。
(2)压缩编码可以降低磁盘存储空间。由于同一列的数据类型是一样的, 可以使用更高效的压缩编码
(例如Run Length Encoding和Delta Encoding)进一步节约存储空间。
(3)只读取需要的列,支持向量运算,能够获取更好的扫描性能。
Spark SQL 的默认数据源为 Parquet 格式。数据源为 Parquet 文件时,Spark SQL 可以方便的执行所有的操作。修改配置项 spark.sql.sources.default,可修改默认数据源格式。
1) Parquet格式写入
scala> import spark.implicits._
import spark.implicits._
// 从内存中创建一个DataFrame
scala> val df = Seq(("Ming", 20, 15552211521L), ("hong", 19, 13287994007L), ("zhi", 21, 15552211523L)).toDF("name", "age", "phone")
df: org.apache.spark.sql.DataFrame = [name: string, age: int ... 1 more field]
scala> df.show()
+----+---+-----------+
|name|age| phone|
+----+---+-----------+
|Ming| 20|15552211521|
|hong| 19|13287994007|
| zhi| 21|15552211523|
+----+---+-----------+
// 以Parquet的格式写入
scala> df.write.format("parquet").save("file:///root/parquet")
option支持参数
名称 | 默认值 | 描述 |
---|---|---|
compression | null | 保存到文件时使用的压缩编解码器,如(none,bzip2,gzip,lz4,snappy和deflate),不区分大小写。 |
2) Parquet格式读取
// 读取Parquet
scala> val parquetDF = spark.read.format("parquet").load("file:///root/parquet")
parquetDF: org.apache.spark.sql.DataFrame = [name: string, age: int ... 1 more field]
scala> parquetDF.printSchema()
root
|-- name: string (nullable = true)
|-- age: integer (nullable = true)
|-- phone: long (nullable = true)
option参数
名称 | 默认值 | 描述 |
---|---|---|
mergeSchema | false | 如果为true,则将文件作为单行读取,而不是按“\ n”拆分 |
// 读取数据
scala> val df = spark.read.load("file:///usr/local/spark-2.4.4-bin-hadoop2.7/examples/src/main/resources/users.parquet")
df: org.apache.spark.sql.DataFrame = [name: string, favorite_color: string ... 1 more field]
// 另存为文件namesAndFavColors.parquet
scala> df.select("name", "favorite_color").write.save("file:///root/namesAndFavColors.parquet")
# 查看结果
root@master:~# ls /root/name*
part-00000-3d4c5b0f-67d7-473e-bf85-3b20260db66b-c000.snappy.parquet _SUCCESS
2. JSON
Spark SQL可处理的数据源包括简洁高效,常用于网络传输的JSON格式数据集。
Spark SQL可以自动推断JSON数据集的结构信息(Schema),并将其作为DataSel[Row]即DataFrame对象返回。通过将Dataset [String]其中String对象是典型的JSON格式字符串)或表示JSON文件存储位置的路径字符中传入SparkSession.readjson ()方法中来完成此转换。
需要注意的是,作为JSON文件提供的文件不是典型的JSON文件。每行必须包含一 个单独的,独立的有效的JSON对象。
1)json格式写入
scala> import spark.implicits._
import spark.implicits._
scala> val df = Seq(("Ming", 20, 15552211521L), ("hong", 19, 13287994007L), ("zhi", 21, 15552211523L)).toDF("name", "age", "phone")
df: org.apache.spark.sql.DataFrame = [name: string, age: int ... 1 more field]
scala> df.show()
+----+---+-----------+
|name|age| phone|
+----+---+-----------+
|Ming| 20|15552211521|
|hong| 19|13287994007|
| zhi| 21|15552211523|
+----+---+-----------+
//以json格式写入文件
df.write.format("json").save("file:///root/json")
// 结果查看
root@master:~# ls json
part-00000-cc4acdd4-53dd-4b04-a203-f1166e426be5-c000.json _SUCCESS
root@master:~# cat json/part-00000-cc4acdd4-53dd-4b04-a203-f1166e426be5-c000.json
{"name":"Ming","age":20,"phone":15552211521}
{"name":"hong","age":19,"phone":13287994007}
{"name":"zhi","age":21,"phone":15552211523}
// 指定SaveMode
scala> df.write.format("json").mode("errorifexists").save("file:///data/json")
常见的SaveMode:
SaveMode | 描述 |
---|---|
errorifexists | 默认,如果文件存在报错 |
append | 将DataFrame保存到数据源时,如果数据/表已存在,则DataFrame的内容应附加到现有数据。 |
overwrite | 覆盖模式意味着在将DataFrame保存到数据源时,如果数据/表已经存在,则预期现有数据将被DataFrame的内容覆盖。 |
ignore | 忽略模式意味着在将DataFrame保存到数据源时,如果数据已存在,则预期保存操作不会保存DataFrame的内容并且不会更改现有数据。这与CREATE TABLE IF NOT EXISTSSQL中的类似。 |
在写json时,我们也可以通过option传入特定的参数,支持参数如下所示:
名称 | 默认值 | 描述 |
---|---|---|
compression | null | 保存到文件时使用的压缩编解码器,如(none,bzip2,gzip,lz4,*snappy和deflate),不区分大小写。 |
dateFormat | yyyy-MM-dd | 设置指示日期格式的字符串。 自定义日期格式遵循java.text.SimpleDateFormat中的格式。这适用于日期类型。 |
timestampFormat | yyyy-MM-dd’T’HH:mm:ss.SSSXXX | 设置表示时间戳格式的字符串。自定义日期格式遵循java.text.SimpleDateFormat中的格式。这适用于时间戳类型 |
encoding | 指定已保存的json 文件的编码(charset)。如果未设置,将使用UTF-8字符集。 | |
lineSep | \n | 指定行分隔符 |
2) json格式读取
// 读取json数据源,json为存放json文件的目录名
scala> val jsonDF = spark.read.format("json").load("file:///root/json")
jsonDF: org.apache.spark.sql.DataFrame = [age: bigint, name: string ... 1 more field]
scala> jsonDF.show()
+---+----+-----------+
|age|name| phone|
+---+----+-----------+
| 20|Ming|15552211521|
| 19|hong|13287994007|
| 21| zhi|15552211523|
+---+----+-----------+
读取json支持的参数:
名称 | 默认值 | 描述 |
---|---|---|
primitivesAsString | false | 将所有原始值推断为String类型 |
prefersDecimal | false | 将所有浮点值推断为十进制类型。如果值不适合十进制,那么它将它们推断为双精度数。 |
allowComments | false | 忽略JSON记录中的Java / C ++样式注释 |
allowUnquotedFieldNames | false | 允许不带引号的JSON字段名称 |
allowSingleQuotes | true 除了双引号外允许使用单引号 | |
allowNumericLeadingZeros | false | 允许数字之前有零,(e.g. 00012) |
allowBackslashEscapingAnyCharacter | false | 允许使用反斜杠引用机制接受所有字符的引用 |
allowUnquotedControlChars | false | 允许JSON字符串包含不带引号的控制字符(值小于32的ASCII字符,包括制表符和换行符)或不包含。 |
mode | PERMISSIVE | 允许在解析过程中处理损坏记录的模式。共有三种模式: PERMISSIVE:当它遇到损坏的记录时,将格式错误的字符串放入由columnNameOfCorruptRecord配置的字段中,并将其他字段设置为“null”。为了保持损坏的记录,用户可以在用户定义的模式中设置名为columnNameOfCorruptRecord的字符串类型字段。如果架构没有字段,它在解析过程中丢弃损坏的记录。在推断模式时,它会在输出模式中隐式添加columnNameOfCorruptRecord字段。 DROPMALFORMED:忽略整个损坏的记录 FAILFAST:当遇到损坏记录时抛出异常 |
columnNameOfCorruptRecord | spark.sql.columnNameOfCorruptRecord中指定的值 | 允许重命名具有由’PERMISSIVE模式创建的格式错误的字符串的新字段。这会覆盖spark.sql.columnNameOfCorruptRecord` |
dateFormat | yyyy-MM-dd | 设置指示日期格式的字符串。 自定义日期格式遵循java.text.SimpleDateFormat中的格式。这适用于日期类型。 |
timestampFormat | yyyy-MM-dd’T’HH:mm:ss.SSSXXX | 设置表示时间戳格式的字符串。自定义日期格式遵循java.text.SimpleDateFormat中的格式。这适用于时间戳类型。 |
multiLine | false | 解析一个记录,每个文件可能跨越多行 |
encoding | 允许强制为JSON文件设置标准基本或扩展编码之一。例如UTF-16BE,UTF-32LE。如果未指定encoding 并且multiLine设置为true,则会自动检测到它。 | |
lineSep | \r, \r\n and \n | 行分隔符 |
samplingRatio | 1.0 | 定义用于模式推断的输入JSON对象的分数 |
3. CSV文件
1) csv格式写入
scala> import spark.implicits._
import spark.implicits._
scala> val df = Seq(("Ming", 20, 15552211521L), ("hong", 19, 13287994007L), ("zhi", 21, 15552211523L)).toDF("name", "age", "phone")
df: org.apache.spark.sql.DataFrame = [name: string, age: int ... 1 more field]
scala> df.show()
+----+---+-----------+
|name|age| phone|
+----+---+-----------+
|Ming| 20|15552211521|
|hong| 19|13287994007|
| zhi| 21|15552211523|
+----+---+-----------+
// 以csv格式写入文件
scala> df.write.format("csv").mode("overwrite").save("file:///root/csv")
// 输出结果
root@master:~# ls csv*
part-00000-532cf409-32c8-4a3e-8875-0fced5339d50-c000.csv _SUCCESS
root@master:~# cat csv/part-00000-532cf409-32c8-4a3e-8875-0fced5339d50-c000.csv
Ming,20,15552211521
hong,19,13287994007
zhi,21,15552211523
option参数列表:
名称 | 默认值 | 描述 |
---|---|---|
sep | , | 列分隔符 |
quote | " | 设置用于转义引用值的单个字符,其中分隔符可以是值的一部分。如果设置了空字符串,则使用u0000 (空字符) |
escape | \ | 设置一个用于在已引用的值内转义引号的单个字符。 |
charToEscapeQuoteEscaping | escape or \0 | 设置一个单独的字符,用于转义引号字符的转义。当转义和引号字符不同时,默认值为转义字符,否则为“\ 0” |
escapeQuotes | true | 一个标志,指示包含引号的值是否应始终用引号括起来。默认是转义包含引号字符的所有值。 |
quoteAll | false | 一个标志,指示是否所有值都应始终用引号括起来。默认是仅转义包含引号字符的值。 |
header | false | 将第一行写为列的名称 |
nullValue | 空字符串 | 设置空值的字符串表示形式。 |
compression | null | 保存到文件时使用的压缩编解码器,如(none,bzip2,gzip,lz4,snappy和deflate),不区分大小写。 |
dateFormat | yyyy-MM-dd | 设置指示日期格式的字符串。 自定义日期格式遵循java.text.SimpleDateFormat中的格式。这适用于日期类型。 |
timestampFormat | yyyy-MM-dd’T’HH:mm:ss.SSSXXX | 设置表示时间戳格式的字符串。自定义日期格式遵循java.text.SimpleDateFormat中的格式。这适用于时间戳类型。 |
ignoreLeadingWhiteSpace | true | 一个标志,指示是否应该跳过正在写入的值的头部空格。 |
ignoreTrailingWhiteSpace | true | 一个标志,指示是否应该跳过正在写入的值的尾部空格。 |
2) csv格式读取
scala> val csvDF = spark.read.format("csv").options(Map("sep"->",","inferSchema"->"true","header"->"true")).load("file:///root/csv")
csvDF: org.apache.spark.sql.DataFrame = [Ming: string, 20: int ... 1 more field]
scala> csvDF.show()
+----+---+-----------+
|Ming| 20|15552211521|
+----+---+-----------+
|hong| 19|13287994007|
| zhi| 21|15552211523|
+----+---+-----------+
option参数列表:
名称 | 默认值 | 描述 |
---|---|---|
sep | , | 列分隔符 |
encoding | UTF-8 | 编码格式 |
quote | " | 设置用于转义引用值的单个字符,其中分隔符可以是值的一部分。如果设置了空字符串,则使用u0000 (空字符) |
escape | \ | 设置一个用于在已引用的值内转义引号的单个字符。 |
comment | empty string | 设置一个用于跳过以此字符开头的行的单个字符。默认情况下,它被禁用。 |
header | false | 将第一行写为列的名称 |
enforceSchema | true | 如果将其设置为“true”,则将强制将指定或推断的模式应用于数据源文件,并忽略CSV文件中的标头。 如果该选项设置为“false”,则在header选项设置为“true”的情况下,将针对CSV文件中的所有标头验证模式。模式中的字段名称和CSV标题中的列名称通过考虑spark.sql.caseSensitive的位置进行检查。虽然默认值为true,但建议禁用 enforceSchema`选项以避免不正确的结果。 |
inferSchema | true | 从数据中自动推断输入模式。 需要对数据进行一次额外的传递。 |
samplingRatio | 1.0 | 定义用于模式推断的行的分数。 |
dateFormat | yyyy-MM-dd | 设置指示日期格式的字符串。 自定义日期格式遵循java.text.SimpleDateFormat中的格式。这适用于日期类型。 |
timestampFormat | yyyy-MM-dd’T’HH:mm:ss.SSSXXX | 设置表示时间戳格式的字符串。自定义日期格式遵循java.text.SimpleDateFormat中的格式。这适用于时间戳类型。 |
ignoreLeadingWhiteSpace | false | 忽略开头是空格的值 |
ignoreTrailingWhiteSpace | false | 忽略结尾是空格的值 |
nullValue | empty string | 设置空值的字符串表示形式。从*2.0.1开始,这适用于所有支持的类型,包括字符串类型。 |
nanValue | NaN | 设置非数字值的字符串表示形式。 |
positiveInf | Inf | 设置正无穷大值的字符串表示形式 |
negativeInf | -Inf | 设置负无穷大值的字符串表示形式 |
maxColumns | 20480 | 定义记录可以有多少列的硬限制。 |
maxCharsPerColumn | -1 | 定义允许读取的任何给定值的最大字符数。默认情况下,它为-1表示无限长度 |
mode | 允许在解析过程中处理损坏记录的模式。共有三种模式: PERMISSIVE:当它遇到损坏的记录时,将格式错误的字符串放入由columnNameOfCorruptRecord配置的字段中,并将其他字段设置为“null”。为了保持损坏的记录,用户可以在用户定义的模式中设置名为columnNameOfCorruptRecord的字符串类型字段。如果架构没有字段,它在解析过程中丢弃损坏的记录。在推断模式时,它会在输出模式中隐式添加columnNameOfCorruptRecord字段。 DROPMALFORMED:忽略整个损坏的记录 FAILFAST:当遇到损坏记录时抛出异常 |
|
columnNameOfCorruptRecord | spark.sql.columnNameOfCorruptRecord中指定的值 | 允许重命名具有由’PERMISSIVE模式创建的格式错误的字符串的新字段。这会覆盖spark.sql.columnNameOfCorruptRecord` |
multiLine | false | 解析一条记录,可能跨越多行。 |
4. Text文件
1) Text格式写入
scala> import spark.implicits._
import spark.implicits._
scala> val df = Seq(("Ming", 20, 15552211521L), ("hong", 19, 13287994007L), ("zhi", 21, 15552211523L)).toDF("name", "age", "phone")
df: org.apache.spark.sql.DataFrame = [name: string, age: int ... 1 more field]
scala> df.show()
+----+---+-----------+
|name|age| phone|
+----+---+-----------+
|Ming| 20|15552211521|
|hong| 19|13287994007|
| zhi| 21|15552211523|
+----+---+-----------+
// 以text格式写入文件
scala> val textDF = df.map(_.toSeq.foldLeft("")(_+","+_).substring(1))
textDF: org.apache.spark.sql.Dataset[String] = [value: string]
scala> textDF.write.format("text").mode("overwrite").save("file:///root/text")
// 查看结果
root@master:~# cat /root/text/part-00000-7ab8f2a4-5e14-46bf-83a0-ce13af18427e-c000.txt
Ming,20,15552211521
hong,19,13287994007
zhi,21,15552211523
写入text格式时,要求我们的DataFrame只有一列,否则会报错误。
option参数:
名称 | 默认值 | 描述 |
---|---|---|
compression | null | 保存到文件时使用的压缩编解码器,如(none,bzip2,gzip,lz4,snappy和deflate),不区分大小写。 |
lineSep | \r, \r\n and \n | 行分隔符 |
2) Text格式读取
// 读取text文件
scala> val text = spark.read.format("text").load("file:///root/text")
text: org.apache.spark.sql.DataFrame = [value: string]
scala> text.show()
+-------------------+
| value|
+-------------------+
|Ming,20,15552211521|
|hong,19,13287994007|
| zhi,21,15552211523|
+-------------------+
// 转为DataFrame
// lazy 懒加载就是我们在使用的时候 才会去加载,声明的时候不加载
scala> lazy val first = textDF.first()
first: String =
scala> val numAttrs = first.split(",").length
numAttrs: Int = 3
scala> import org.apache.spark.sql.functions._
import org.apache.spark.sql.functions._
scala> var newDF = textDF.withColumn("splitCols", split($"value", ","))
newDF: org.apache.spark.sql.DataFrame = [value: string, splitCols: array]
// 0.until 返回一个不包含区间上线的数组
scala> 0.until(numAttrs).foreach(x => {
| newDF = newDF.withColumn("col" + "_" + x, $"splitCols".getItem(x))
| })
scala> newDF.show()
+-------------------+--------------------+-----+-----+-----------+
| value| splitCols|col_0|col_1| col_2|
+-------------------+--------------------+-----+-----+-----------+
|Ming,20,15552211521|[Ming, 20, 155522...| Ming| 20|15552211521|
|hong,19,13287994007|[hong, 19, 132879...| hong| 19|13287994007|
| zhi,21,15552211523|[zhi, 21, 1555221...| zhi| 21|15552211523|
+-------------------+--------------------+-----+-----+-----------+
Spark SQL 读取text文件,只有一列,这是我们可以通过进一步的处理,转化为以“,”分割的多列DataFrame
option参数
名称 | 默认值 | 描述 |
---|---|---|
wholetext | false | 如果为true,则将文件作为单行读取,而不是按“\ n”拆分 |
lineSep | \r, \r\n and \n | 行分隔符 |
附:
scala> val b= 0.until(10);
b: scala.collection.immutable.Range = Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
5. JDBC数据源
1) JDBC数据源写入
scala> import spark.implicits._
import spark.implicits._
// 从内存中创建一个DataFram
scala> val df = Seq(("Ming", 20, 15552211521L), ("hong", 19, 13287994007L), ("zhi", 21, 15552211523L)).toDF("name", "age", "phone")
df: org.apache.spark.sql.DataFrame = [name: string, age: int ... 1 more field]
scala> df.show()
+----+---+-----------+
|name|age| phone|
+----+---+-----------+
|Ming| 20|15552211521|
|hong| 19|13287994007|
| zhi| 21|15552211523|
+----+---+-----------+
// 导入依赖包
scala> import java.util.Properties
import java.util.Properties
scala> val connectionProperties = new Properties()
connectionProperties: java.util.Properties = {}
// 设置数据库连接属性
scala> connectionProperties.put("user", "root")
res1: Object = null
scala> connectionProperties.put("password", "1234")
res2: Object = null
scala> connectionProperties.put("driver", "com.mysql.jdbc.Driver")
res3: Object = null
// 写入数据库数据
scala> df.write.jdbc("jdbc:mysql://localhost:3306/sparkdata?useSSL=false&characterEncoding=utf-8","spark_people",connectionProperties)
支持参数:
名称 | 默认值 | 描述 |
---|---|---|
url | jdbc:subprotocol:subname形式的JDBC数据库url | |
table | 外部数据库中表的名称。 | |
connectionProperties | JDBC数据库连接参数,任意字符串标记/值的列表。通常至少应包括“用户”和“密码”属性。 “batchsize”可用于控制每个插入的行数。 “isolationLevel”可以是“NONE”,“READ_COMMITTED”,“READ_UNCOMMITTED”,“REPEATABLE_READ”,或“SERIALIZABLE”之一,对应于JDBC的Connection对象定义的标准事务*隔离级别,默认值为“READ_UNCOMMITTED” 。 |
3) JDBC数据源读取
// 导入依赖包
scala> import java.util.Properties
import java.util.Properties
scala> val connectionProperties = new Properties()
connectionProperties: java.util.Properties = {}
// 设置数据库连接属性
scala> connectionProperties.put("user", "root")
res1: Object = null
scala> connectionProperties.put("password", "1234")
res2: Object = null
scala> connectionProperties.put("driver", "com.mysql.jdbc.Driver")
res3: Object = null
scala> val mysqlDF = spark.read.jdbc("jdbc:mysql://localhost:3306/sparkdata?useSSL=false&characterEncoding=utf-8","spark_people",connectionProperties)
mysqlDF: org.apache.spark.sql.DataFrame = [name: string, age: int ... 1 more field]
scala> mysqlDF.show()
+----+---+-----------+
|name|age| phone|
+----+---+-----------+
|Ming| 20|15552211521|
|hong| 19|13287994007|
| zhi| 21|15552211523|
+----+---+-----------+
参数列表:
名称 | 默认值 | 描述 |
---|---|---|
url | jdbc:subprotocol:subname形式的JDBC数据库url | |
table | 表名 | |
columnName | 将用于分区的整数类型列的名称。 | |
lowerBound | columnName的最小值用于决定分区步幅。 | |
upperBound | columnName的最大值用于决定分区步幅。 | |
numPartitions | 分区数量。这与lowerBound(包含),upperBound(不包括)一起形成分区,用于生成WHERE 子句表达式,用于均匀地分割列columnName。当*输入小于1时,数字设置为1。 | |
connectionProperties | JDBC数据库连接参数,任意字符串标记/值的列表。通常至少应包括“用户”和“密码”属性。 “batchsize”可用于控制每个插入的行数。 “isolationLevel”可以是“NONE”,“READ_COMMITTED”,“READ_UNCOMMITTED”,“REPEATABLE_READ”,或“SERIALIZABLE”之一,对应于JDBC的Connection对象定义的标准事务*隔离级别,默认值为“READ_UNCOMMITTED” 。 |
6.Hive数据源
Spark SQL支持对Hive中存储的数据进行读写。操作Hive中的数据时,必须创建HiveContext,而不是SQLContext。
HiveContext继承自SQLContext,但是增加了在Hive元数据库中查找表,以及用HiveQL语法编写SQL的功能。除了sql()方法,HiveContext还提供了hql()方法,从而用Hive语法来编译sql。
使用HiveContext,可以执行Hive的大部分功能,包括创建表、往表里导入数据以及用SQL语句查询表中的数据。查询出来的数据是一个Row数组。
1) 配置
- 普通配置
将hive-site.xml
拷贝到spark/conf目录下,将mysql connector
拷贝到spark/jars目录下:
root@master:~# cp /usr/local/apache-hive-2.3.6-bin/conf/hive-site.xml /usr/local/spark-2.4.4-bin-hadoop2.7/conf/
root@master:~# cp /usr/local/apache-hive-2.3.6-bin/lib/mysql-connector-java-5.1.48.jar /usr/local/spark-2.4.4-bin-hadoop2.7/jars/
SparkSQL通过连接hive提供的metastore服务来获取hive表的元数据。
直接启动hive的metastore服务即可完成SparkSQL和Hive的集成。
hive.cli.print.header
true
hive.cli.print.current.db
true
- 高可用配置
如果hdfs配置了高可用,则还要把hadoop集群中的hdfs-site.xml和core-site.xml文件拷贝到spark/conf文件夹下面:
[root@master ~]# cp /usr/local/hadoop-2.10.0/etc/hadoop/core-site.xml /usr/local/spark-2.4.5-bin-hadoop2.7/conf/
[root@master ~]# cp /usr/local/hadoop-2.10.0/etc/hadoop/hdfs-site.xml /usr/local/spark-2.4.5-bin-hadoop2.7/conf/
* thrift方式集成
hvie-site.xml:
# 关闭数据库验证
hive.metastore.schema.verification
false
# thrift方式集成
hive.metastore.uris
thrift://master:9083
None
2) Spark-Shell--Hive操作
- HiveContext :
scala> import org.apache.spark.sql.hive.HiveContext
import org.apache.spark.sql.hive.HiveContext
scala> val hiveContext = new HiveContext(sc);
warning: there was one deprecation warning; re-run with -deprecation for details
hiveContext: org.apache.spark.sql.hive.HiveContext = org.apache.spark.sql.hive.HiveContext@736af6f3
// 创建表
scala> hiveContext.sql("CREATE TABLE IF NOT EXISTS students (name STRING, age INT)")
- 登录Hive查看:
// 执行结果(创建成功)
0: jdbc:hive2://192.168.71.130:10000> select * from students;
OK
+----------------+---------------+
| students.name | students.age |
+----------------+---------------+
+----------------+---------------+
- Spark-Shell显示Hive内容:
// 显示hive表内容
scala> hiveContext.table("emp").show()
+-----+------+---------+----+----------+------+------+------+
|empno| ename| job| mgr| hiredate| sal| comm|deptno|
+-----+------+---------+----+----------+------+------+------+
| 7935| 程超| bigdata|7902|2019-12-19|5000.0| 0.0| 40|
| 7937|牛文娟| bigdata|7902|2019-12-19|4000.0| 0.0| 50|
| 7499|ALLEN |SALESMAN |7698|1981-02-20|1600.0| 300.0| 30|
| 7521|WARD |SALESMAN |7698|1981-02-22|1250.0| 500.0| 30|
| 7566|JONES |MANAGER |7839|1981-04-02|2975.0| 0.0| 20|
| 7654|MARTIN|SALESMAN |7698|1981-09-28|1250.0|1400.0| 30|
| 7698|BLAKE |MANAGER |7839|1981-05-01|2850.0| 0.0| 30|
| 7782|CLARK |MANAGER |7839|1981-06-09|2450.0| 0.0| 10|
| 7788|SCOTT |ANALYST |7566|1987-07-13|3000.0| 0.0| 20|
| 7839|KING |PRESIDENT|null|1981-11-07|5000.0| 0.0| 10|
| 7844|TURNER|SALESMAN |7698|1981-09-08|1500.0| 0.0| 30|
| 7876|ADAMS |CLERK |7788|1987-07-13|1100.0| 0.0| 20|
| 7900|JAMES |CLERK |7698|1981-12-03| 950.0| 0.0| 30|
| 7902|FORD |ANALYST |7566|1981-12-03|3000.0| 0.0| 20|
| 7934|MILLER|CLERK |7782|1982-01-23|1300.0| 0.0| 10|
+-----+------+---------+----+----------+------+------+------+
// 数据查询
scala> hiveContext.sql("select * from default.emp").show(5,false)
+-----+------+---------+----+----------+------+-----+------+
|empno|ename |job |mgr |hiredate |sal |comm |deptno|
+-----+------+---------+----+----------+------+-----+------+
|7935 |程超 |bigdata |7902|2019-12-19|5000.0|0.0 |40 |
|7937 |牛文娟|bigdata |7902|2019-12-19|4000.0|0.0 |50 |
|7499 |ALLEN |SALESMAN |7698|1981-02-20|1600.0|300.0|30 |
|7521 |WARD |SALESMAN |7698|1981-02-22|1250.0|500.0|30 |
|7566 |JONES |MANAGER |7839|1981-04-02|2975.0|0.0 |20 |
+-----+------+---------+----+----------+------+-----+------+
only showing top 5 rows
- SparkSession:
scala> spark.sql("show tables").show(false)
+--------+---------+-----------+
|database|tableName|isTemporary|
+--------+---------+-----------+
|default |students |false |
+--------+---------+-----------+
# 创建users表:
scala> spark.sql(("create table users(id int, name string) row format delimited fields terminated by ','"))
- 数据:
1,zhangsan
2,lishi
3,wangwu
- 加载数据
scala> spark.sql("LOAD DATA LOCAL INPATH '/root/users' INTO TABLE users")
scala> spark.sql("select * from users").show
+---+--------+
| id| name|
+---+--------+
| 1|zhangsan|
| 2| lishi|
| 3| wangwu|
+---+--------+
二、常见问题
-
spark java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
解决:
拷贝jdbc jar文件到spark的jars目录下。
root@master:~# cp /usr/local/apache-hive-2.3.6-bin/lib/mysql-connector-java-5.1.48.jar /usr/local/spark-2.4.4-bin-hadoop2.7/jars/
2. Hive Schema version 1.2.0 does not match metastore's schema version 2.3.0 Metastore is not upgraded or corrupt
在hvie-site.xml中将hive.metastore.schema.verification参数设置为false:
hive.metastore.schema.verification
false
附:
csv,tsv,txt 文件类型区别
sv 和 csv 都是文本文件。
tsv, 是Tab-separated values的缩写,用制表符(Tab,’\t’)作为字段值的分隔符。
csv,Comma-separated values,用半角逗号(’,’)作为字段值的分隔符。