此贴,主要记录本人在工作中遇到的某些报错问题,并提出自己的解决办法。
1.
spark = SparkSession.builder() TypeError: 'Builder' object is not callable
解决办法:.builder() 改为 .builder [SPARK-18426] Python Documentation Fix for Structured Streaming Programming Guide - ASF JIRA
spark = SparkSession.builder() 改为 spark = SparkSession.builder
2.
py4j.protocol.Py4JJavaError: An error occurred while calling o49.load.
: java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V
此报错是scala的版本过低所致,本人当前环境选用的是scala 2.11.0版本,升级到2.11.8后【版本建议和spark所支持的版本一致,版本号2.11.8仅作参考】,没有再出现此报错。
3.
'PipelinedRDD' object has no attribute '_jdf'
报这个错,是因为导入的机器学习包错误所致。
pyspark.ml 是用来处理DataFrame
pyspark.mllib是用来处理RDD。
所以你要看一下你自己代码里定义的是DataFram还是RDD。
sc = SparkContext() 【RDD】 应导入
from pyspark.mllib.feature import HashingTF, IDF
spark = SparkSession(sc) 【DataFrame】 应导入
from pyspark.ml.feature import HashingTF, IDF
4.
PySpark spark.sql 使用substring及其他sql函数,提示NameError: name 'substring' is not defined
解决办法,导入如下的包即可。
from pyspark.sql.functions import *
Scala则导入
import org.apache.spark.sql.functions._
5.
org.apache.spark.sql.DataFrame = [_corrupt_record: string]
读取json文件报错。
此问题首先要明白spark读取文件的原理,是按行作为一个record,所以你要看下你的json文件是否是平整的。下面我举个例子,
原json文件内容如下:【文件中存在换行符】
{
"staffList":{
"total":3,
"result":[
{
"toco":41,
"id":1,
"name":"张三",
"typeJoin":[
"22"
],
"type":2
},
{
"toco":46,
"id":2,
"name":"李四",
"typeJoin":[
"22"
],
"type":2
},
{
"toco":42,
"id":3,
"name":"王五",
"typeJoin":[
"22"
],
"type":2
}
]
}
}
解决方法①
应该将文件内容"压平"成为平面文件,转换成如下格式:
{"staffList" : {"total" : 3,"result" : [ { "toco" : 41, "id" : 1, "name" : "张三", "typeJoin" : 22, "type" : 2}, { "toco" : 46, "id" : 2, "name" : "李四", "typeJoin" : 22, "type" : 2}, { "toco" : 42, "id" : 3, "name" : "王五", "typeJoin" : 22 ], "type" : 2} ]}}
再读取json文件,即可。
解决方法Ⅱ
或者在读取json文件时,指定读取多行为真,option("multiLine", true) 。
6.
==========================================================
Spark SQL 和 DataFrames 支持下面的数据类型 :
- 数值类型
- ByteType : 表示 1 字节长的有符号整型,数值范围 : -128 到 127。
- ShortType : 表示 2 字节长的有符号整型,数值范围 : -32768 到 32767。
- IntegerType : 表示 4 字节长的有符号整型,数值范围 : -2147483648 到 2147483647。
- LongType : 表示 8 字节长的有符号整型,数值范围 : -9223372036854775808 到 9223372036854775807。
- FloatType : 表示 4 字节长的单精度浮点数。
- DoubleType : 表示 8 字节长的双精度浮点数。
- DecimalType : 表示任意精度有符号带小数的数值。内部使用 java.math.BigDecimal,一个BigDecimal 由一个任意精度的整数非标度值和一个 32 位的整数标度 (scale) 组成。
-
字符串类型
-
StringType : 表示字符串值
-
- 二进制类型
- BinaryType : 表示字节序列值
- 布尔类型
- BooleanType : 表示布尔值
- 日期类型
- TimestampType : 表示包含年月日、时分秒等字段的日期值
- DateType : 表示包含年月日字段的日期值
- Complex types(复杂类型)
-
ArrayType(elementType, containsNull) : 数组类型,表示一个由类型为 elementType 的元素组成的序列,containsNull 用来表示 ArrayType 中的元素是否能为 null 值。
-
MapType(keyType, valueType, valueContainsNull) : 映射类型,表示一个键值对的集合。键的类型由 keyType 表示,值的类型则由 valueType 表示。对于一个 MapType 值,键是不允许为 null值。valueContainsNull 用来表示一个 MapType 的值是否能为 null 值。
-
StructType(fields) : 表示由 StructField 序列描述的结构。
- StructField(name, datatype, nullable) : 表示 StructType 中的一个字段,name 表示字段名,datatype 是字段的数据类型,nullable 用来表示该字段是否可以为空值。
-
==========================================================
对于嵌套结构数据,如何定义schema
首先导入包 import org.apache.spark.sql.types._
其次,对于StructType的定义,参考spark源代码,有说spark/StructType.scala at master · apache/spark · GitHub
// Extract multiple StructFields. Field names are provided in a set. 提取多个StructField。字段名称以集合形式提供
org.apache.spark.sql.types.ArrayType Scala Example
还是参考之前一个嵌套结构json数据,定义一个Schema
{
"staffList":{
"total":3,
"result":[
{
"toco":41,
"id":1,
"name":"张三",
"typeJoin":[
"22"
],
"type":2
},
{
"toco":46,
"id":2,
"name":"李四",
"typeJoin":[
"22"
],
"type":2
},
{
"toco":42,
"id":3,
"name":"王五",
"typeJoin":[
"22"
],
"type":2
}
]
}
}
下面给出我写定义的schema
val jsSchema =
StructType(Seq(
StructField("staffList",
StructType(Seq(
StructField("total", IntegerType),
StructField("result", ArrayType(
StructType(Seq(
StructField("toco",IntegerType),
StructField("id",StringType),
StructField("name",StringType),
StructField("typeJoin",ArrayType(StringType)),
StructField("type",IntegerType))))))))));
# 或者
val jsSchema =
StructType(List(
StructField("staffList",
StructType(List(
StructField("total", IntegerType),
StructField("result", ArrayType(
StructType(List(
StructField("toco",IntegerType),
StructField("id",StringType),
StructField("name",StringType),
StructField("typeJoin",ArrayType(StringType)),
StructField("type",IntegerType))))))))));
spark上验证定义的schema正确
7.
WARN Utils: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.debug.maxToStringFields' in SparkEnv.conf.
==========
在交互环境,暂时修改
scala> spark.conf.set("spark.debug.maxToStringFields","100")
===========
永久修改
在节点(集群)的sparkEnv.sh中修改或新增spark.debug.maxToStringFields变量
8.
java.lang.IllegalArgumentException: Can't zip RDDs with unequal numbers of partitions
这个报错,是因为使用rdd的zip函数时,两个rdd的分区个数不一致所致。
摘录一段官方api说明:
Zips this RDD with another one, returning key-value pairs with the first element in each RDD, second element in each RDD, etc. Assumes that the two RDDs have the same number of partitions and the same number of elements in each partition (e.g. one was made through a map on the other).
解决的办法是: 将两个rdd的分区个数统一后,再zip。
附上伪代码:
RDD1.coalesce(1).zip(RDD2.coalesce(1))
9.
foreach(println)无法将RDD的字段,打印到stdout中?
Printing elements of an RDD
Another common idiom is attempting to print out the elements of an RDD using rdd.foreach(println) or rdd.map(println). On a single machine, this will generate the expected output and print all the RDD’s elements. However, in cluster mode, the output to stdout being called by the executors is now writing to the executor’s stdout instead, not the one on the driver, so stdout on the driver won’t show these! To print all elements on the driver, one can use the collect() method to first bring the RDD to the driver node thus: rdd.collect().foreach(println). This can cause the driver to run out of memory, though, because collect() fetches the entire RDD to a single machine; if you only need to print a few elements of the RDD, a safer approach is to use the take(): rdd.take(100).foreach(println).
关于RDD的输出,官网上是以上叙述:
意思就是:利用rdd.foreach(println) 或者 rdd.map(println),在一台机器上时,会得到理想的输出,打印出所有的RDD的数值;但在集群环境中,输出会被executors唤起,被写到executors的输出,而不是驱动所在的主机,所以在主机上不会显示打印信息,为了能够在主机上打印信息,要使用collect()函数首先把RDD放到主机节点上,rdd.collect().foreach(println),但因为collect()会将整个RDD的数据放到主机上,会使得驱动主机内存溢出。如果你只想打印出有限个RDD数据,一个靠谱的方法就是用take():rdd.take(100).foreach(println)
10.
spark Sql使用md5的方法:
详情参考:
scala - Function over multiple Spark DataFrame columns at once - Stack Overflow
11.
spark sql yyyymmdd to yyyy-MM-dd:
详情参考:
Scala: Spark SQL to_date(unix_timestamp) returning NULL - Stack Overflow
#伪代码
select(date_format(unix_timestamp(substring($"date",1,8), "yyyyMMdd").cast("timestamp"), "yyyy-MM-dd"))
spark.sql("""
SELECT DATE_FORMAT(
CAST(UNIX_TIMESTAMP('20161025', 'yyyyMMdd') AS TIMESTAMP), 'yyyy-MM-dd')
""")
#如果传的日期是整型,需要使用cast转换成string
# date 20161025
spark.sql("""
SELECT DATE_FORMAT(
CAST(UNIX_TIMESTAMP(cast(date as string), 'yyyyMMdd') AS TIMESTAMP), 'yyyy-MM-dd')
""")
12.
Spark sql 将array类型字符串转换成为一个字符串。
How to convert column of arrays of strings to strings?
apache spark - How to convert column of arrays of strings to strings? - Stack Overflow
In Spark 2.1+ to do the concatenation of the values in a single Array column you can use the following:
concat_ws
standard functionmap
operator- a user-defined function (UDF)
13.
spark sql scala row_number over 函数用法
scala - Update Spark Dataframe's window function row_number column for Delta Data - Stack Overflow
#伪代码
select(
col("KEY1"), col("KEY2"), col("VAL"), row_number().over(
Window.partitionBy(col("KEY1"), col("KEY2")).orderBy(col("Row_Num"))
).alias("New_Row_Num")
14.
Joining Multiple DataFrames using Multiple Conditions Spark Scala
Joining Multiple DataFrames using Multiple Conditions Spark Scala - Stack Overflow
伪代码:
val result = df1.as("df1").join(df2.as("df2"),
$"df1.col1"===$df2.col1" && $"df1.col2"===$df2.col2").join(df3.as("df3"),
$"df3.col1"===$df2.col1" && $"df3.col2"===$df2.col2", "left_outer")
15.
spark Sql 对于嵌套的结构的提取。
使用explode函数来操作,如果有多层嵌套,使用多次explode函数即可。
How to Extract Nested JSON Data in Spark - PHPFog.com
单层嵌套
{
"user": "gT35Hhhre9m",
"dates": ["2016-01-29", "2016-01-28"],
"status": "OK",
"reason": "some reason",
"content": [{
"foo": 123,
"bar": "val1"
}, {
"foo": 456,
"bar": "val2"
}, {
"foo": 789,
"bar": "val3"
}, {
"foo": 124,
"bar": "val4"
}, {
"foo": 126,
"bar": "val5"
}]
}
//explode content field
scala> val dfContent = df.select(explode(df("content")))
dfContent: org.apache.spark.sql.DataFrame = [col: struct<bar:string,foo:bigint>]
//output
scala> dfContent.show
+----------+
| col|
+----------+
|[val1,123]|
|[val2,456]|
|[val3,789]|
|[val4,124]|
|[val5,126]|
+----------+
//rename "col" to "content"
scala> val dfContent = df.select(explode(df("content"))).toDF("content")
dfContent: org.apache.spark.sql.DataFrame = [content: struct<bar:string,foo:bigint>]
//output
scala> dfContent.show
+----------+
| content|
+----------+
|[val1,123]|
|[val2,456]|
|[val3,789]|
|[val4,124]|
|[val5,126]|
+----------+
//extracting fields in struct
scala> val dfFooBar = dfContent.select("content.foo", "content.bar")
dfFooBar: org.apache.spark.sql.DataFrame = [foo: bigint, bar: string]
//output
scala> dfFooBar.show
+---+----+
|foo| bar|
+---+----+
|123|val1|
|456|val2|
|789|val3|
|124|val4|
|126|val5|
+---+----+
多层嵌套
提取tableData的数据
伪代码
val DailyPriceDimDF = DailyPriceDimDF_
.select($"code", explode($"content") as "data")
.select($"code", explode($"data.tableData") as "data")
16.
scala spark sql 将yyyymmdd的字符串转为yyyy-mm-dd日期类型:
伪代码
#openingHours 19970413000000
select(date_format(unix_timestamp(substring($"openingHours",1,8), "yyyyMMdd").cast("timestamp"), "yyyy-MM-dd").alias("approveDate")
)
spark.sql("""
SELECT DATE_FORMAT(
CAST(UNIX_TIMESTAMP('20161025', 'yyyyMMdd') AS TIMESTAMP), 'yyyy-MM-dd')
""")
#如果传的日期是整型,需要使用cast转换成string
# date 20161025
spark.sql("""
SELECT DATE_FORMAT(
CAST(UNIX_TIMESTAMP(cast(date as string), 'yyyyMMdd') AS TIMESTAMP), 'yyyy-MM-dd')
""")
17.
Spark Sql 日期函数的综合应用:
SPARK-SQL内置函数之时间日期类 - 飞末 - 博客园
Spark SQL Date Functions – Complete list with examples -
上述两个帖子,有日期函数的使用说明
下面说下重点,求出某一天对应年及月及日的指标,伪代码如下
//新增 day_of_year, week_of_year, month_of_year, day_of_week, day_of_month, days_of_month, days_of_year
#年的第几天
.withColumn("day_of_year", dayofyear(from_unixtime(col("unix_time"), "yyyy-MM-dd")).cast(LongType))
#年的第几周
.withColumn("week_of_year", weekofyear(from_unixtime(col("unix_time"), "yyyy-MM-dd")).cast(LongType))
#年的第几个月
.withColumn("month_of_year", month(from_unixtime(col("unix_time"))).cast(LongType))
#一周的第几天(周一为第一天,未使用dayofmonth,该函数的每周第一天是周日)
.withColumn("day_of_week", from_unixtime(col("unix_time"), "u").cast(LongType))
#月的第几天
.withColumn("day_of_month", dayofmonth(from_unixtime(col("unix_time"))).cast(LongType))
#所在月份有几天
.withColumn("days_of_month", datediff( last_day(trunc(from_unixtime(col("unix_time"), "yyyy-MM-dd"), "MM")), trunc(from_unixtime(col("unix_time"), "yyyy-MM-dd"), "MM")).cast(LongType) +1)
#所在年份有几天
.withColumn("days_of_year", datediff( concat(year(from_unixtime(col("unix_time"), "yyyy-MM-dd")), lit("-12-31")), trunc(from_unixtime(col("unix_time"), "yyyy-MM-dd"), "year")).cast(LongType) +1 )
#所在月份对应季度的最后一天
.withColumn("quarter_date", l
last_day(concat(year(from_unixtime(col("unix_time"))).cast(StringType),
lit("-"),
when(quarter(from_unixtime(col("unix_time"))) === 1, lit("03"))
.when(quarter(from_unixtime(col("unix_time"))) === 2, lit("06"))
.when(quarter(from_unixtime(col("unix_time"))) === 3, lit("09"))
.otherwise(lit("12")),
lit("-01"))
)
补充一个函数的说明:
date_trunc函数用法,我参考了官网的说明,发现其示例有错误。
Functions - Spark SQL, Built-in Functions
date_trunc
date_trunc(fmt, ts) - Returns timestamp ts
truncated to the unit specified by the format model fmt
.fmt
should be one of ["YEAR", "YYYY", "YY", "MON", "MONTH", "MM", "DAY", "DD", "HOUR", "MINUTE", "SECOND", "WEEK", "QUARTER"]
正确用法
18. Spark sql regexp_replace 及 rlike用法
工作中遇到了一些字符串中偶然含有 \n (软回车) \r (软空格),在写入到hive后,建Kylin cube时有报错,说明在数据清洗时,没有考虑到这一点。要在数据清洗时,去除 \n (软回车) \r (软空格)
当要匹配特殊的隐藏字符\n \r \t ,等回车符、制表符时,需要通过使用四个 \ 进行转译。
伪代码
# RDD的替换方法
s.replaceAll("[\\r\\n]", "")
# Spark Sql的替换方法
select(regexp_replace(trim($"name"), "[\\r\\n]", "").alias("name"))
#
sparkSession.sql(
"""
|select
|regexp_replace(title, '\\\\r|\\\\n|\\\\b|\\\\f|\\\\t','') title
|from tableName
""")
rlike用法
scala - Using rlike in org.apache.spark.sql.Column - Stack Overflow
Advanced String Matching with Spark's rlike Method - MungingData
19.
Spark Dataframe WHERE Filter 这两个函数的讲解
鉴于原贴写的很好,我就给个链接。
http://sqlandhadoop.com/spark-dataframe-where-filter/
Spark Dataframe IN-ISIN-NOT IN
http://sqlandhadoop.com/spark-sql-dataframe/ 一些用法值得借鉴
我只说一点 in 的用法,在spark sql里,需要用 filter( .isin) 的形式来展现。
20.
spark sql window函数初探:
先附上相关网站链接,后续给出自己的伪代码示例:
SparkCore / SparkSQL中窗口函数RANK, DENSE_RANK, ROW_NUMBER的区别_Jerry林的博客-优快云博客
spark sql窗口函数_ShyieZhang的博客-优快云博客_sparksql窗口函数
Introducing Window Functions in Spark SQL - The Databricks Blog
apache-spark Tutorial => Window functions - Sort, Lead, Lag , Rank...
21.
spark sql 从某一个表读取数据,之后再将数据写回原表,没有数据?
原因:回归问题本质,Spark是惰性执行。 具体解释请看如下帖子中的说明。
最佳答案
问题出在您的代码中.因为您覆盖了一个您尝试读取的表,所以在Spark实际访问它之前,您会有效地删除所有数据.
请记住,Spark是懒惰的.创建数据集时,Spark会提取所需的元数据,但不会加载数据.因此,没有魔法缓存可以保留原始内容.实际需要时将加载数据.在这里,当您执行写入操作时,当您开始写入时,不再需要获取数据.
你需要的是这样的:
>创建数据集.
>应用所需的转换并将数据写入中间MySQL表.
> TRUNCATE原始输入和INSERT INTO … SELECT从中间表或DROP原始表和RENAME中间表.
替代但不太有利的方法是:
>创建数据集.
>应用所需的转换并将数据写入持久性Spark表(df.write.saveAsTable(…)或等效表)
> TRUNCATE原始输入.
>读取数据并保存(spark.table(…).write.jdbc(…))
> Drop Spark表.
https://codeday.me/bug/20190309/744771.html
https://codeday.me/bug/20190301/716426.html
22.
org.apache.spark.sql.AnalysisException: Reference 'XXXXX' is ambiguous
原因是:多表join后,存在重复列的问题。
①解决办法,选择重复列时,指明该列来自之前join的DataFrame即可。
②join时,把重复列取别名。
下面对方法①做一个demo演示。
val joined = df.join(df2, df("course") === df2("course") && df("name") === df2("name"), "left_outer")
#出现了重复course 和 name 列
#取 course 和 name 列时,指定对应df的列即可
# 报错代码
val errCode = joined.select("name", "course")
#org.apache.spark.sql.AnalysisException: Reference 'XXX' is ambiguous
###########################
#正确代码
val rightCode = joined.select(df("name"), df("course"), df2("name"), df2("course"))
23.
SparkSQL - The correlated scalar subquery can only contain equality predicates
写spark Sql时,用到了嵌套select查询,但sql解析报错,究其原因,和spark本身sql解析机制有关,解决办法是:
改写原有sql即可。下面给出我的一个demo
##有个需求:填充非交易日股票价格,那么需要找到离非交易日最近的那个交易日股价。
###########
# 报错sql
val wrongDF = ss.sql("""
select a.stock_id, a.code, a.date_id, a.date_value,
(select max(b.date_id)
from stockPriceNotNullDF b
where b.stock_id = a.stock_id and b.date_id < a.date_id
) as oid
from stockPriceNullDF a
group by a.stock_id, a.code, a.date_id, a.date_value
order by a.stock_id, a.date_id
""")
#提示
The correlated scalar subquery can only contain equality predicates
###################
# 改写之后的sql,放弃使用子查询方式
val rightDF = ss.sql("""
select a.stock_id, a.code, a.date_id, a.date_value,
max(b.date_id) as oid
from stockPriceNullDF a, stockPriceNotNullDF b
where b.stock_id = a.stock_id and b.date_id < a.date_id
group by a.stock_id, a.code, a.date_id, a.date_value
order by a.stock_id, a.date_id
""")
24.
Spark SQL 的日期函数 dayofweek ,返回的天数,不是国人习惯的日期,改写方法。
参考官方文档解释:Functions - Spark SQL, Built-in Functions
HIVE 计算指定日期本周的第一天和最后一天 - chenzechao - 博客园
若改成国人习惯的日期,则需要自行转换,下面给出demo (scala中用when else 来判断)
//新增days_of_week 当周第几天(按照国人习惯,周一为第一天)
.withColumn("days_of_week", when(dayofweek(from_unixtime(col("unix_time"), "yyyy-MM-dd")) === 1, 7)
.otherwise(dayofweek(from_unixtime(col("unix_time"), "yyyy-MM-dd")) -1)
.cast(LongType))
25.
Spark Sql求出每一周的周一和周日
当看到这个需求时,很自然的想到用 date_sub或date_add函数,但参考官方文档的函数说明,发现其用法跟关心型数据库sql语法不太一致,需要做一些转换才可以达到想要的效果。
所以有一个变通的方法。 date_sub或者date_add与next函数相结合来满足这个需求
# date_value 2019-07-31
.withColumn("week_first_date_id", date_sub(next_day($"date_value", "monday"), 7))
.withColumn("week_end_date_id", when($"days_of_week" === 7, $"date_value")
.otherwise(next_day($"date_value", "sunday").cast(StringType))
)
如下是demo输出结果
26.
Spark DataFrame写入Hive Orc 分区表
分区表建立过程不过多演示,只给出写入hive表的过程。
//方法一:
addStgCompanyDF.write.partitionBy("dt").mode(SaveMode.Overwrite).orc("hdfs://XXXX/apps/hive/warehouse/XXXX.db/XXXXX/")
//方法二:
addStgCompanyDF.repartition(1).write.mode(SaveMode.Append).format("orc").insertInto("XXXX.XXXX")
Overwrite形式举例:
.write.mode(SaveMode.Overwrite).format("orc").saveAsTable("库名.表名")
Append形式举例:
.write.mode(SaveMode.Append).format("orc").insertInto("库名.表名")
分区表Overwrite形式举例:
.write.partitionBy("XX").mode(SaveMode.Overwrite).format("orc").saveAsTable("库名.表名")
分区表append(insertInto)形式举例:
.repartition(1).write.mode(SaveMode.Append).format("orc").insertInto("XXXX.XXXX")
数据写入hdfs后,如果通过hive去查询,表中无数据,还需要使用 msck 修复hive元数据信息。
MSCK REPAIR HIVE EXTERNAL TABLES - Cloudera Community - 229066
- hive> Msck repair table <db_name>.<table_name>
27.
Spark : org.apache.spark.sql.AnalysisException: Reference 'XXXX' is ambiguous
这个问题是大多是因为,多个表join后,存在同名的列,在select时,取同名id,无法区分所致。
解决办法:
①对于列名相同的列,在DataFrame中更名。alias或withColumnRenamed可以实现,demo代码就暂时不提供。
②在join后,drop掉同名的列
df1.join(df2,df1.a == df2.a,'left_outer').drop(df2.a)
28.
Spark 的Scala项目中,读取mysql数据
Spark JDBC To MySQL - 智能先行者 - 博客园
①在sbt配置文件中,添加mysql依赖。版本很多,选用哪一个版本均可以的,以下是示例:
libraryDependencies XXX
添加 "mysql" % "mysql-connector-java" % "5.1.28"
②sbt assembly
③读取mysql表方法:
import java.util.Properties
val mysqlUrl = "jdbc:mysql://localhost:3306/test"
val mysqlTable = "name_map"
val user = "XXX"
val password = "XXX"
val properties = new Properties()
properties.setProperty("user", user)
properties.setProperty("password", password)
properties.setProperty("driver","com.mysql.jdbc.Driver")
val df2 = ss.read.jdbc(mysqlUrl, mysqlTable, properties)
df2.show()
如下帖子中有一些可能的报错,值得借鉴:
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
解决办法:
可能还会有的报错:
ERROR ApplicationMaster: User class threw exception: java.sql.SQLException: No suitable driver
java.sql.SQLException: No suitable driver
在spark连接mysql的代码里指定driver为:"com.mysql.jdbc.Driver"
【properties.setProperty("driver","com.mysql.jdbc.Driver")】
29.
此作者写的很好,附送原链接地址,在这里不做过多赘述,只说明一些关键用法
spark 累加历史 + 统计全部 + 行转列 - zhangxuhui - 博客园
preceding:用于累加前N行(分区之内)。若是从分区第一行头开始,则为 unbounded。 N为:相对当前行向前的偏移量
following :与preceding相反,累加后N行(分区之内)。若是累加到该分区结束,则为 unbounded。N为:相对当前行向后的偏移量
current row:顾名思义,当前行,偏移量为0
说明:上边的前N,后M,以及current row均会累加该偏移量所在行
30.
Spark SQL case when用法:
https://sparkbyexamples.com/spark-case-when-otherwise-example/
how to write case with when condition in spark sql using scala - Stack Overflow
scala - SPARK SQL: Implement AND condition inside a CASE statement - Stack Overflow
上述几个帖子已经写得很详细了,我就不再赘述,只放出链接。
Spark Sql 使用Case when,存在多个when条件的代码示例:
SPARK SQL - case when then - Stack Overflow
伪代码:
select
CASE WHEN company_base = 'ah' THEN '安徽'
ELSE
CASE WHEN company_base = 'bj' THEN '北京'
ELSE
CASE WHEN company_base = 'cq' THEN '重庆'
ELSE
CASE WHEN company_base = 'fj' THEN '福建'
ELSE
CASE WHEN company_base = 'gd' THEN '广东'
ELSE
CASE WHEN company_base = 'gx' THEN '广西'
ELSE
CASE WHEN company_base = 'gs' THEN '甘肃'
ELSE
CASE WHEN company_base = 'gz' THEN '贵州'
ELSE
CASE WHEN company_base = 'han' THEN '海南'
ELSE
CASE WHEN company_base = 'heb' THEN '河北'
ELSE
CASE WHEN company_base = 'hen' THEN '河南'
ELSE
CASE WHEN company_base = 'hlj' THEN '黑龙江'
ELSE
CASE WHEN company_base = 'hub' THEN '湖北'
ELSE
CASE WHEN company_base = 'hun' THEN '湖南'
ELSE
CASE WHEN company_base = 'jl' THEN '吉林'
ELSE
CASE WHEN company_base = 'js' THEN '江苏'
ELSE
CASE WHEN company_base = 'jx' THEN '江西'
ELSE
CASE WHEN company_base = 'ln' THEN '辽宁'
ELSE
CASE WHEN company_base = 'nmg' THEN '内蒙古'
ELSE
CASE WHEN company_base = 'nx' THEN '宁夏'
ELSE
CASE WHEN company_base = 'sc' THEN '四川'
ELSE
CASE WHEN company_base = 'sd' THEN '山东'
ELSE
CASE WHEN company_base = 'sh' THEN '上海'
ELSE
CASE WHEN company_base = 'snx' THEN '陕西'
ELSE
CASE WHEN company_base = 'sx' THEN '山西'
ELSE
CASE WHEN company_base = 'tj' THEN '天津'
ELSE
CASE WHEN company_base = 'xj' THEN '新疆'
ELSE
CASE WHEN company_base = 'xz' THEN '西藏'
ELSE
CASE WHEN company_base = 'yn' THEN '云南'
ELSE
CASE WHEN company_base = 'zj' THEN '浙江'
ELSE
CASE WHEN company_base = 'qh' THEN '青海'
ELSE '未知'
END END END END END END END END END END END END END
END END END END END END END END END END END END END
END END END END END
AS company_base
from company
group by company_name
31.
Spark 读取mongo 使用withPipeline的用法:
在工作中遇到过需要从一个公司列表中找出mongo中存在的公司信息。参考Mongo语法 $in可支持这个用法
需要配合spark的.withPipeline来使用。
https://docs.mongodb.com/spark-connector/current/scala/aggregation/
pipeline需要给出的条件是字符串,所以需要对一些字段转换成字符串即可
【 scala 的 mkstring 用法 Scala mkString方法(把一个集合转化为一个字符串)_艾伦蓝的博客-优快云博客】
下面贴出关键的代码。
#dataFrame都只有公司名
val addCompanyNameArray = entryCompanyNameDF.except(stgCompanyNameDF).map(r => r.getString(0)).collect.toArray
#将公司Array转为字符串
// 将Array转换成String
var addCompanyNameStr = addCompanyNameArray.mkString("\"", "\",\"", "\"")
#读取Mongo的过程不做赘述
#下面 withPipeline 配合 $in来使用
val df = sc.loadFromMongoDB(readconf).withPipeline(Seq(Document.parse("{ $match: { 'name' : {$in : [" + addCompanyNameStr + "]} } }"))).toDF(schema)
32.
如何在spark Sql里 创建自增id字段,作为主键?
参考了很多Spark的RDD原生函数,比如zip(),zipWithIndex(),自增id,效率不高。尤其是DataFram转换成RDD,再用zipWithIndex()效率低下。下面我给出一个我认为比较合理的方法,借用row_number函数实现。
下面列出我的伪代码:
下面给出示例:
import org.apache.spark.sql.expressions.Window
/* Case: 1
df是一个DataFrame
需要为其建立主键
withColumn与row_number函数结合的方式完成
**/
df.withColumn("id",row_number.over(Window.partitionBy(lit(1)).orderBy(lit(1))).cast(LongType))
/* Case: 2
df是一个DataFrame
如果是在存量数据基础上再自增主键id
withColumn与row_number函数结合的方式完成
**/
//求当前df的最大id
var maxID = ss.sql("select if(max(id) is null, 0, max(id)) from XXXX").collect()(0)
var maxID_ = maxID(0).toString().toLong
// 在row_number()函数基础上,再加上 maxID_即可
df.withColumn("id",row_number.over(Window.partitionBy(lit(1)).orderBy(lit(1))).cast(LongType)+lit(maxID_))
33.
scala.collection.mutable.WrappedArray$ofRef cannot be cast to scala.collection.immutable.Set
在工作中,需要些UDF函数,对某些字段做替换。对数组类型转换时,遇到如下报错
情景复原:
原始代码中使用了 Array[] 来定义,根据网络上一些解释,此方法,会引用WrappedArray。 建议将Array 换成Seq。
参考:
官方文档写的很详细
数组 | Collections | Scala Documentation
34.
play 框架中如何使用start、stop、restart、status脚本化操作?
参考了一个人写的:https://gist.github.com/cnicodeme/6917319
#!/bin/bash
#
# --------------------------------------------------------------------
# This is a free shell script under GNU GPL version 3.0 or above
# Copyright (C) 2005 ReFlectiv project.
# Feedback/comment/suggestions : http://www.reflectiv.net/
# -------------------------------------------------------------------------
#
# This scripts do the start/stop/restart of a PlayFramework project with GIT Support
#
### BEGIN vars
PORT=9100
BASE_DIR=/path/to/play/project/
CONF_PATH=/path/to/play/project/conf/application.conf
PLAY_VERSION=2.1.5 # We assume Play is in /opt/play/{version}, eg: /opt/play/2.1.5/
# Specific project configuration environment :
export _JAVA_OPTIONS="-Xms1024m -Xmx1024m -XX:PermSize=512m -XX:MaxPermSize=512m"
### END vars
# Exit immediately if a command exits with a nonzero exit status.
set -e
update() {
echo "Updating"
cd $BASE_DIR || exit
unset GIT_DIR
# Update repo
git pull origin master
cd $BASE_DIR
# Creating new project (MUST BE ON THE GOOD DIR)
/opt/play/$PLAY_VERSION/play clean compile stage
}
start() {
echo "Starting server"
eval $BASE_DIR$ENV"/target/start -Dhttp.port="$PORT" -Dconfig.file="$CONF_PATH" &"
}
stop() {
echo "Stopping server"
if [ -f $BASE_DIR"/RUNNING_PID" ];then
kill `cat $BASE_DIR$ENV"/RUNNING_PID"`
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
update)
update
;;
force-restart)
stop
update
start
;;
*)
echo $"Usage: $0 {start|force-restart|stop|restart|update}"
esac
exit 0
如下是我的修改后的脚本:
#!/bin/bash
### BEGIN vars
PORT="XXX"
BASE_DIR="XXXXX"
PLAY_NAME="XXXXXX"
PLAY_VERSION=2.7.3
### END vars
# Exit immediately if a command exits with a nonzero exit status.
set -e
run() {
apiPid=`ps -ef | grep $PLAY_NAME | grep -v grep|awk '{print $2}'`
if [ -z "$apiPid" ]
then
echo "Starting server"
rm -f ${BASE_DIR}/RUNNING_PID
nohup ${BASE_DIR}/bin/${PLAY_NAME} -Dplay.http.secret.key=XXXXXXXXXX -Dhttp.port=${PORT} > ${BASE_DIR}/logs/${PLAY_NAME}.logs 2>&1 &
else
echo "${PLAY_NAME} is already running....."
netstat -nlp | grep "$apiPid"
fi
}
stop() {
rm -f ${BASE_DIR}/RUNNING_PID
apiPid=`ps -ef | grep $PLAY_NAME | grep -v grep|awk '{print $2}'`
if [ -z "$apiPid" ]
then
echo "$PLAY_NAME is Not running....."
else
echo "Stopping server"
kill -s 9 `ps -ef | grep $PLAY_NAME | grep -v grep |awk '{print $2}'`
fi
}
status() {
#echo "Status server"
apiPid=`ps -ef | grep $PLAY_NAME | grep -v grep|awk '{print $2}'`
if [ -z "$apiPid" ]
then
echo "$PLAY_NAME is Not running....."
else
echo "$PLAY_NAME is running....."
netstat -nlp | grep "$apiPid"
fi
}
case "$1" in
run)
run
;;
stop)
stop
;;
restart)
stop
run
;;
status)
status
;;
*)
echo $"Usage: $0 {run|stop|restart|status}"
esac
exit 0
35.
Spark 2.4版本以下没有array_join、array_sort 函数,可变通的办法。
首先 ,先要知道 array_join 及 array_sort的函数用法,详情请参考如下网址:
Apache Spark 2.4 新增内置函数和高阶函数使用介绍 – 过往记忆
下面给出Spark 2.4的 demo代码
select
row_number() OVER (PARTITION BY 1 ORDER BY 1) id,
md5(array_join(array_sort(collect_set(f.holder_id)),'|')) association_id,
current_timestamp() date_modified,
first(f.date_id) date_id,
array_join(array_sort(collect_set(f.holder_id)),'|') horder_ids_string,
size(collect_set(f.holder_id)) holder_count,
first(h.type) holder_type,
first(h.type_name) holder_type_name,
first(f.date_id) dt
from XXXXX f, XXXX h
where f.holder_id=h.id
group by f.association_tmp_id
下面给出Spark2.3版本的实现方法,即采用先排序,再用collect_list函数完成array_join、array_sort的功能
select
row_number() OVER (PARTITION BY 1 ORDER BY 1) id,
md5(concat_ws("|", collect_list(cast (holder_id as varchar(20))))) association_id,
current_timestamp() date_modified,
date_id,
concat_ws("|", collect_list(cast (holder_id as varchar(20)))) horder_ids_string,
size(collect_set(holder_id)) holder_count,
holder_type,
holder_type_name,
dt
from
(
select f.association_tmp_id,
f.holder_id,
f.date_id,
f.holder_type,
h.type_name as holder_type_name,
f.date_id as dt
from
XXXXXXXX f, XXXX h
where f.holder_id=h.id
order by f.date_id, f.association_tmp_id, f.holder_id
)
group by date_id, association_tmp_id, holder_type, holder_type_name, dt
写的比较简洁,若有什么其他问题,欢迎在评论区提问,我看到后会回复的。
36.
Spark 读取嵌套Json文件的方法
写此问题,我参考了很多现有的帖子说明,综合了各方的方法,我以我的实际操作过程,来说明使用哪种方法最为合适:
附参考网页
Stack Overflow:
How to read the multi nested JSON data in Spark [duplicate]
How to read the multi nested JSON data in Spark - Stack Overflow
BIG DATUMS
How to Extract Nested JSON Data in Spark - PHPFog.com
砖厂 databricks
Complex and Nested Data
Query semi-structured data in Databricks | Databricks on AWS
综合评价,以砖厂的参考方法为正统
如下是我的探索过程:
给出一条嵌套json文件(关键信息,以模糊化处理,请理解),请关注读取过程
下面给出关键代码:
select(
trim($"container").alias("container_id"),
trim($"type").alias("type"),
trim($"destination").alias("destination"),
//利用explode函数,把locations数组数据进行展开
explode($"locations").alias("locations")
)
结果如下
再读取locations内的嵌套数据,参考给出的方法 使用诸如 "locations.date" 或者 col("locations.date") 。Spark均提示有报错,提示
Can't extract value from locations#29
下面给出探索过程的代码截屏
提示报错
综合砖厂给出的方法,使用 get_json_object() 函数,成功提取locations的数据
给出关键代码
.select(
$"container_id",
$"type",
$"destination",
get_json_object($"locations", "$.date").alias("update_date"),
get_json_object($"locations", "$.shipped").alias("shipped"),
get_json_object($"locations", "$.port").alias("port"),
get_json_object($"locations", "$.status").alias("status"),
get_json_object($"locations", "$.vesselName").alias("vessel_name"),
get_json_object($"locations", "$.voyage").alias("voyage"),
get_json_object($"locations", "$.terminal").alias("terminal"),
get_json_object($"locations", "$.country").alias("country")
)
.withColumn("id",row_number.over(Window.partitionBy(lit(1)).orderBy(lit(1))).cast(LongType) )
.withColumn("date_modified",lit(com.github.nscala_time.time.Imports.LocalDate.today.toDateTimeAtCurrentTime().toString()).cast("timestamp"))
得出的数据如下
所以,参考砖厂的文档最好。
Query semi-structured data in Databricks | Databricks on AWS
37. Spark-shell启动时,报如下错误
java.lang.AssertionError: assertion failed: unsafe symbol SparkSession (child of package sql) in runtime reflection universe
此报错,实属罕见。排除了spark配置及集群参数等后,追本溯源,怀疑是服务器上误上传了一个jar包到了spark指定目录,删掉后,问题解决。
删掉
/usr/hdp/2.6.5.0-292/spark2/jars/ Spark该目录下存在的一个jar包: XXXXX.spark-XXXXX-0.0.1.jar (此jar包,是某项目用到的jar包,是误操作上传到此目录)。
即可
38.Scala IDE: Scala Library error on a new project
如下帖子讲解的很详细
Scala IDE: Scala Library error on a new project – Kev's Development Toolbox
39.
hive 在使用 count(distinct ) over 时报错,提示 FAILED: SemanticException [Error 10025]: Line 1:123 Expression not in GROUP BY key 解决办法
参考了很多帖子,都没有说明解决办法。
我给出一个折中的参考方案,在聚合前,先将数据去重,再cout() over 即可。
下面给出我的参考范例
某股东一致行动人持有相同的股票,需要求出改一致行动人累计的上榜次数及持有股票累计次数。
select dt,holder_list, count(distinct holder_list) over(partition by dt) as rn,
count(distinct code) over(partition by dt, holder_list) as rn2
from XXXX
#####################
# 提示报错 Expression Not In Group By Key
需要去重后再去统计
### 统计股东一致行动人累计上榜次数
select dt, holder_list, count(dt) over (partition by holder_list order by dt) as rn
from
(select distinct dt, holder_list
from XXXX
)
#### 统计股东一致行动人持有股票累计上榜次数
select dt, code, count(code) over (partition by holder_list, code order by dt) as rn
from
(select distinct dt, holder_list, code
from XXXX
)
可以得到最后类似 count(distinct) 效果
40.
Hive中的复杂数据类型Array,Map,Structs的一些查询
参考
Hive中对array类型字段的处理_爱吃西蓝花的老张的博客-优快云博客_hive 空array
关于Hive中的复杂数据类型Array,Map,Structs的一些使用案例_搜索与推荐Wiki的博客-优快云博客_hive array去重
41.Scals sbt 国内镜像配置:
我参考了很多说明,最后看到了如下帖子所说的配置最为完整,(阿里等镜像,不完整)
感谢华为云提供的镜像。
[repositories]
local
huaweicloud-maven: https://repo.huaweicloud.com/repository/maven/
maven-central: https://repo1.maven.org/maven2/
sbt-plugin-repo: https://repo.scala-sbt.org/scalasbt/sbt-plugin-releases, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]
42.Spark.read.csv 配置项示例:
如下几篇博客,写的很详细,建议大家参考借鉴,我在这里就不班门弄斧了,附上链接,只做一个搬运工。
Generic Load/Save Functions - Spark 3.3.1 Documentation
Spark - csv read option - Stack Overflow
Spark Read CSV file into DataFrame - Spark by {Examples}
43.org.apache.spark.sql.AnalysisException: Can not create the managed table The associated location already exists
在写入Hive表时,表已经删除,但文件还在,
参考
中断后在覆盖模式下创建表失败 - Azure Databricks | Microsoft Learn
将标志设置 spark.sql.legacy.allowCreatingManagedTableUsingNonemptyLocation
为 true
.set("spark.sql.legacy.allowCreatingManagedTableUsingNonemptyLocation","true")
重新写入该表即可。
44.spark-shell 报错提示 error: not found: value SaveMode
情景复现,通过spark-shell控制台,将读取的数据写入hive表,但总提示error: not found: value SaveMode
解决办法:
在spark-shell 控制台,输入 import org.apache.spark.sql._
45.hive -e 提示 X.sh: line XXX: percent: command not found和not recognize input near ‘percent‘ ‘*‘
报错提示的截图
场景复现:
有对一个Hive表做数据清洗,其中某个表字段是percent;
而percent是hive的一个函数,所以写sql时需要使用反引号“`”对字段进行引用
比如:
select
id,
name,
`percent`
from XXXX
where
name = 'XXX'
在写Hive脚本时,想当然的仍然对percent字段做反引号的引用;但在实际操作中有报错
hive -e \
"select \
id, \
name, \
`percent`
from XXXXX \
where XXXXX" \
| sed -e 's/[\t]/,/g' \
| grep -v "WARN" \
| grep -v "main ERROR" \
> XXXXXX_data.csv;
因为shell脚本里,反引号“`”是有特殊的含义:shell中的反引号(` `)的作用 将反引号(` `)内的字符串当作shell命令来执行,返回值是命令的执行的结果,起到的是一个命令的替换作用。所以,在此处,percent并不是shell的命令,
才会有本文刚开始提示的报错 XXXX.sh: line XXX: percent: command not found
解决办法:应在“`”(反引号)前添加转移字符“\”,对于我这个报错场景,`percent`转变为\'percent\`
select
id,
name,
\`percent\`
from XXXXX
伪代码如下:
hive -e \
"select \
id, \
name, \
\`percent\`
from XXXXX \
where XXXXX" \
| sed -e 's/[\t]/,/g' \
| grep -v "WARN" \
| grep -v "main ERROR" \
> XXXXXX_data.csv;
46. org.apache.spark.SparkException: Could not find CoarseGrainedScheduler
报错:
ERROR server.TransportRequestHandler: Error while invoking RpcHandler#receive() for one-way message. org.apache.spark.SparkException: Could not find CoarseGrainedScheduler. at org.apache.spark.rpc.netty.Dispatcher.postMessage(Dispatcher.scala:160) at org.apache.spark.rpc.netty.Dispatcher.postOneWayMessage(Dispatcher.scala:140) at org.apache.spark.rpc.netty.NettyRpcHandler.receive(NettyRpcEnv.scala:655)
参考
解决办法:
提交Spark代码时,设置如下参数值改为一个较大值(单位:秒):
spark.dynamicAllocation.executorIdleTimeout
比如
--conf spark.dynamicAllocation.executorIdleTimeout=360000