读取文件,Rdd,DataFrame,DataSet理解
Rdd : 算子,或者我们可以将其理解为一个数组(虽然它不是数组),想象它就像一个长方形的容器,里面就单纯的存储着数据
DataFrame : 将Rdd比作长方形的容器,DataFrame就是多个长方形的容器拼接组成,也就是将rdd加上表格化就是dataframe
DataSet :,DataSet有很多的类型,相当于是由rdd经过不同类型组合起来的,其中一种类型就是DataFrame, 及Dataset[Row]=DataFrame
三者转换:
1).RDD转换DataFrame或者Dataset
转换DataFrame时,定义Schema信息,加上表格化
转换为Dataset时,不仅需要Schema信息,还需要RDD数据类型为CaseClass类型
2)Dataset或DataFrame转换RDD
由于Dataset或DataFrame底层就是RDD,所以直接调用rdd函数即可转换
dataframe.rdd 或者dataset.rdd
3)DataFrame与Dataset之间转换
由于DataFrame为Dataset特例,所以Dataset直接调用toDF函数转换为DataFrame
当将DataFrame转换为Dataset时,使用函数as[Type],指定CaseClass类型即可。
下面原文更清楚链接:https://blog.csdn.net/ZGL_cyy/article/details/119865313
scala读取Hadoop数据库
// 创建SparkSession对象 val spark = SparkSession.builder().appName("aaa").config("spark.master", "local") // 设置Hadoop文件系统 .config("spark.hadoop.fs.defaultFS", "hdfs://192.168.52.147:8020").getOrCreate() // 从HDFS中读取数据 val rdd = spark.sparkContext.textFile("hdfs://192.168.52.146:9000/data/userbehavior/UserBehavior.csv")
scala读取本地文件
读取本地文件有3种方法,它们之间也有很大的差异
1.使用spark.sparkContext.textfile,这样读取的文件后aaa是一个rdd,方便进行api处理
val conf = new SparkConf().setAppName("etldemo").setMaster("local") val spark = SparkSession.builder().config(conf) .enableHiveSupport() //------Hive支持 .getOrCreate() val aaa = spark.sparkContext.textFile("D://File/wechat/test.log")
2. 使用spark.read.csv,这样读取文件是一个dataframe,使用read.csv获得的数据spark对其进行了处理,它将数据根据一列一列分割开了,变成一个表格化
val df = spark.read.csv("hdfs://192.168.52.147:8020/app/data/exam/meituan_waimai_meishi.csv")
val df = spark.read.option("header", "true").csv("hdfs://192.168.52.147:8020/app/data/exam/meituan_waimai_meishi.csv") //它可以加上.option("header", "true")为数据是否加上表头,true为保留表头,false去除表头,
3.使用.read.text 方法读取文本文件返回一个 DataFrame。这个 DataFrame 的每一行对应文本文件中的一行。就只是读取了文件,没有任何处理,数据就是一行一坨在一起的。
val df = spark.read.text("hdfs://192.168.52.147:8020/app/data/exam/meituan_waimai_meishi.csv") //
数据处理
Rdd的Api处理,先将DataFrame转换为RDD,或者本来就是Rdd
.map(x=>(x(1),x(2)) ---将数据中的第二个和第三个数据拿出来,可以衍生在map里面进行处理数据如相加或者乘除
.filter(!_.startsWith("sp_id")) ---过滤掉以"spu_id"开头的行
.map(_.split(",",-1)) ---分割每行,保留所有尾随的空字符串
同一种目的的reduceByKey,reduce,groupBy的不同用法
val keyValuePairs = aaa.rdd.map(arr => (arr(2), 1)).reduceByKey(_ + _).foreach(println) //生成了一个以该元素的第三个元素为键、以1为值的键值对,将具有相同键的所有值相加。 val ccc=aaa.rdd.map(x=>(x (2),x(0),x(1),1)).reduce((x,y)=>(x._1,x._2,x._3,x._4+y._4)) //将filteredAndSplitRDD中的每个元素映射为一个元组,元组的第一个元素为x(2),第二个元素为x(0),第三个元素为x(1),第四个元素为1 val ddd=aaa.rdd.map(x=>(x (2),x(0),x(1))).groupBy(x=>x._1).map(x=>(x._1,x._2.toList.size)).foreach(print) //将aaa中的每个元素映射为一个元组,元组的第一个元素为x(2),第二个元素为x(0),第三个元素为x(1)
val dd=rdd.map(x=>(x(1),x(2).toDouble)) // 将每个元组映射为一个元组,元组的第一个元素为x(1),第二个元素为一个元组,元组的第一个元素为x(2),第二个元素为1 .map(x=>(x._1,(x._2,1))) // 按照x(1)进行分组,并对每个分组中的元组进行reduce操作,将x(2)相加,将1相加 .reduceByKey((x,y)=>(x._1+y._1, x._2+y._2)) // 将每个元组映射为一个元组,元组的第一个元素为x(1),第二个元素为x(2)除以1 .map(x=>(x._1, x._2._1/x._2._2))
将rdd转换成DataFrame
//用Row和schema信息组成Dataframe //通过定义schema,可以确保数据的结构一致性,便于后续的数据分析和处理。 val log_schema: StructType = StructType( Array( StructField("event_time", StringType), // 事件发生时间 StructField("url", StringType), // 请求的url StructField("method", StringType), // 请求方法 StructField("status", StringType), // 响应状态码 StructField("sip", StringType), // 客户端ip StructField("user_uip", StringType), // 用户ip StructField("action_prepend", StringType), // 操作前缀 StructField("action_client", StringType) // 客户端操作 ) ) //通过row,schema信息组成dataframe import spark.implicits._ //要使用dataframe和dataset需要该类 val logDF: DataFrame = spark.createDataFrame(rowRdd, log_schema)// 创建一个名为logDF的DataFrame,其数据来源于rowRdd和log_schema