慕课网日志数据分析

第一章 HDFS架构

1 Master(NameNode/NN)    带N个Slaves(DataNode/DN)
HDFS/YARN/HBase

1个文件会被拆成多个Block
blocksize:128M
130M===》2个Block:128M 和 2M

NN:
1)负责客户端请求的响应
2)负责元数据(文件名称、副本系数、Block存在的DN)的管理

DN:
1)存储用户的文件对应的数据块(Block)
2)要定期向NN发送心跳信息,汇报本身及其所有的block信息,健康状况

典型策略:
1个NameNode+N个DataNode
建议:NN和DN是部署在不同的节点(机器)上。

replication factor:副本系数、副本因子

All block in a file except the last block are the same size.


开发环境:
课程整套CDH相关软件下载地址:http://archive.cloudera.com/cdh5/cdh/5/
cdh-5.7.0
生产或者测试环境选择对应CDH版本时,一定采用尾号是一样的版本。


/software:存放的是安装的软件包
/app:存放的是所有软件的安装目录
/source:存放的是软件源码目录

linux命令
上传文件:scp /Users/colinqi/Downloads/hive-1.1.0-cdh5.7.0.tar.gz [email protected]:/software
配置域名:sudo vi /etc/hosts
解压文件到指定目录:tar zxvf /software/hadoop-2.6.0-cdh5.7.0.tar.gz -C /app


Hadoop环境搭建:
1)下载Hadoop
   http://archive.cloudera.com/cdh5/cdh/5/
   2.6.0-cdh5.7.0

   wget  http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.7.0.tar.gz

2) 安装jdk
   下载
   解压到app目录:tar zvxf jdk-7u51-linux-x64.tar.gz -C /app/
   验证安装是否成功:/app/jdk1.7.0_51/bin    执行./java -version
   建议把bin目录配置系统环境变量(~/.bash_profile):
           export JAVA_HOME=/app/jdk1.7.0_51
           export PATH=$JAVA_HOME/bin:$PATH
       重新生效:source .bash_profile


3)机器参数设置:

    修改机器名:vi /etc/sysconfig/network

    设置ip和hostname的映射关系:/etc/hosts

    在CentOS7中要修改主机名称(hostname)只能修改/etc/hostname文件内容来进行,修改/etc/sysconfig/network文件根本不起作用。

    ssh免密码登录:ssh-keygen -t rsa
                 cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys

4)hadoop安装配置

    解压:tar -zxvf hadoop.... -C /app

   Hadoop配置文件修改:/app/hadoop-2.6.0-cdh5.7.0/etc/hadoop
   vi hadoop-env.sh :export JAVA_HOME=/app/jdk1.7.0_51

   vi core-site.xml 

   
           fs.defaultFS
        hdfs://hadoop001:8020
   


   
           hadoop.tmp.dir
        /app/tmp
   


    vi hdfs-site.xml
   
           dfs.replication
        1
   

5)格式化HDFS
    注意:这一步操作,只是在第一次时执行。
    bin目录 ./hdfs namenode -format

6)启动HDFS
    sbin目录:./start-dfs.sh
    验证启动是否成功:
        jps:
        2970 NameNode
        3087 DataNode
        3243 SecondaryNameNode
        3346 Jps
        982 Bootstrap

        注意:datanode当时没有启动成功,/etc/hosts中127.0.0.1没有和localhost对应

        浏览器验证:http://172.20.10.2:50070/

7)停止HDFS
    sbin目录 ./stop-dfs.sh

    HDFS常用的shell命令:
    在bin目录下:hadoop fs----->查看帮助
    查看hadoop根文件夹:hadoop fs -ls /
    创建文件夹:hadoop fs -mkdir /test
    递归创建文件夹:hadoop fs -mkdir -p /a/b
    递归查看所有的目录:hadoop fs -ls -R /
    复制文件到指定位置:hadoop fs -put hdfs.cmd /test/
    查看文件内容:hadoop fs -cat /test/hdfs.cmd
    从HDFS下载文件到本地并重命名:hadoop fs -get /test/hdfs.cmd a_tmp
    删除:hadoop fs -rm /test/hdfs.cmd
    递归删除:hadoop fs -rmr /a


第二章 YARN架构 
1个RM(Resource Manager)+N个NM(Node Manager)
ResourceManager职责:
1)处理客户端请求(启动和杀死)
2)启动/监控ApplicanMaster(一个作业对应一个AM)
3)监控NM
4)系统的资源分配和调度

NodeManager职责:整个集群中有N个,负责单个节点的资源管理和使用以及task的运行情况
1)定期向RM汇报本结点的资源使用请求和各个Container的运行状态
2)接收并处理RM的container启停的各种命令
3)单个节点的资源管理和任务管理


ApplicationMaster:每个应用和作业对应一个,负责应用程序的管理
1)数据切分
2)为应用程序向RM申请资源(Container),并分配内部任务
3)与NM通信以及启停task,task是运行在container中的
4)task的监控和容错


Containner:对任务运行情况的描述:cpu、内存、环境变量


