1.搭建Hadoop集群
1.准备3台虚拟机
先建一个虚拟机,克隆出3台虚拟机
2.搭建Hadoop集群
关闭防火墙 systemctl stop firewalld
systemctl disable firewalld(永久关闭)
关闭selinux vi /etc/sysconfig/selinux
SELINUX = enforcing 改为disabled
更改主机名 vi /etc/hostname
删除内容 改为node01.kaikeba.com
主机名与IP地址的映射 vi /etc/hosts
加在最后 IP地址 主机名 node01
添加普通用户 统一添加用户hadoop,并给sudo权限
useradd hadoop
passwd hadoop
visudo #添加sudo权限
在root ALL=(ALL) ALL 下面一行增加
hadoop ALL=(ALL) ALL
定义统一目录 mkdir -p /kkb/install #软件压缩包存放目录
mkdir -p /kkb/install #软件解压后存放目录
chown -R hadoop:hadoop /kkb #将文件夹权限更改为hadoop用户
切换到hadoop 用户下,重启三个虚拟机,让主机名生效
hadoop用户免密码登录
①生成公钥与私钥
ssh-keygen -t rsa (按三次enter键)
②拷贝公钥到node01服务器
ssh-copy-id node01
③node01服务器将公钥拷贝给node02与node03
cd /home/hadoop/.ssh
scp authorized_keys node02:/home/hadoop/.ssh
scp authorized_keys node03:/home/hadoop/.ssh
关机重启 sudo reboot -h now
安装jdk,配置文件
3.搭建zookeeper集群
知识点:
ssh
ssh:网络协议,用于计算机之间的加密登录
格式: ssh -p 22 user@host
-p:指定端口号
user:登录的用户名
host:登录的主机
2.HDFS
介绍
是一个分布式文件系统,主要运用HDFS将底层数量众多且分布在不同位置通过网络连接的各种存储设备组织在一起,通过统一的接口向上层应用提供对象级文件访问服务能力。
基本概念
1.数据块(Block)
HDFS的文件被分成块进行存储,块是文件存储处理的逻辑单位。可以支持大规模文件存储,适合数据的备份。每一个block会在多个namenode上存储多份副本,默认为3份。
2.名称节点(NameNode)
存储文件系统的元数据,包括每个文件的位置及所在DateNode内的所有数据块的内存映射。把元数据保存在内存里。
3.数据节点(DataNode)
存储文件内容,将内容保存在磁盘里。
启动Hadoop
一步启动:start-all.sh (需设置免密登录)
多步启动:start-dfs.sh
start-yarn.sh
mapred --daemon start historyserver
可用命令jps查看是否启动,若启动会显示jps,ResourceManager,DataNode,NodeManager,SecondaryNameNode,NameNode
关闭Hadoop只需要将start改为stop即可
HDFS命令
格式:hadoop fs -<命令> <目标>
hdfs dfs -<命令> <目标>
1.查看Hadoop内所包含的所有命令及用法
hadoop fs -help
hdfs dfs -help
2.查看hdfs系统版本
hdfs version
3.查看hdfs系统状态(比如有哪些datanode,每个datanode的情况)
hdfs dfsdmin -report
4.目录操作
查看目录及文件 hadoop fs -ls /
创建及删除目录 hadoop fs -mkdir /test hadoop fs -mkdir -p /test/test1/test2(-p为批量创建)
hadoop fs -rm -r /test
hadoop里设置有回收站功能,删除的文件会保留在回收站中,hadoop fs -expunge 可清空回收站
mv,cp用法同Linux中的一样,都可以起到移动文件、重命名、复制文件的作用
5.文件操作
1.上传及下载文件 hadoop fs -put linux本地磁盘文件路径 hadoop路径
hadoop fs -get 被下载的文件
2.查看文件内容 hadoop fs -cat 文件名
hadoop fs -text 文件名(text方法可将源文件输出为文本格式,允许格式为zip和TextRecordInputStream)
hadoop fs -tail 文件名(tail方法是将文件尾部1k字节的内容输出)
3.查找文件 hadoop fs -find / -name part-r-00000 (在HDFS根目录中查找part-r-00000文件)
4.查看文件大小 hadoop fs -du -s 文件名(-s可不加,直接写目录表示查看该目录下所有文件大小)
5.stat方法可以返回指定路径的统计信息,有多个参数可选,当使用-stat选项但不指定format时候,只打印文件创建日期,相当于%y
hadoop fs -stat 目录文件名
format形式:%b:打印文件大小(目录为0) %n:打印文件名 %o:打印block size %r: 打印备份数 %y:打印UTC日期 yyyy-MM-dd HH:mm:ss
6.安全模式
进入安全模式 hadoop dfsadmin -safemode enter
离开安全模式 hadoop dfsadmin -safemode leave
Hadoop与API
1.上传本地文件
通过“FileSystem.copyFromLocalFile (Path src,Path dst)"将本地文件上传至HDFS指定位置,src和dst为文件的完整路径。例
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class CopyFile {
public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
FileSystem hdfs=FileSystem.get(conf);
//本地文件
Path src =new Path("C:/");
//HDFS地址
Path dst =new Path("/");
hdfs.copyFromLocalFile(src, dst);
System.out.println("Upload to"+conf.get("fs.default.name"));
FileStatus files[]=hdfs.listStatus(dst);
for(FileStatus file:files){
System.out.println(file.getPath());
}
}
}
2.创建HDFS文件
通过”FileSystem.create (Path f)"创建文件,f为文件的完整路径。例:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class CreateFile {
public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
FileSystem hdfs=FileSystem.get(conf);
byte[] buff="hello hadoop world!\n".getBytes();
Path dfs=new Path("/test");
FSDataOutputStream outputStream=hdfs.create(dfs);
outputStream.write(buff,0,buff.length);
}
}
3.创建HDFS目录
通过“FileSystem.mkdirs (Path f)"创建目录。例:
public static void main(String[] args) throws Exception{
Configuration conf=new Configuration();
FileSystem hdfs=FileSystem.get(conf);
Path dfs=new Path("/TestDir");
hdfs.mkdirs(dfs);
}
3.MapReduce
原理
mapreduce是一个分布式运算程序的编程框架,核心思想是“分而治之”。将一个大任务分成多个小的子任务(map),由多个节点进行并行执行,并行执行后,合并成结果(reduce)。
Map函数
1.输入:键值对<k1,v1>;如<行号,"a,b,c">
2.输出:List(<k2,v2>),如<"a",1> <"b",1>
3.说明:①将小数据集进一步解析成一批<key,value>对,输入Map函数进行处理。②每一个输入的<k1,v1>会输出一批<k2,v2>。<k2,v2>是计算的中间结果。
Reduce函数
1.输入:<k2,List(v2)>;如<"a",<1,1,1>>
2.输出:<k3,v3>;如<"a",3>
3.说明:输入的中间结果<k2,List(v2)>中的List(v2)表示是一批属于同一个k2的value。
MapReduce编写
1.编写程序分为三个部分:Mapper,Reducer,Driver(提交运行mapreduce程序的客户端)
2.Mapper的输入、输出数据是KV对的形式,Mapper的业务逻辑写在map()方法中,map()方法对每一个<k,v>调用一次
3.Reducer的输入数据是KV对的形式,Reducer的业务逻辑写在reduce()方法中,reduce()方法对每一个<k,v>调用一次
4.自定义的Mapper和Reducer都要继承各自的父类
5.整个程序需要一个Driver来进行提交,提交的是一个描述了各种必要信息的job对象
wordcount示例编写
在一堆给定的文本文件中统计输出每一个单词出现的总次数
(1)定义一个mapper类
//首先要定义四个泛型的类型
//keyin:LongWritable valuein:Text
//keyout:Text valueout:IntWritable
public class WordCountMapper extends Mapper<LongWritable,Text,Text,LongWritable>{
//map方法的生命周期:框架每传一行数据就被调用一次
//key : 这一行的起始点在文件中的偏移量
//value: 这一行的内容
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//拿到一行数据转换为string
String line = value.toString();
//将这一行切分出各个单词
String[] words = line.split(" ");
//遍历数组,输出<单词,1>
for(String word:words){
context.write(new Text(word), new IntWritable(1));
}
}
}
将单词作为key,次数1为value。以便后续的数据分发,根据单词分发相同的单词分到相同的reduce task
(2)定义一个reduce类
//生命周期:框架每传递进来一个kv 组,reduce方法被调用一次
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//定义一个计数器
int count = 0;
//遍历这一组kv的所有v,累加到count中
for(IntWritable value:values){
count += value.get();
}
context.write(key, new IntWritable(count));
}}
(3)定义一个主类,用来描述job并提交job
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class WordcountDriver {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
//conf.set("HADOOP_USER_NAME", "hadoop");
//conf.set("dfs.permissions.enabled", "false");
//不提交在yarn上面,只在本地跑
conf.set("mapreduce.framework.name", "local");
//本地模式运行mr程序时,输入输出的数据可以在本地,也可以在hdfs上
//到底在哪里,酒宴以下两行配置,用的是哪行,默认是本地的
conf.set("fs.defaultFS", "file:///");
/*conf.set("fs.defaultFS", "hdfs://192.168.175.128:9000/");
conf.set("mapreduce.framework.name", "yarn");
conf.set("yarn.resoucemanager.hostname", "192.168.178.128");*/
Job job = Job.getInstance(conf);
/*job.setJar("/home/hadoop/wc.jar");*/
//指定本程序的jar包所在的本地路径
job.setJarByClass(WordcountDriver.class);
//指定本业务job要使用的mapper/Reducer业务类
job.setMapperClass(WordcountMapper.class);
job.setReducerClass(WordcountReduce.class);
//指定需要使用combiner,以及用哪个类作为combiner的逻辑
/*job.setCombinerClass(WordcountCombiner.class);*/
job.setCombinerClass(WordcountReduce.class);
//如果不设置InputFormat,它默认用的是TextInputformat.class
/*job.setInputFormatClass(CombineTextInputFormat.class);
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);
CombineTextInputFormat.setMinInputSplitSize(job, 2097152);*/
//指定mapper输出数据的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//指定最终输出的数据的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//指定job的输入原始文件所在目录
FileInputFormat.setInputPaths(job, new Path("D:\\wordstest\\input"));
//指定job的输出结果所在目录
FileOutputFormat.setOutputPath(job, new Path("D:\\wordstest\\output"));
//将job中配置的相关参数,以及job所用的java类所在的jar包,提交给yarn去运行
/*job.submit();*/
boolean res = job.waitForCompletion(true);
System.exit(res?0:1);
}
}
4.Hive
介绍
hive是基于Hadoop构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析数据
原理
hive和hadoop之间的工作流程:
Hive和Hadoop框架的交互方式:
数据类型
Hive中包含以下数据类型:
db:在 HDFS中表现为${hive.metastore.warehouse.dir}目录下的一个文件夹
table:在HDFS中表现所属db目录下一个文件夹
external table:与table类似,不过其数据存放位置可以指定在任意路径
partition:在HDFS中表现为table目录下的子目录
bucket:在HDFS中表现为同一个表目录下根据hash散列之后的多个文件
基本数据类型
复杂数据类型
元数据类型
内部表与外部表
分区表(partition)
在hive中,表中的一个partition对应表下的一个目录,所有的Partition的数据都存储在对应的目录中
创建分区表
create table 表名 (字段 属性) partitiooned by (分表用的字段 属性) row format delimited fields terminated by '.';
创建一个表内容包括分区的一个特征
insert into table 表名2 partition(字段=‘ ’) select 表1中字段 from 表2 where 字段=‘ ’;
桶表(Bucket Table)
桶表是对数据进行哈希取值,然后放到不同文件中存储
创建一个表,以id分两个桶
create table 表名 (id int,name string, gender string,s1 float,s2 float,s3 float) clustered by(id) sorted by(gender) into 2 buckets row format delimited fields terminated by '.';
视图(view)
视图是一种虚表,是一个逻辑概念,可跨越多张表
视图建立在已有表的基础上,视图赖以建立的这些表称为基表
视图可以简化复杂的查询
已知一个表有id,name,gender,s1,s2,s3六个字段,现按后三个字段和排序
select id ,name,gender,(s1+s2+s3) as score from 表名 order by score desc;
创建一个tmpview表将上面内容保存在表中
create view tmpview1 as select id ,name,gender,(s1+s2+s3) as score from 表名 order by score desc;
命令行模式(CLI)
清屏:Ctrl+L或!clear
看数据库中的表:show tables;
看数据库中的内置函数:show functions;
看表结构:desc 表名
看HDFS上的文件:dfs -ls 目录
执行Linux操作系统的命令:!Linux命令
执行HQL语句:select * from 表名 (查看表内数据)
执行SQL语句:source SQL文件 (执行某个脚本文件)
Hive命令
创建表
1.内部表
create table 表名(字段1 属性1,字段2 属性2...)
row format delimited
fields terminated by '\t' //这是 列 按什么进行分割
lines terminated by '\n'; //这是 行 按什么分割
2.外部表
create external table aa(uid int,uname string)
row format delimited
fields terminated by '\t'
lines terminated by '\n'
location 'hdfs://IP(或者主机名):9000/文件路径'; //HDFS上指定文件或目录地址
插入
insert into (字段名...) 表名 values (值...);
多表插入:指在同一条语句中,把读取的同一份数据插入到不同的表中。只需要扫描一遍数据即可完成所有表的插入操作,效率很高。
from buyer_log
insert overwrite table buyer_log1 select *
insert overwrite table buyer_log2 select*;
查询
1.普通查询
select * from 表名;
有时数据量大,使用关键字limit限制输出条数 select * from 表名 limit 10;
tablesample语句
select * from goods_t tablesample(bucket 1 out of 2 on goods_id);
tablesample 是抽样语句,语法如下:
tablesample(bucket x out of y)
y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。例如,table总共分了64份,当y=32时,抽取(64/32=)2个bucket的数据,当y=128时,抽取(64/128=)1/2个bucket的数据。
x表示从哪个bucket开始抽取。例如,table总bucket数为32,tablesample(bucket 3 out of 16),表示总共抽取(32/16=)2个bucket的数据,分别为第3个bucket和第(3+16=)19个bucket的数据。
2.别名查询
当多表连接字段较多时,常用别名
select b.id,b.ip from buyer_log b limit 10;
3.限定查询(where)
select buyer_id from buyer_log where opt_type=1 limit 10; //查询buyer_log表中opt_type=1的用户ID(buyer_id)
4.两表或多表联合查询(可按需求查询多个表中不同字段)
select l.dt,f.goods_id from buyer_log l,buyer_favorite f where l.buyer_id = f.buyer_id limit 10; //通过用户ID(buyer_id)连接表buyer_log和表buyer_favorite,查询表buyer_log的dt字段和表buyer_favorite的goods_id字段
删除
drop table 表名;
drop databases 数据库名;
多目录输出文件
将同一文件输出到本地不同文件夹中,提高效率,可以避免重复操作from
from buyer_log
insert overwrite local directory '本地地址1‘ select*
insert overwrite local directory '本地地址2‘ select*; /将buyer_log表导入到本地
数据导入
1.创建一个表与另一个表相同
create table 表名 like 另一个表名;
2.将Linux本地文件导入hive表
load data local inpath 'linux路径' into hive表名;
3.将hdfs中的文件导入hive表
load data inpath 'hdfs路径' into table 表名;
4.将表1中的数据查出来放到表2中
insert into 表名2 select * from 表名1;
5.创建表时并且导入数据
create table 表2 as select * from 表1;
HQL语句
DDL操作(数据定义语言)包括:Create、Alter、Show、Drop等。
(1)create database- 创建新数据库
(2)alter database - 修改数据库
(3)drop database - 删除数据库
(4)create table - 创建新表
(5)alter table - 变更(改变)数据库表
(6)drop table - 删除表
(7)create index - 创建索引(搜索键)
(8)drop index - 删除索引
(9)show table - 查看表
DML操作(数据操作语言)包括:Load 、Insert、Update、Delete、Merge。
(1)load data - 加载数据
①insert into - 插入数据
②insert overwrite - 覆盖数据(insert ... values从Hive 0.14开始可用。)
(2)update table - 更新表(update在Hive 0.14开始可用,并且只能在支持ACID的表上执行)
(3)delete from table where id = 1; - 删除表中ID等于1的数据(delete在Hive 0.14开始可用,并且只能在支持ACID的表上执行)
(4)merge - 合并(MERGE在Hive 2.2开始可用,并且只能在支持ACID的表上执行)
Hive数据仓库的操作
创建数据仓库
create database if not exiss DB; //加上if not exists可避免新建的库名与已有库名重复而报错
查看数据仓库的信息及路径
describe database DB;
某些关键字
[row format delimited]关键字,用来设置创建的表在加载数据的时候,支持的列分隔符
[stored as textfile]关键字,用来设置加载数据的数据类型。默认是TEXTFILE
分组排序
(1)Hive中的Order by和传统Sql中的Order by一样,对查询结果做全局排序,会新启动一个Job进行排序,会把所有数据放到同一个Reduce中进行处理,不管数据多少,不管文件多少,都启用一个Reduce进行处理。如果指定了hive.mapred.mode=strict(默认值是nonstrict),这时就必须指定limit来限制输出条数,原因是:所有的数据都会在同一个Reducer端进行,数据量大的情况下可能不出结果,那么在这样的严格模式下,必须指定输出的条数。
(2)Sort by是局部排序,会在每个Reduce端做排序,单个Reduce出来的数据是有序的,假设我设置了3个Reduce,那么这3个Reduce就会生成三个文件,每一个文件都会按Sort by后设置的条件排序,但是当这3个文件数据合在一起就不一定有序了,一般情况下可以先进行Sort by局部排序完成后,再进行全局排序,就会提高不少效率。
(3)Group by是分组查询,一般配合聚合函数一起使用,Group by有一个原则,就是Select后面的所有列中,没有使用聚合函数的列,必须出现在Group by后面。
(4)Hive中的Distribute by是控制在Map端如何拆分数据给Reduce端的。按照指定的字段对数据划分到不同的Reduce输出文件中,默认是采用Hash算法。对于Distribute by进行测试,一定要分配多Reduce进行处理,否则无法看到Distribute by的效果。
(5)Cluster by除了具有Distribute by的功能外还兼具Sort by的功能,相当于Distribute by+ Sort by的结合,但是排序只能是倒叙排序,不能指定排序规则为ASC或者DESC。
格式:
select * from 表名 排序方法(order by) 字段 desc limit 10;
join用法
1.join
内关联,只返回两个表中关联上的结果
select a.id,a.name,b.age from a join b on a.id = b.id
结果:
2.full(outer)join
全外关联,关键字outer可省略 。以两个表的记录为基准,返回两个表的记录去查之和,关联不上的字段为null。
select a.id,a.name,b.age from a full join b on a.id = b.id
得到结果:
3.left semi join
以left semi join关键字前面的表为主表,返回主表的KEY也在副表中的记录。
select a.name,b.name from a left semi join b on a.id = b.id
得到结果:
4.cross join
笛卡尔积关联,返回两个表的笛卡尔结果,不需要指定关联键
select a.id,a.name,b.age from a cross join b
得到结果:
5.Hive数据清洗思路
1.创建信息表(以两个字段分成分区表)
create table if not exists db(字段1 属性,字段2 属性) partitioned by (字段 属性,字段 属性) row format delimited fields terminated by '\t';
2.创建临时表1
create table if not exists db1(字段 属性...) row format delimitedd fields terminated by '\t';
3.分析数据向临时表1中插入数据
insert overwrite table db1 select 表1中字段或一些数据的合成 from db where 条件;
4.创建临时表2,分析数据向表2中插入数据
同2.3步
5.通过某些字段将两个临时表join在一起后插入到会话信息表中
insert overwrite table db partition(条件) select b1.字段,...b2.字段.. from db1 b1 join db2 b2 on .....;
6.创建结果表
create table db_result(字段 属性....) row format dalimited fields terminated by '\t';
7.为结果信息导入数据
insert overwrite table db_result select 字段或字段的合成 from db where ;