• sparksql 核心概念


    Spark-sql概念补充

    基本概念
            SparkSQL是基于RDD的,可以通过Schema信息来访问其中某个字段
            RDD处理的不是结构化数据,所以不能进行类似HIve逻辑优化器的优化操作(条件传播)
            SparkSQL默认读取的类型都是 DataFrame 
    Catalyst优化器
            1.解析SQL,并解析成AST(抽象语法树)
            2.在树里面加入元数据信息
                scan(peolple) scan(score)  =>  join  =>  filter  =>  peoject  => Aggregate(sum(v))
                id#1#l  名称 列下标 数据类型
            3.优化器 优化(hive 优化)   最后经过成本优化
                val qe = data.queryExecution
                println(qe)
                == Parsed Logical Plan == //解析逻辑执行计划
                'Project ['gaid, unresolvedalias('from_unixtime('submit_at, yyyyMMdd), None)]
                +- 'UnresolvedRelation `data`

                == Analyzed Logical Plan ==//分析逻辑计划
                gaid: string, from_unixtime(CAST(submit_at AS BIGINT), yyyyMMdd): string
                Project [gaid#10, from_unixtime(cast(submit_at#11 as bigint), yyyyMMdd, Some(Asia/Shanghai)) AS from_unixtime(CAST(submit_at AS BIGINT), yyyyMMdd)#14]
                +- SubqueryAlias `data`
                +- Relation[gaid#10,submit_at#11] csv

                == Optimized Logical Plan ==//优化逻辑计划
                Project [gaid#10, from_unixtime(cast(submit_at#11 as bigint), yyyyMMdd, Some(Asia/Shanghai)) AS from_unixtime(CAST(submit_at AS BIGINT), yyyyMMdd)#14]
                +- Relation[gaid#10,submit_at#11] csv

                data.explain()
                == Physical Plan ==//物理执行计划
                *(1) Project [gaid#10, from_unixtime(cast(dt#11 as bigint), yyyyMMdd, Some(Asia/Shanghai)) AS from_unixtime(CAST(dt AS BIGINT), yyyyMMdd)#27]
                +- *(1) FileScan csv [gaid#10,dt#11] Batched: false, Format: CSV, Location: InMemoryFileIndex[file:/data/aa/data.csv], PartitionFilters: [], PushedFilters: [], ReadSchema: struct<gaid:string,dt:string>
    DataSet(结构化数据 自定义的数据类) 转成DataSet:.toDS()
            特点:
                强类型API  自定义数据类  
                若类型API  可以直接访问类的属性 当做字符串
                可以直接在类中使用SQL( 类的属性 < 10) 当做一列
            DataSet[] 支持优化器优化
                执行计划中都是RDD[InternalRow] 数据结构  
                将数据结构保存下来,在集群中运行
                RDD[InternalRow] = dataset.queryExecution.tordd  //获取的是已经分析和解析过的 dataset 的执行计划中拿到的
                RDD[Persion] = dataset.rdd //将底层的RDD[InternalRow] 通过Decoder转成了和 dataset 一样的RDD
    DataFrame(固定类型的列值,类似关系型数据库,行和列 Row +Schema )
            创建方式:1.toDF() 底层DatasetHolder  2.createDataFrame  3.read
    DataSet DataFrame区别
            1.DataFrame就是DataSet      DataFrame = Dataset[ROW]   DataSet可以是任意的类型(自定义类)
            2.DataFrame弱类型(ROW)   DataSet强类型 
                df.map((row:Row)=>Row(row.get(0),row.get(1)))(RowEncoder.apply(df.schema)) //df输入是ROW输出也是ROW
                ds.map((persion:Persion)=>Persion(name,age)) //是具体的类型
            3.DataFrame:编译时候不安全    DataSet:编译时候安全的
        Row对象的操作
            1.Row必须配合Schema对象才有列名  val row = Row("aa",1)  row.getString(1)  支持样例类
    DataFrameReader DataFrameWriter
            DataFrameReader  
                option:delimiter 分隔符,默认为逗号|nullValue 指定一个字符串代表 null 值|quote 引号字符,默认为双引号|
                header 第一行不作为数据内容,作为标题|
    inferSchema 自动推测字段类型|gnoreLeadingWhiteSpace 裁剪前面的空格|
                ignoreTrailingWhiteSpace 裁剪后面的空格|nullValue 空值设置,如果不想用任何符号作为空值,可以赋值null即可|multiline  运行多列,超过62 columns时使用|
                encoding   指定編码,如:gbk  / utf-8  Unicode  GB2312|

            DataFrameWriter
                mode "error":目标存在报错  "append":添加  "overwrite":覆盖  "ignore":存在就不报错
                partitionBy分区字段   bucketBy桶表字段  sortBy排序子段
            json toJSON 将字符串转成json   
    Spark 数据操作
            有类型转换算子
                flatMap() map() mapPartitions(iter=>{  }) 
                transform(dataset => dataset.withColumn("double","abcd")) //将一个dataset转换成另一个dataset
                as[Student]  //DataFrame 转换成 DataSet 
                filter(col("a")>10).show(10,false);//过滤条件
                groupByKey(perison=>perison.name) //需要把一列转换成key  转换以后才能进行agg cogroup reduce count
                randomSplit()  sample()
                ds.orderBy('false'.desc desc_nulls_first desc_nulls_last )   sd.sort('age'.asc)//排序
                distinct()//去除所有重复列  ds.dropDuplicates('')//按照某一列去重
                except() //除了   intersect//交集   union//并集
            无类型转换算子
                select //查询结果  可以在任何位置   selectExpr(sum(age)) //表达式格式
                    import org.apache.spark.sql.functions._ select(expr("sum(age)"))
                withColumn("double","abcd")  withColumn("double","abcd"===NULL)//新建列    withColumnRenamed('name','name_new')//重命名列
                drop("")//删除某列    
                groupBy() //groupByKey生成的算子是有类型的   生成的算子是无类型的
            Column对象
                as ds.select('name' as 'new_name')//别名  as ds.select('name'.as[Int])//类型转换
                ds.withColumn('double','age'*(2))   //新增列    ds.where('aa' like "zhang%")//模糊查询
                ds.sort("age".desc).show()//排序   ds.where("name" isin("zhangsan","lisi") )//枚举
            缺失值
                类型:1.nullNaN等特殊类型的值  2."Null","NA"," "等字符串缺失值
                处理框架:DataFrameNaFuncions   .na.drop     .na.fill(0,List("name","age"))
                处理:执行schema类型处理空置,将缺失值转换对对应对象下的NaN
                    select(when("PM" === "NA",Double.Nan).otherwise('PM' cast DoubleType) ).as("PM")
                    .na.replace("NA",Map("NA" -> "NaN"))//原始类型必须和处理后的类型一致
            聚合操作 (返回的类型都是 RelationalGroupedDataset)
                ds.groupBy("name","age").agg(avg("pm"as "pmavg")
                ds.avg("pm").select(col("avg(pm)"as "pm_avg")
                rollup("name","age").agg(sum("amount"as "amount"//第一列必须存在group by name,age/name/null 
                cube("name","age").agg(sum("amount"as "amount")   //全排列  group by name,age/name/age/null

                grouping sets sql格式:"group by name,age grouping sets ((name,age),name,age,())"
                cube sql格式:"group by cube(name,age)"
                rollup sql格式:"group by rollup(name,age)"
                RelationalGroupedDataset
            连接操作
                data.join(data1,data.col("id")===data1.col("id"), )
                joinType:"inner,cross,outer,full,full_outer,left,left_outer,right,right_outer,left_semi,left_anti"
                cross:笛卡尔积  inner:交叉连接  full full_outer:全外连接  left_semi:只显示左边连接上的   left_anti:只显示左侧关联不上的
            udf
                val toStrUdf = udf(aa _)   .select(toStrUdf("name"))
            窗口函数
                val window = Window.partitionBy("name").orderBy("age")
                .select(dense_rank() over window as "rank").where("rank"<2)
                sql格式:("dense_rank() over(partation by name order by age) as 'rank' ")
                ROWS between 2000 preceding and 1000 following //前一天数据和有一条数据
                rank() 相同排名 名次相同,后面+2
                dense_rank() 相同排名 名次相同,后面+1
                row_number()  first_value() last_value()  lag()前多少条  lead()后多少条
  • 相关阅读:
    LDAP2-创建OU创建用户
    GNE: 4行代码实现新闻类网站通用爬虫
    为什么每一个爬虫工程师都应该学习 Kafka
    新闻网页通用抽取器GNEv0.04版更新,支持提取正文图片与源代码
    写了那么久的Python,你应该学会使用yield关键字了
    新闻类网页正文通用抽取器
    为什么Python 3.6以后字典有序并且效率更高?
    为什么你需要少看垃圾博客以及如何在Python里精确地四舍五入
    数据工程师妹子养成手记——数据库篇
    一行js代码识别Selenium+Webdriver及其应对方案
  • 原文地址:https://www.cnblogs.com/wuxiaolong4/p/16628841.html
Copyright © 2020-2023  润新知