YARN执行流程:
1)用户向YARM提交作业
2)RM为该作业分配第一个container(AM)
3)RM会与对应的NM通信,要求NM在这个container上启动应用程序的AM
4)AM首先向RM注册,然后AM将为各个任务申请资源,并监控运行情况
5)AM采用轮询的方式通过RPC协议向RM申请和领取资源
6)AM申请到资源以后,便和相应的NM通信,要求NM启动任务
7)NM启动我们作业对应的task


YARN环境搭建
目录:/app/hadoop-2.6.0-cdh5.7.0/etc/hadoop
mapred-site.xml
    
        mapreduce.framework.name
        yarn
    

yarn-site.xml
    
        yarn.nodemanager.aux-services
        mapreduce_shuffle
    

启动yarn:sbin/start-yarn.sh

验证启动是否成功:
    jps:
        ResourceManager
        NodeManager

    浏览器:http://172.20.10.3:8088


停止yarn:
    sbin目录:./stop-yarn.sh


测试,提交yarn作业:
bin目录下执行:
    hadoop jar /app/hadoop-2.6.0-cdh5.7.0/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0-cdh5.7.0.jar wordcount /input/wc/hello.txt /output/wc


第三章 大数据数据仓库 Hive

1)通常用于离线数据处理(采用MapReduce)
2)底层支持多种不同的执行引擎
3)支持多种不同的压缩格式、存储格式以及自定义函数

Hive底层执行引擎有:MapReduce\Tez\Spark

    Hive on MapReduce
    Hive on Tez
    Hive on Spark

压缩:GZIP、LZO、Snappy、BZIP2..
存储:TextFile、SequenceFile、RCFile、ORC、Paraquet
UDF:自定义函数

为什么要使用Hive?
1)简单、容易上手(提供了类似SQL查询语言HQL)
2)为超大数据集设计的计算/存储扩展能力(MR计算、HDFS存储)
3)统一的元数据管理(可与Presto/Impala/SparkSQL等共享数据)===》非常重要

Hive环境搭建:
1)Hive下载:http://archive.cloudera.com/cdh5/cdh/5/hive-1.1.0-cdh5.7.0.tar.gz
    wget http://archive.cloudera.com/cdh5/cdh/5/hive-1.1.0-cdh5.7.0.tar.gz

2)解压
    tar -zxvf hive-1.1.0-cdh5.7.0.tar.gz -C /app/

3)配置

环境变量设置:vi ~/.bash_profile 

export HIVE_HOME=/app/hive-1.1.0-cdh5.7.0
export PATH=$HIVE_HOME/bin:$PATH

先进入/app/hive../cnf下复制:cp hive-env.sh.template hive-env.sh
vi hive-env.sh
HADOOP_HOME=/app/hadoop-2.6.0-cdh5.7.0


事先安装一个mysql,yum install xxx

进入mysql:/usr/bin/mysql -u root -p   密码:root

进入/app/hive../cnf新建文件hive-site.xml并写入:


   javax.jdo.option.ConnectionURL
   jdbc:mysql://localhost:3306/sparksql?createDatabaseIfNotExist=true


   javax.jdo.option.ConnectionDriverName
   com.mysql.jdbc.Driver


   javax.jdo.option.ConnectionUserName
   root


   javax.jdo.option.ConnectionPassword
   root

4)拷贝mysql驱动到lib: cp mysql-connector-java-5.1.47-bin.jar /app/hive-1.1.0-cdh5.7.0/lib

5)启动hive:bin目录 ./hive   (前提:hadoop:./start-all.sh)

创建表:
create table hive_wordcount(context string);
create table hive_wordcount1(context string);

加载数据到hive表:
load data local inpath '/data/hello.txt' into table hive_wordcount;

load data local inpath '/data/hello1.txt' into table hive_wordcount1;

select word,count(1) from hive_wordcount lateral view explode(split(context,' ')) wc as word group by word;


lateral view explode(split(context,' ')):是把每行记录按指定分隔符进行拆解

select word,count(1) from hive_wordcount1 lateral view explode(split(context,' ')) wc as word group by word;

hive ql提交执行以后会生成mr作业,并在yarn上运行。


第四章 Spark及生态圈:

产生背景、概述及特点、发展历史、Spark Survey、Spark对比Hadoop、Spark和Hadoop的协作性、Spark开发语言、Spark运行模式

官网:spark.apache.org

Spark特点:

Speed(基于内存(避免数据落地)、DAG执行引擎、基于线程模型对比进程)、Ease of Use(语言丰富、API多)、Generality、Runs Everywhere

MapReduce的局限性:
1)代码繁琐
2)只能够支持map和reduce方法;
3)执行效率低下
4)不适合迭代多次、交互式、流式处理

Spark生态圈:BDAS(Berkeley Data Analytics Stack)

协作性:

Hadoop优势:
unlimited scale、enterprise platform、wide range of applications(Files\Databases\Semi-structured)


框架多样化:
1)批处理(离线处理):MapReduce、Hive、Pig
2)流式处理(实时处理):storm、Jstorm
3)交互式计算:Impala

====》Spark

实战环境搭建:

Spark源码编译:目的是和指定版本的hadoop兼容使用。

