太久没写博客了,我,回来了。

忙完毕业,写点啥呢,写点实习中的东西吧,主要关于spark的使用相关,相当于之前spark-scala的进阶版?惯例,我主要是做个笔记自己看的,如有雷同,算我抄你的。

  • rdd与dataframe选哪个用
  • dataframe的几个操作
  • 一些环境参数的配置与submit的问题
  • 一些语法细节的坑

rdd与dataframe

先说重点:尽量使用dataframe
看下,谢谢作者。

  • rdd
    (1)遇到action算子触发作业,transformation算子是不会立即触发作业提交,具体细节百度/Google;
    (2)stage的划分,划分的依据是依赖算子是否是shuffle(如reduceByKey,Join等)的,每个stage又可以划分成若干task;这个可以这么看,没有shuffle之前都是map操作,不怎么涉及节点之间的通信;
    (3)分区(Partition),影响你的并发和计算效率,比如,1000个并发,200个Partition,另外800个并发就空闲着,所以合理的设置repartition和shuffle.partitions
  • dataframe
    (1)DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库中的二维表格,和sql像的很;
    (2)Spark SQL得以洞察更多的结构信息,从而对藏于DataFrame背后的数据源以及作用于DataFrame之上的变换进行了针对性的优化,最终达到大幅提升运行时效率的目标;RDD,由于无从得知所存数据元素的具体内部结构,Spark Core只能在stage层面进行简单、通用的流水线优化。

dataframe的几个操作

想起来几个算几个吧,有点忘了。。

  • 一行变多行
    explode[A, B](inputColumn: String, outputColumn: String)
    例子1:xxDF.explode( “c3” , “c3_” ){time: String => time.split( ” ” )},原始c3列为String类型;
    例子2:withColumn(“A_”, explode(col(“A”))).drop(“A”),原始A列为Array类型;
  • 多行变一行
    groupBy(col1: String, cols: String*)
    例子1:groupBy(“A”).agg(collect_list(“B”) as “B_list”).withColumn(“C”, func1(func2(col(“B_list”))));
  • 多列拼接为一列
    concat
    例子1: select(col(“A”), concat(col(“B”), lit(“\t”), col(“C”)) as “BC”)
  • 一列变多列
    withColumn也行
  • join操作
    大表放左边
  • 填补缺失项
    DF.na.fill(value = 1.0f, cols=Array(“A”))
  • 增加某一固定列
    withColumn(“flag”, lit(“666”))
  • 重命名某一列
    withColumnRenamed(“A”, “C”)
  • 转换列的数据类型
    例子1:val df2 = df1.withColumn(“id1”,col(“id”).cast(StringType)).drop(“id”)
  • 比较diff
    例子1:val diff = when(col(“id1”) === col(“id”),1).otherwise(0)
    val cross_df = df2.join(df2_,”id”,”left”).withColumn(“diff”, diff).filter(col(“diff”) === 0)
  • dataframe某列进行统计排序
    例子1:val df_count = df_label.select(“T”).groupBy(“T”).count
    val df_count_sort = df_count.orderBy(“count”)
    细节见//

一些参数上的配置与submit的问题

常见的就不说了,说下其他的,主要是优化任务执行

  • 预执行/推测任务
    推测任务是指对于一个Stage里面拖后腿的Task,会在其他节点的Executor上再次启动这个task,如果其中一个Task实例运行成功则将这个最先完成的Task的计算结果作为最终结果,同时会干掉其他Executor上运行的实例。spark推测式执行默认是关闭的,可通过spark.speculation属性来开启。
    换句话说:有的搬砖工实在搬这个task太累,那么启动其他并发来做这个,谁先做完就把其他的任务kill掉,很明显这样可以提高速度,但是需要额外的资源。需要观察任务执行的时间分布,如果存在明显拖后腿的现象,则可以使用
  • GC Time
    GC Time太长,影响任务的速度。集群硬件的配置此处不太懂,不乱说,从使用者的角度,GC Time过高解决的思路:
    (1)给每个task分配的内存的确很少,调大内存executor memory
    (2)机器负载太重,cpu占用过高,导致没有cpu资源进行gc,从而gc时间长。(可以加入sepculate机制)

其他submit参数优化见,谢谢作者。

一些语法细节的坑

  • 读取文件
    本地文件:sc.textFile(“file:///home/xx”);
    hafs文件:spark.read.parquet(“hdfs://xx”)
    注意本地的斜杠有3个;
  • trim函数
    删除指定字符串的首尾空白符,类似会把什么”\001”,”\002”、”\t”、”\n”等都去掉的,小心用;
  • split函数
    主要关于split不小心会丢掉后面的空字符串,有毒,细节见
  • 一点小操作
    如果需要简单的二次排序,将2个key组合为tuple作为key,然后sortBy;