综合RDD数据操作

360 阅读4分钟

综合RDD数据操作

  • 需求:

    统计客户中的5大家族

  • 数据源:customers.csv

    将该文件上传到HDFS: /input/customer

    image-20210201142215057

image-20210201142532676

我们需要统计第三列,姓氏出现频次最多的前五个。

一.基于IDEA构建spark项目

  • 新建maven项目
  • 把main中的java文件名改成scala
  • 添加scala编译工具 File->Project Structure->Libraries->+
image-20210201145407802

1 添加pom.xml依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>day05RDD</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <repositories>
        <repository>
            <id>ali-maven</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
                <checksumPolicy>fail</checksumPolicy>
            </snapshots>
        </repository>
        <repository>
            <id>central</id>
            <name>Maven Repository Switchboard</name>
            <layout>default</layout>
            <url>http://repo1.maven.org/maven2</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.12</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.12</artifactId>
            <version>3.0.0</version>
        </dependency>
        <!--streaming-->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming_2.12</artifactId>
            <version>3.0.0</version>
        </dependency>
        <!-- MySQL驱动 -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>
    </dependencies>

</project>

demo测试

package cn.com.chinahitech


import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.SparkSession


/**
 * @author SJ
 * @date 2021/2/1
 */
object Hello {
  def main(args: Array[String]): Unit = {
    //配置日志显示级别,进行日志的过滤
    Logger.getLogger("org").setLevel(Level.ERROR)
    // 1 创建spark
    val spark = SparkSession.builder().master("local[2]").appName("Hello").getOrCreate()//得到一个spark对象
    val sc=spark.sparkContext
    // 2 创建RDD数据集
    val rdd=sc.parallelize(1 to 9)
    // 3 进行转换,行动操作
    rdd.map(data => data*2).collect().foreach(println(_))
  }

}

image-20210201171718033

2.编程实现

统计五大家族,最终结果存到mysql里

数据集的端口

image-20210201172150668 image-20210201172228405

9870是web网页的访问地址 在hdfs-site.xml这个文件里配置的,默认端口是50070 ,9870是我们自己后改的

package cn.com.chinahitech

import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.SparkSession

/**
 * @author SJ
 * @date 2021/2/1
 */

object CustomerAnalysis {
  def main(args: Array[String]): Unit = {
    //配置日志显示级别,进行日志的过滤
    Logger.getLogger("org").setLevel(Level.ERROR)
    // 1 创建spark
    val spark = SparkSession.builder().master("local[2]").appName("Hello").getOrCreate()//得到一个spark对象
    val sc=spark.sparkContext

    //从hdfs里加载数据
    val customerRDD = sc.textFile("hdfs://192.168.0.104:9000/input/customer/customers.csv")

    //看一下是否成功
    customerRDD.take(3).foreach(println(_))
  }

}

image-20210201172901878

数据出来了,证明数据访问是没有问题的

现在得到的数据每一行是个字符串,字符串之间用逗号分隔,我们需要提取第三列,就是姓氏这一列,并且每一列都用双引号包起来了,需要把双引号去掉,再进行规约。

    //3对源数据集进行处理
    val tempRDD=customerRDD.map(line=>line.split(","))//每一行的string就变成了Array[String]
    
    //提取数组的第二个值
    tempRDD.map(arr=>arr(2))

合起来就是(算子喜欢垂直摆放)

    //3对源数据集进行处理
    val tempRDD=customerRDD
      .map(line=>line.split(","))//每一行的string就变成了Array[String]
      .map(arr=>arr(2))                 //Array[String]=>姓氏

    //看一下
    tempRDD.take(3).foreach(println(_))

image-20210201193126750

把双引号去掉

    //3对源数据集进行处理
    val tempRDD=customerRDD
      .map(line=>line.split(","))//每一行的string就变成了Array[String]
      .map(arr=>arr(2).replace("\"",""))    //Array[String]=>姓氏,并把双引号替换成空

image-20210201193353986

然后进行转换

    //3对源数据集进行处理
    val tempRDD=customerRDD
      .map(line=>line.split(","))//每一行的string就变成了Array[String]
      .map(arr=>arr(2).replace("\"",""))    //Array[String]=>姓氏,并把双引号替换成空
      .map(word=>(word,1))  
      .reduceByKey(_+_)       //规约