前置要求:
1)Building Spark using Maven requires Maven 3.3.9 and Java 7+
2)export MAVEN_OPTS="-Xmx2g -XX:ReservedCodeCacheSize=512m"


    UTF-8
    UTF-8
    1.7
    3.3.9
    spark
    1.7.16
    1.2.17
    2.2.0
    2.5.0
    ${hadoop.version}
  

spark两者编译方式: 

方式一:mvn编译命令:

    ./build/mvn -Pyarn -Phadoop-2.6 -Phive -Phive-thriftserver -Dhadoop.version=2.6.0-cdh5.7.0 -DskipTests clean package


方式二:#推荐使用的编译(可形成压缩包):

./dev/make-distribution.sh --name 2.6.0-cdh5.7.0 --tgz -Pyarn -Phadoop-2.6 -Phive -Phive-thriftserver -Dhadoop.version=2.6.0-cdh5.7.0

编译完成后:
    spark-$VERSION-bin-$NAME.tgz

    spark-2.1.0-bin-2.6.0-cdh5.7.0.tgz


spark编译注意事项:

坑一:

    [ERROR] Failed to execute goal on project spark-launcher_2.11: Could not resolve dependencies for project org.apache.spark:spark-launcher_2.11:jar:2.1.0: Failure to find org.apache.hadoop:hadoop-client:jar:2.6.0-cdh5.7.0 in http://maven.aliyun.com/nexus/content/groups/public was cached in the local repository, resolution will not be reattempted until the update interval of nexus-aliyun has elapsed or updates are forced -> [Help 1]

    需要pom.xml添加:
    
    
    cloudera
    https://repository.cloudera.com/artifactory/cloudera-repos/
    

坑二:cd dev/===>vi make-distribution.sh(应该是这个位置吧??)

    export MAVEN_OPTS=“-Xmx2g -XX:ReservedCodeCacheSize=512m -XX:MaxPermSize=512M”

    注意点:如果提示内存不够,可能vm需要调整内存至少2-4G

坑三:

    如果编译的是scala版本是2.10
    ./dev/change-scala-version.sh 2.10

坑四:
    
    was cached in the local repository.....

    两种方案解决:

    1)    去仓库把xxx.lastUpdated文件全部删除,重新执行maven命令
    2)编译命令后加 -U

坑五:
    
    Remote host closed connection during handshake和SSL peer shut down incorrectly报错的解决方法====》Jdk版本的问题
 
 


Spark环境搭建

    将编译好的spark压缩包解压到某个位置==〉配置spark环境变量~./bash_profile

    第一种:Local模式搭建:bin目录下执行==》spark-shell --master local[2]

    第二种:standalone模式搭建:

     cp spark-env.sh.template spark-env.sh 

     vi spark-env.sh

     添加:
             SPARK_MASTER_HOST=hadoop001
            SPARK_WORKER_CORES=2
            SPARK_WORKER_MEMORY=2g
            SPARK_WORKER_INSTANCES=2

        集群的搭建:

            conf目录下:slaves文件配置:

            hadoop1:master
            hadoop2:worker
            hadoop3:worker
            .......
            hadoop10:worker

            slaves:
            hadoop2:ip...
            hadoop3
            ....

            =====>start-all.sh   会在hadoop1机器上启动master进程,在slaves文件配置的所有hostname的机器上启动worker进程

    bin目录下:spark-shell --master spark://hadoop001:7077


Spark简单使用

    spark WordCount统计:

        val file=spark.sparkContext.textFile("file:///data/hello.txt") 

        val wordCounts=file.flatMap(line=>line.split(",")).map((word=>(word,1))).reduceByKey(_+_)

        wordCounts.collect


第五章 Spark SQL

    Spark SQL前世今生

        为什么需要SQL?===》1)事实上的标准。 2)易学易用。 3)受众面广。 


        Hive:类似sql的Hive QL语言,sql==》mapreduce
            缺点:mapreduce 
            改进:hive on tez、hive on spark....

        Spark:hive on spark===>shark(初期)

            shark推出:欢迎。基于spark、基于内存的列式存储、与hive能兼容

            缺点:hive ql的解析、逻辑执行计划生成、执行计划的优化是依赖于hive的

                仅仅只是把物理执行计划从mr作业替换成spark作业。

                依赖过大导致添加新功能不方便;mr基于进程级别处理,spark基于线程==》线程安全问题

        Shark终止以后,产生两个分支:

            1)Hive on Spark(Help existing Hive users migrate to spark)

                hive社区,源码在Hive中

            2)Spark SQL(A new SQL engine designed from ground-up for Spark)

                Spark社区,源码在Spark中

                    优点:支持多种数据源,多种优化技术,扩展性好很多。


    SQL on Hadoop常用框架

        1)Hive

            sql==》mapreduce

            metastore:元数据

            sql:database、table、view

        2)impala

            cloudera:cdh(建议大家在生产上使用的hadoop系列版本)

            sql:自己的守护进程执行的,非mr

            metastore

        3)presto

            facebook   京东   sql

        4)drill

                sql  支持访问:hdfs、rdbms、json、hbase、mangodb、s3、hive

        5)Spark SQL

                sql  支持访问:hdfs、rdbms、json、hbase、mangodb、s3、hive

                基于dataframe/dataset api 编程

                metastore


    Spark SQL概述

            1)Part of the core distributio since Spark1.0(April 2014)

            2)Runs SQL/Hive Ql queries including UDFs UDAFs and SerDes

            3)Connect existing BI tools to Spark througth JDBC

            4)Binding in Python,Scala,Java,R

        Spark SQL is Apache Spark's module for working with structured data.

        有见到SQL字样吗?
        Spark SQL它不仅仅有访问或者操作SQL的功能,还提供了其他的非常丰富的操作“外部数据源、优化

        Spark SQL概述小结:

            1)Spark SQL的应用不局限于SQL

            2)访问hive、json、parquet等文件的数据

            3)SQL只是Spark SQL的一个功能
            ====》Spark SQL这个名字起的并不恰当。

            4)Spark SQL提供了SQL的api、DataFrame和Dataset的API


    Spark SQL愿景

        Write less code

        Read less data

        Let the optimizer do the the hard work

    Spark SQL架构

        见架构图

第六章 从Hive平滑过渡到Spark SQl

    SQLContext/HiveContext/SparkSession的使用==>前两个已经过时

    spark-shell/spark-sql的使用

    thriftserver/beeline的使用

    jdbc方式编程访问


 1、SQLContext的使用

     创建maven项目===》构建ImoocSparkSQLProject项目

    package com.imooc.spark
    import org.apache.spark.{SparkConf, SparkContext}
    import org.apache.spark.sql.SQLContext

    object SQLContextApp {
      def main(args: Array[String]): Unit = {

        val path=args(0);

        //1)创建相应的context
        val sparkConf =new SparkConf()

        //在测试和生产环境中,AppName和Master建议在脚本中指定
        sparkConf.setAppName("SQLContextApp").setMaster("local[2]")

        val sc=new SparkContext(sparkConf)
        val sQLContext=new SQLContext(sc)

        //2)相关的处理
        val people=sQLContext.read.format("json").load(path)
        people.printSchema()
        people.show()
        
        //3)关闭资源
        sc.stop()
      }
    }

    注意:path参数的传入,点击项目Edit Configurations

    打包执行:
        
        进入项目的目录下,执行:mvn clean package -DskipTests

        打好的jar包在target文件夹下,上传到服务器上:sudo scp  1.jar [email protected]:~/lib

    执行以下代码执行:

      spark-submit \
      --class com.imooc.spark.SQLContextApp \
      --master local[2] \
      /root/lib/sql-1.0.jar\
      /app/spark-2.1.0-bin-2.6.0-cdh5.7.0/examples/src/main/resources/people.json


     将上述代码放在脚本文件中执行:

          vi sqlcontext.sh

          注意赋给用户该文件执行的权限:chmod u+x sqlcontext.sh

          执行./sqlcontext.sh

  
HiveContext:

     spark-submit \
      --class com.imooc.spark.HiveContextApp \
      --master local[2]\
      --jars /app/mysql-connector-java-5.1.30-bin.jar\
      /root/lib/sql-1.0.jar

      区别:需要jdbc驱动,找到元数据,不需要传入参数。

SparkSession:
    
        object SparkSessionApp {

          def main(args: Array[String]): Unit = {

        val spark=SparkSession.builder().appName("SparkSessionApp").master("local[2]").getOrCreate()

        spark.read.json("file:///imooc/people.json").show()

        spark.stop()
          }
        }