image-20210201193637437

  //4 进行数据位置交换、排序
    val resultRDD=tempRDD.map(data=>data.swap) ////(姓氏,数量) => (数量,姓氏)
      .sortByKey(false)//降序排列
      .map(data=>data.swap) // //(数量,姓氏)=>(姓氏,数量)
      

image-20210201194130739

CREATE TABLE `customer` (
  `name` varchar(255) NOT NULL,
  `count` int DEFAULT NULL,
  PRIMARY KEY (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

mysql建表用来存数据image-20210201201510839

出现问题:

image-20210201204201513

解决:case class People(name : String, age : Int) 的定义需要放在方法的作用域之外(即Java的成员变量位置)

blog.csdn.net/zhao8974261…

    //5 将RDD转换成DataFrame类型(包含数据+数据的格式)DataFrame=RDD+Schema
    //首先要导一个包
    import spark.implicits._
    //我们现在得到的RDD是这种格式(String,int),我们要把这种数据转换成带有格式的
    //这个时候就要借助样例类,样例类存在的意义就是实现数据格式的封装转换
    //[样例类定义在方法之外]

    val resultDF=resultRDD.map(data=>Customer(data._1,data._2)).toDF()
    //查看数据集格式
    resultDF.printSchema()
    //查看数据,默认显示20条
    resultDF.show()
    
image-20210201204443460

//再写一个成员方法实现把dataframe保存到mysql里的功能

  /**
   * 给一个数据集df,放到tablename表里面,执行完毕后输出msg消息
   * @param df:需要存储的DataFrame数据集
   * @param tableName:需要存储到的mysql的表名
   * @param msg:执行存储完毕后的输出消息
   */
  def saveToMySQL(df: DataFrame,tableName:String,msg:String):Unit={
    val url="jdbc:mysql://192.168.0.104:3306/customerdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false"
    val props = new java.util.Properties()
    props.put("user","root")
    props.put("password","ROOTroot_1")
    props.put("driver","com.mysql.cj.jdbc.Driver")

    //执行写入
    //模式有overwrite、append
    df.repartition(1).write.mode("overwrite").jdbc(url,tableName,props)
    //输出提示信息
    println(msg)

  }

在main函数里调用

    //6 执行存储到mysql
    saveToMySQL(resultDF,"customer","写入成功!")

image-20210201205818145

image-20210201205859378

二.打包上传jar到Linux

把上面的表删掉

image-20210201210129077

1.image-20210201212834330

清楚非必要依赖,留这一个

image-20210201213130510

3.编译项目, 生成字节码

image-20210201213205619

4.打作业包

image-20210201213305558 image-20210201213342917

三 上传并执行

image-20210201213456760
[hadoop@hadoop01 ~]$ cd /opt/data/
[hadoop@hadoop01 data]$ ll
总用量 37820
drwxrwxr-x 4 hadoop hadoop      173 1月  26 14:09 1_22
-rw-rw-r-- 1 hadoop hadoop 34723590 1月  22 22:22 bjmarket-0.0.1-SNAPSHOT.jar
-rw-rw-r-- 1 hadoop hadoop  1177355 1月  31 20:13 customers.csv
-rw-rw-r-- 1 hadoop hadoop  2358298 2月   1 21:34 day05RDD.jar
drwxrwxr-x 2 hadoop hadoop       87 1月  26 20:55 film_rating
drwxrwxr-x 2 hadoop hadoop      202 1月  26 13:26 hive_dir
-rw-rw-r-- 1 hadoop hadoop     8857 1月  22 13:39 market.sql
-rw------- 1 hadoop hadoop     7257 1月  22 22:56 nohup.out
-rw-rw-r-- 1 hadoop hadoop   439966 1月  21 21:01 world.sql
[hadoop@hadoop01 data]$ spark-submit day05RDD.jar   #执行
21/02/01 21:38:40 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
写入成功!
[hadoop@hadoop01 data]$ 

也可以像老师这样指定主类执行、指定cpu和内存

image-20210201214014711

对于这个报错

image-20210201214507186

是配置问题

image-20210201214739174

配置完重启电脑就行