spark-shell/spark-sql的使用:

        前提条件:1)在spark/conf中添加hive/conf中的hive-setting.xml文件,以便连接数据库;
                    
                 2)需要驱动mysql-connector-java-5.1.30-bin.jar

        =====》对比spark查询表和hive查询表速度上的区别。


        /spark/bin目录下执行:

        spark-sql --master local[2] --jars /app/mysql-connector-java-5.1.30-bin.jar


        create table t(key string,value string);

        explain extended select a.key*(2+3),b.value from t a join t b on a.key=b.key and key>3; 


        查看spark(架构)执行计划:
        explain extended select a.id*(2+3),b.name from student a join student b on a.id=b.id and a.id>0; 

        == Parsed Logical Plan ==
        'Project [unresolvedalias(('a.id * (2 + 3)), None), 'b.name]
        +- 'Join Inner, (('a.id = 'b.id) && ('a.id > 0))
           :- 'UnresolvedRelation `student`, a
           +- 'UnresolvedRelation `student`, b

        == Analyzed Logical Plan ==
        (id * (2 + 3)): int, name: string
        Project [(id#2 * (2 + 3)) AS (id * (2 + 3))#10, name#7]
        +- Join Inner, ((id#2 = id#6) && (id#2 > 0))
           :- SubqueryAlias a
           :  +- MetastoreRelation default, student
           +- SubqueryAlias b
              +- MetastoreRelation default, student

        == Optimized Logical Plan ==
        Project [(id#2 * 5) AS (id * (2 + 3))#10, name#7]
        +- Join Inner, (id#2 = id#6)
           :- Project [id#2]
           :  +- Filter (isnotnull(id#2) && (id#2 > 0))
           :     +- MetastoreRelation default, student
           +- Project [id#6, name#7]
              +- Filter ((id#6 > 0) && isnotnull(id#6))
                 +- MetastoreRelation default, student

        == Physical Plan ==
        *Project [(id#2 * 5) AS (id * (2 + 3))#10, name#7]
        +- *BroadcastHashJoin [id#2], [id#6], Inner, BuildRight
           :- *Filter (isnotnull(id#2) && (id#2 > 0))
           :  +- HiveTableScan [id#2], MetastoreRelation default, student
           +- BroadcastExchange HashedRelationBroadcastMode(List(cast(input[0, int, false] as bigint)))
              +- *Filter ((id#6 > 0) && isnotnull(id#6))
                 +- HiveTableScan [id#6, name#7], MetastoreRelation default, student

thriftserver/beeline的使用

        =====》实际开发中最常用的方式

1)启动thriftserver:默认端口是10000,可以修改

    spark/sbin目录下:

        ./start-thriftserver.sh --master local[2] --jars /app/mysql-connector-java-5.1.30-bin.jar

    使用:jps -m 查看是否启动成功?


2)客户端beeline连接:

    beeline -u jdbc:hive2://localhost:10000 -n hadoop

    修改thriftserver启动占用的默认端口号:

    ./start-thrifserver.sh \

    --master local[2] \

    --jars /app/mysql-connector....

    --hiveconf hive.server2.thrift.port=1400

    beeline -u jdbc:hive2://localhost:14000 -n hadoop

    thriftserver和普通的spark-shell/spark-sql有什么不同?

    1)spark-shell、spark-sql都是一个spark application;

    2)thriftserver,不管你启动多少个客户端(beeline/code),永远都是一个spark application

        解决了一个数据共享的问题,多个客户端可以共享数据;


    客户端jdbc方式连接:

        注意:一定先要启动thriftserver

        import java.sql.DriverManager

        object SparkSQLThriftserverApp {
          def main(args: Array[String]): Unit = {

            Class.forName("org.apache.hive.jdbc.HiveDriver")

             val con=DriverManager.getConnection("jdbc:hive2://172.20.10.3:10000","","")
             val pstmt=con.prepareStatement("select * from student")
             val rs=pstmt.executeQuery()
            while (rs.next()){
              print("id:"+rs.getInt("id")+",name:"+rs.getString("name"))
            }
            rs.close()
            con.close()
            pstmt.close()
          }
        }


第七章 DataFrame和Dataset

    DataFrame产生背景

        Spark RDD API vs MapReduce API

        R/Pandas(最早产生DataFrame,可以无缝连接)

    DataFram概述

        DataFrame它不是spark sql提出的,而是最早在R、Pandas语言就已经有了的。

        A Dataset is a distributed collection of data:分布式的数据集

        A DataFrame is a Dataset organized into named columns

        以列(列名、列的类型、列值)的形式构成的分布式数据集,按照列赋予不同的名称。

    DataFrame对比RDD

        图:

        RDD:
            java/scala====》Jvm  python===〉python 运行环境

        DataFrame:
            java/scala/python===》Logic plan

        ====〉执行性能不同。

    DataFrame基本API常用操作

        object DataFrameApp {
          /**
            DataFrame API操作
            */
          def main(args: Array[String]): Unit = {

            val spark=SparkSession.builder().appName("DataFrameApp").master("local[2]").getOrCreate()
            val peopleDF=spark.read.format("json").load("file:///imooc/people.json")

            //输出DataFrame对应的schema信息
            peopleDF.printSchema()

            //输出数据集前20条记录
            peopleDF.show()

            //查询某列数据:select name from table
            peopleDF.select("name").show()

            //查询某几列数据,并对列进行计算:select name,(age+10) as age2 from table
            peopleDF.select((peopleDF.col("age")+10)as("age2"),peopleDF.col("name")).show()

            //根据某一列进行分组,再进行聚合操作
            peopleDF.groupBy("age").count().show()

            //根据年龄进行过滤操作
            peopleDF.filter(peopleDF.col("age")>19).show()

            spark.stop() 
          }
        }


    DataFrame API实战

        package com.imooc.spark

        import org.apache.spark.sql.SparkSession

        object DataFrameCase {
          /**
            *
            DataFrame API实战
            */
          def main(args: Array[String]): Unit = {

           val spark=SparkSession.builder().appName("DataFrameCase").master("local[2]").getOrCreate()

            val rdd=spark.sparkContext.textFile("file:///imooc/student.txt")

          import spark.implicits._
          val studentDF=rdd.map(_.split("\\|")).map(line=>Student(line(0),line(1),line(2),line(3))).toDF()
            val studentDF2=rdd.map(_.split("\\|")).map(line=>Student(line(0),line(1),line(2),line(3))).toDF()

        //    studentDF.show(20,false)
        //    studentDF.show(9)
        //
        //    studentDF.take(5)
        //    studentDF.first()
        //    studentDF.head(4)
        //
        //    studentDF.select("email","name").show()
        //    studentDF.sort(studentDF.col("id").desc,studentDF.col("name").asc).show()

            studentDF.filter("substring(name,0,1)='A'").show()

        //    studentDF.select(studentDF.col("name").as("student_name")).show()
        //
        //    studentDF.join(studentDF2,studentDF.col("id")===studentDF2.col("id")).show()
            spark.stop()

          }
          case class Student(id:String,name:String,phone:String,email:String)
        }


    DataFrame与RDD两种互操作

        package com.imooc.spark
        import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
        import org.apache.spark.sql.{Row, SparkSession, types}
        object DataFramRDD {
          /**
            DataFram和RDD互操作
            */
          def main(args: Array[String]): Unit = {

            val spark=SparkSession.builder().appName("DataFramRDD").master("local[2]").getOrCreate()
        //    inferReflection(spark)

            program(spark)

            spark.close()
          }
          //第二种互操作
           def program(spark: SparkSession) = {
             val rdd = spark.sparkContext.textFile("file:///imooc/infos.txt")
             val Infordd=rdd.map(_.split(",")).map(line => Row(line(0).toInt, line(1), line(2).toInt))
             //结构
             val structType=StructType(Array(StructField("id",IntegerType),StructField("name",StringType),StructField("age",IntegerType)))
              //将数据和结构结合
             val df=spark.createDataFrame(Infordd,structType)
             df.printSchema()
             df.show()
           }
          //第一种互操作
           def inferReflection(spark: SparkSession) = {
            val rdd = spark.sparkContext.textFile("file:///imooc/infos.txt")

            //RDD==>DataFrame

            // 注意需要导入隐式转换
            import spark.implicits._
            val infosDF = rdd.map(_.split(",")).map(line => Info(line(0).toInt, line(1), line(2).toInt)).toDF()

            infosDF.show()

            //将DataFrame转化成sql可以处理的表
            infosDF.createOrReplaceTempView("info")

            spark.sql("select * from info where age>30").show()
          }

          case class Info(id:Int, name:String, age:Int)
        }

        DataFrame和RDD两种互操作的区别:
        1)反射:case class 前提:事先需要知道你的字段、字段类型

        2)编程:Row。  如果第一宗情况不能满足你的要求

        3)优先选择第一种互操作


    Dataset概述

        object DatasetApp {
          def main(args: Array[String]): Unit = {
            val spark=SparkSession.builder().appName("DatasetApp").master("local[2]").getOrCreate()

            //如何解析csv文件?
            import spark.implicits._
            val path="file:///imooc/person.csv"
            val df=spark.read.option("header","true").option("inferSchema","true").csv(path)
            df.show()
            val ds=df.as[Person]
        //    ds.show()
            ds.map(line=>line.name).show()
          }
          case class Person(name:String,sex:String,age:String)
        }

第八章 External Data Source API

    产生背景

        Every Spark application starts with loading data and ends with saving data.

        用户:方便快速从不同的数据源(json、parquet、rdbms),经过混合处理(json join parquet),

            再将处理结果以特定的格式(json/parquet)写回到指定的系统(HDFS、S3)上去。

        ==》Spark SQL 1.2===〉外部数据源API

    Loading and saving data is not easy:

        Parse raw data:text/json/parquet

        Convert data forma transformation

        Datasets stored in various Formats/System.

    目标

        外部数据源的目的

            1)开发人员:是否需要把代码合并到spark中??不需要。
                weibo
                --jars

            2)用户
                读:spark.read.format(format)
                    format
                        build-in(内置):json parquet jdbc csv(2+)
                        packages:外部的。并不是spark内置。https://spark-package.org

                写:people.write.format("parguet").save("path")

    操作Parquet文件数据

        spark-shell处理:

            object ParquetApp {
          /**
            parquet外部数据操作
            */
          def main(args: Array[String]): Unit = {
            /**
              * 标准写法:spark.read.format("parquet").load
              *
              * 简洁写法:spark.read.load
              *
              * 默认format就是parquet
              *
              */
            val spark=SparkSession.builder().appName("ParquetApp").master("local[2]").getOrCreate()
            val df=spark.read.format("parquet").load("file:///app/spark-2.1.0-bin-2.6.0-cdh5.7.0/examples/src/main/resources/users.parquet")
            df.printSchema()
            df.show()

            df.select("name","favorite_color").show()
            
            df.select("name","favorite_color").write.format("json").save("file:///tmp/jsonout")

          }
        }

        spark-sql处理:

            create temporary view parquetTable using org.apache.spark.sql.parquet options(path "/app/spark-2.1.0-bin-2.6.0-cdh5.7.0/examples/src/main/resources/users.parquet");

            select * from parquetTable;


    操作Hive表数据

        spark.sql("select deptno,count(1) as mount from emp where group by deptno").filter("deptno is not null").write.saveAsTable("hive_table_1")

        如果不加as mount:
        org.apache.spark.sql.AnalysisException:Attribution name "count(1)" contains invalid characters among...

        spark.sqlContext.setConf("spark.sql.shuffle.partitions",10)
        在生产环境中一定要注意设置spark.sql.shuffle.partitions,默认是200

    操作Mysql表数据

        第一种方式:

        val jdbcDF = spark.read.format("jdbc").option("url", "jdbc:mysql://localhost:3306/")
        .option("dbtable", "mysql.tables_priv").option("driver", "com.mysql.jdbc.Driver")
        .option("user", "root").option("password", "root").load()

        第二种方式:

        import java.util.Properties
        val connectionProperties = new Properties()
            connectionProperties.put("driver", "com.mysql.jdbc.Driver")
            connectionProperties.put("user", "root")
            connectionProperties.put("password", "root")

        val jdbcDF2 = spark.read.jdbc("jdbc:mysql://localhost:3306/", "mysql.tables_priv", connectionProperties)
        
        


第九章:慕课网日志分析实战项目

    1)用户行为日志概述

        用户行为日志:用户每次访问网站时所有的行为数据(访问、浏览、搜索、点击...)

        又称:用户行为轨迹、流量日志

        用户行为日志生成渠道:Nginx和Ajax

        用户行为日志内容:

            一次访问记录:
            访问者IP地址、访问者账号、访问时间和区域

            访问者所有的客户端(手机/电脑,chrome、firefox..)、访问模块id、跳转/连接地址...

    2)离线数据处理架构

        1、数据采集
            Flume:web日志写入到HDFS

        2、数据清洗
            脏数据
            Spark、Hive|MapReduce或者其他一些分布式计算框架
            清洗后的数据可以存放到HDFS(Hive/Spark SQL)

        3、数据处理
            按照我们的需求进行相应业务的统计和分析
            Spark、Hive、MapReduce或者其他一些分布式框架

        4、处理结果入库
            结果可以存法在RDBMS、NoSQL

        5、数据的可视化
            通过图形化展示的方式展示出来:饼图、柱状图、地图、折线图
            ECharts、HUE、Zeppelin

        一般的日志处理方式,我们是需要进行分区的,
        按照日志中的访问时间进行相应的分区,比如:d,h,m5(每5分钟一个分区)


    ==》架构图

    3)项目需求

        需求一:统计imooc主战最受欢迎的课程/手记的Top N访问次数

        需求二:按地市统计imooc主站最受欢迎的Top N课程
                根据IP地址提取出城市信息
                窗口函数在Spark SQL中使用

        需求三:按流量来统计imooc主站最受欢迎的Top N课程

    4)功能实现

        输入:访问时间、访问URL、访问过程耗费流量、访问IP地址

        输出:URL、cmsType(video/article)、cmsId(编号)、流量、ip、城市信息、访问时间、分区(天)

        坑:
        怎么解决java.lang.Integer is not a valid external type for schema of string??

            case:Exception => Row(0)的问题 换成Row("","",0L,0L,"","","","")

        使用github上已有的开源项目
        1)git clone https://github.com/wzhe06/ipdatabase.git

        2)编译已经下载的项目:mvn clean package -DskipTests

        3)安装jar包到自己的maven仓库

            mvn install:install-file -Dfile=/imooc/BigDataImooc/ipdatabase/target/ipdatabase-1.0-SNAPSHOT.jar -DgroupId=com.ggstar -DartifactId=ipdatabase -Dversion=1.0 -Dpackaging=jar    

            坑:maven报错 the goal you specified requires a project to execute but there is no POM in this direct...

            这个错误的原因是当前目录下没有pom.xml 文件,Maven执行必须要pom.xml文件,我就跑到pom.xml文件目录下 mvn install.问题解决

        4)idea项目pom.xml添加依赖
            
            com.ggstar
            ipdatabase
            1.0
            

            
                org.apache.poi
                poi-ooxml
                3.14
            

            
                org.apache.poi
                poi
                3.14
            

        5)清洗后数据保存

            df.coalesce(1).write.format("parquet").mode(SaveMode.Overwrite).partitionBy("day").save("/imooc/clean/")

            按字段”day“分区==》分区后每个区执行文件个数coalesce()==>mode模式可以选择覆盖

        6)写入数据库Mysql

            create table day_video_access_topn_stat(
            day varchar(8) not null,
            cms_id bigint(10) not null,
            times bigint(10) not null,
            primary key (day,cms_id)
            );

            create table day_video_city_access_topn_stat(
            day varchar(8) not null,
            cms_id bigint(10) not null,
            city varchar(20) not null,
            times bigint(10) not null,
            times_rank int not null
            );

            //加入主键出问题。

        数据可视化:一幅图片最伟大的价值莫过于它能够使的我们实际看到的比我们期望看到的内容更加丰富

        常用的数据可视化框架:echarts、highcharts、D3.js。

            不需要开发的框架:HUE、Zeppelin

        本次课程使用echarts和Zeppelin作数据可视化。


    5)Spark on YARN

        spark支持可插拔的集群管理模式
        对于yarn而言,spark applicaion仅仅是一个客户端而已

            在spark中,支持4种运行模式:

            1、Local:开发时使用

            2、Standalone:
                是spark自带的,缺点:如果一个集群是standalone模式的话,那么就需要在多台机器上同时部署spark环境。

            3、Yarn:建议大家在生产上使用该模式,统一使用Yarn进行整个集群作业(MR、spark)的资源调度

            4、Mesos:国内基本不用

            不管使用什么模式,spark应用程序的代码都是一样的,只需要在提交的时候通过--master参数来指定我们的运行模式即可。

            spark on yarn之client模式:

                Driver运行在Client端(提交spark作业的机器)
                client会和请求的Container进行通信来完成作业的调度和执行,Client是不能退出的
                日志信息会在控制台输出:便于我们的测试

            spark on yarn之cluster模式:

                Driver运行在ApplicatinMaster中
                Client只要提交完作业之后就可以关闭,因为作业已经在Yarn上运行了
                日志在终端看不到的,因为日志在Driver上,只能通过yarn logs -applicationId application_id或者网页上查看


            官网例子:

                client模式:

                //注意格式要求

                ./bin/spark-submit --class org.apache.spark.examples.SparkPi  --master yarn --executor-memory 1G  --num-executors 1  /app/spark-2.1.0-bin-2.6.0-cdh5.7.0/examples/jars/spark-examples_2.11-2.1.0.jar  4

                 此处的yarn就是client模式,如果是cluster模式的话,就写 yarn-cluster.cd

                 报错:

                 Exception in thread "main" java.lang.Exception: When running with master 'yarn' either HADOOP_CONF_DIR or YARN_CONF_DIR must be set in the environment.

                 如果想运行在YARN之上,那么就必须要设置HADOOP_CONF_DIR或者YARN_CONF_DIR

                 1、export HADOOP_CONF_DIR=/app/hadoop-2.6.0-cdh5.7.0/etc/hadoop
                 2、修改$SPARK_HOME/conf/spark-env.sh


                cluster模式:

                ./bin/spark-submit \
                  --class org.apache.spark.examples.SparkPi \
                  --master yarn-cluster \
                  --executor-memory 1G \
                  --num-executors 1 \
                  /app/spark-2.1.0-bin-2.6.0-cdh5.7.0/examples/jars/spark-examples_2.11-2.1.0.jar \
                  4

                  ./bin/spark-submit --class org.apache.spark.examples.SparkPi  --master yarn-cluster --executor-memory 1G  --num-executors 1  /app/spark-2.1.0-bin-2.6.0-cdh5.7.0/examples/jars/spark-examples_2.11-2.1.0.jar  4

                  命令查看日志:==》还是有报错的
                  yarn logs -applicationId application_1547961770643_0002


        打包时需要注意,pom.xml中需要添加如下:

        
                maven-assembly-plugin
               
                   
                       
                           
                       

                   

                   
                        jar-with-dependencies
                   

               

           

        打包命令:mvn assembly:assembly


                export HADOOP_CONF_DIR=/app/hadoop-2.6.0-cdh5.7.0/etc/hadoop

                ./bin/spark-submit \
                  --class com.imooc.spark.log.SparkStatCleanJobYARN \
                  --name SparkStatCleanJobYARN\
                  --master yarn\
                  --executor-memory 1G \
                  --num-executors 1 \
                  --files ~/lib/ipDatabase.csv,~/lib/ipRegion.xlsx\
                  /root/lib/sql-1.0-jar-with-dependencies.jar \
                  hdfs://hadoop001:8020/imooc/input/* hdfs://hadoop001:8020/imooc/clean
                  


    6)性能调优

        集群优化:1、存储格式的选择:www.infoq.com/cn.article/bigdata-store-choose/

                 2、压缩格式的选择:www.ibm.com/developerworks/cn/opensource/os-cn-hadoop-compression-analysis/

                     压缩速度和压缩文件的可分割性

                 默认格式是snappy,可选择合适压缩格式:

                 SparkSession.builder().config("spark.sql.parquet.compression.codec","gzip").getOrCreate()

        代码优化:1、选择高性能的算子

                     将数据写入数据库的统计操作:cityTopStatDF.foreachPartition(partOfRecord=>{}、list(每个分区)、 pstmt.addBatch()等

                 2、复用已有的代码/数据


        参数优化:1、并行度:spark.sql.shuffle.partitions,默认为200,根据实际情况调整


                ./bin/spark-submit \
                  --class com.imooc.spark.log.SparkStatCleanJobYARN \
                  --name SparkStatCleanJobYARN\
                  --master yarn\
                  --executor-memory 1G \
                  --num-executors 1 \
                  --conf spark.sql.shuffle.partitions=100\
                  --files ~/lib/ipDatabase.csv,~/lib/ipRegion.xlsx\
                  /root/lib/sql-1.0-jar-with-dependencies.jar \
                  hdfs://hadoop001:8020/imooc/input/* hdfs://hadoop001:8020/imooc/clean


                 2、分区字段类型推测:spark.sql.sources.partitionColumnTypeInference.enabled,默认是true

                    一般将其设置为false:
                    var spark=SparkSession.builder().config("spark.sql.sources.partitionColumnTypeInference.enabled","false").getOrCreate()
    
 

 

 

 

你可能感兴趣的:(大数据,Hadoop,Spark,大数据)