vi命令:
ctrl + :切换到命令模式,输入 %s/a/b/g ,会将 a 替换成 b。
vi 编辑后文件,如果错误地使用 ctrl +zz 关闭编辑,下一次打开时会老是报错。这是因为这样并没有退出编辑文件,可以通过杀死进程来解决
注意直接杀死进程是不行的,因为会有一个临时文件
ps aux | grep vi (或者 ps -ef | grep vi) ,kill -9 6087 ,但是不行。
正确方法,删除 .xx.txt.swp 临时文件
ll 显示文件后,然后 rm .xx.txt.swp
删除全部内容:
在命令模式下 ,先使用 :0或:1 跳到文件第一行,然后输入:.,$d(表示删除当前光标后面的所有内容) 一回车就全没了
另::$ 跳到文件最后一行
hive 的基本使用介绍
1、hive 的参数设置方式
a、直接在 hive 窗口使用 set 去设置:只对当前连接的 session 有效
让提示符显示当前库,这样结果就会显示当前所在库名了。
设置 hve命令 打印当前的库
set hive.cli.print.current.db=true;
显示查询结果时显示字段名,不设置使用 select * from table ,只会有数据,不会有对应字段提示。
set hive.cli.print.header=true
[图片上传失败...(image-d503ab-1546140371812)]
注:上面两个参数设置都只是临时的,如果关闭 hive 将会失效
解决办法:
在 linux 的当前用户目录下(即~,cd 命令下),编辑一个 .hiverc 文件(隐藏文件,hive启动时会去加载这个文件),写入以下参数
set hive.cli.print.current.db=true;
set hive.cli.print.header=true;
b、配置文件设置:全局有效
用户自定义配置文件:$HIVE_CONF_DIR/hive-site.xml
默认设置文件:$HIVE_CONF_DIR/hive-default.xml
注:使用 vi ~/.bashrh 命令查看设置的各个全局变量,知道 hive、hadoop 的安装目录是在哪里
使用 vi /etc/hosts 查看 ip 地址的别名
[图片上传失败...(image-a4b758-1546140371812)]
c、启动hive 窗口或者远程连接时指定:只当前session 有效
使用以下命令启动,设置显示当前库名,可以跟多条参数
hive -hiveconf hive.cli.print.current.db=true hive.cli.print.header=true
3、启动 hive 的另一种方式:把 hive 启动为一个服务(端口10000),这样就可以使用 hive客户端(beeline)在任意地方访问了。
启动服务端,注意这是阻塞式的,输入以下命令
/opt/hive2.1/bin/hiveserver2
注意:在后台运行的启动方式,1表示标准输出信息>重定向输出,2表示错误信息,最后一个&就是表示不阻塞后台运行,这里指向 /dec/null 是一个黑洞,放什么都会消失。加nohup 是为了不会因为当前用户退出而导致服务退出,而是会一直运行除非使用 kill -9 杀进程,jobs -l 命令可以查看进程号, 或者使用ps aux|grep file.name
nohup /opt/hive2.1/bin/hiveserver2 1>/dev/null 2>&1 &
可以使用命令查看 10000 端口,有看到10000端口这样就可以启动客户端
netstat -nltp
启动客户端,这是一个交互式程序
/opt/hive2.1/beeline
写命令连接到服务端,URI 符合jdbc规范,用户是启动 hdfs 的用户名
!connect jdbc:hive2://192.168.109.147:10000:用户名:密码
服务端连接成功后,就可以写 hive 命令了
select * from table
客户端关闭
!quit
总结:
使用这种方式连接会和 mysql 的显示一样很好看,服务端会显示客户端的执行结果
注意程序是在开启服务端的机器运行的,下面分区表中是从本地加载文件到 hdfs,如果文件是在客户端的,那么 load data local inpath 语句将会报错;'文件不存在'。此时就需要在文件所在机器直接用 hive 命令开启而不是用客户端连接了,这样就可以了。
4、hive 的脚本运行方式:不会进入hive 命令行
注意这个是 linux 命令,而不是在 hive 里面敲的,etl.sh 脚本如下
hive -e 'show databases;
select * from cookie4'
所以利用上面这个原理,就可以把很多命令都写成 hive -e 的形式,组成一个脚本 et1.sh,然后使用 sh et1.sh 命令执行 shell 脚本,可以把所有要执行的hive 语句都放到一个 hive -e "*****"; 里面, 使用hive -v -e “***” 会输出日志信息
[图片上传失败...(image-ef0edd-1546140371812)]
5、hive 命令的另一种执行方式:不会进入hive 命令行
适用于命令很长,用脚本也不不好写(一条语句几百行),就可以将命令写到一个 *.hql 文件(有; ,上面脚本的没有 ;),然后执行
hive -f test.hql
文件内容如下
select * from cookie5;
6、运行一个参数文件,从配置文件中启动 hive,并加载配置文件中的参数:会进入hive 命令行
inithive.conf 的内容如下,里面也可以放一下 hql 执行语句
use myhive;
set hive.cli.print.current.db=true;
一、hive的语句
查看当前所在库
select current_database();
模糊查找表名:包含lan 的表
show tables 'lan';
查看表信息
desc formatted table_name; 排列友好
desc extended table _name;
show create table table_name;
1、建库
建好库后,就会在 hdfs 中生成目录:/opt/hive2.1_data/warehouse/db_order.db
create database db_order;
建带属性的库:
create database db_name comment '库的属性:可选' dbproperties('creater'='lanyi','date'='2018-11-02')
删除库:
drop database db_lan; 空库
drop database db_lan cascade; 不是空库,库里面有表
2、建表
标准,包含 数组、结构体、字典的建表语句
create table cdt(
id int comment '识别码',
name string comment '姓名',
work_location array
piaofang map
address struct
row format delimited fields terminated by '\t'
collection items terminated by ','
map keys terminated by ':'
lines terminated by '\n' (默认就是以换行区分一条记录,可以省略)
stored as textfile; (默认文件格式)
使用 show create table cdt; 命令可以得到
表示是以\n 区分每行记录
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
表示底层文件存储格式是 textFile
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
注意:Hive 对文件中字段的分隔符默认情况下只支持单字节分隔符,如果数据文件中的分隔符是多 字符的,如下所示:
01||huangbo
02||xuzheng
03||wangbaoqiang
但是可以使用RegexSerDe 正则表达式来解析实现双字节分隔符
create table t_bi_reg(id string,name string)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe'
with serdeproperties('input.regex'='(.)\|\|(.)','output.format.string'='%1s')
stored as textfile;
load data local inpath '/home/hadoop/data.txt' into table t_bi_reg;
表建好后,会在库目录下再建一个表目录, /opt/hive2.1_data/warehouse/db_order.db /t_order
注意,如果不写 row 后面的语句,hive 会认为表数据文件中的字段分隔符为 ^A,这是一个
create table t_order(id string,create_time string,amount float,uid string) row format delimited fields terminated by ',';
表建好后,可以尝试把数据放到 hdfs 下,数据要放到表目录中。如
建立一个表
create table t_movie(movie string,actor string) row format delimited fields terminated by ',';
数据文件为 movie.dat,内容如下(一行一条数据,以逗号分隔)
zhuilong,liudehua
tianyi,
sansheng,wangfei
把数据放到 hdfs 文件目录,注意是表目录下
hadoop fs -put ./movie.dat /opt/hive2.1_data/warehouse/db_order.db/t_movie
通过 子查询建表,会带有查询出来的数据
create table t_data
as
select *****;
注意:这种查询建表的方式生成的表字段名,会是查询结果的字段名,如果使用了 nvl(非空字段时取值,空字段时取值)这种不确定字段名的情况,就要使用 as 取别名,不然会又异常。
上面的注意情况,如果是查询数据插入到表中,则不用关注别名问题,因为不管取不取名字,插入表都是已经有字段名字了。
增加字段:
alter table t_date add columns (score int comment '得分',address string comment '地址')
增加分区:是增加分区,而不是增加分区字段
alter table t_date add partition(city = 'shenzhen');
alter table t_date add partition(city='ganzhou') partition(city='nankang');
3、删除表
hive 会从元数据库中清除关于这个表的信息,还会从 hdfs 中删除这个表的表目录
drop table t_order;。
删除表中数据,清空数据
truncate table tablename
删除库:
drop database db_lan; 空库
drop database db_lan cascade; 不是空库,库里面有表
删除分区,注意要有引号,因为分区字段定义是string
ALTER TABLE my_partition_test_table DROP IF EXISTS PARTITION (y=“2018 ”,m=“08”;
删除字段:不支持,但是可以使用 replace columns 替换字段来实现
删除分区:
alter table t_data drop partition (city='shenzhen');
3.1、改表
修改字段: 会将 name 字段变成 new_name sring类型,如果有注释仍然保留,不影响表数据
alter table t_data change name new_name string;
修改(替换)所有字段:会依次把字段替换掉,表数据保留并一 一对应,如果字段变少数据也变少,变多则为null。用来替换所有字段
alter table t_date replace columns (id int , name string , address string);
修改分区:只能修改分区存储的位置
此时原先的分区文件夹仍存在,但是在往分区添加数据时,只会添加到新的分区目录
alter table student_ptn partition (city='beijing') set location '/student_ptn_beijing';
添加分区时就指定分区的存储目录
alter table student_ptn add if not exists partition(city='beijing')
location '/student_ptn_beijing' partition(city='cc') location '/student_cc';
4、内部表 Managed_table 和外部表 External_table
建外部表的语法:不指定目录的就是 内部表
a、内部表的目录在 hive 的仓库目录中(/opt/hive2.1_data/warehouse ),外部表的目录由用户指定
b、drop 一个内部表时:hive 会清除相关元数据,并删除表数据目录(数据也没了)
c、drop 一个外表表时:hive 只会清除相关元数据(数据还在)
eg:
在 hdfs 下建立两级目录,所以带上了 -p,
hadoop fs -mkdir -p /pvlog/2017/
将造的日志数据 pv.log 放到 hdfs 新目录下(暴力导入数据),数据如下图
hadoop fs -put pv.log /pvlog/2017/
[图片上传失败...(image-9e70a0-1546140371812)]
建立外部表,将数据和表关联到一起(这样就不用将数据移动到表目录了)
create external table t_access( ip string,url string, access_time string ) row format delimited fields terminated by ',' location 'access/log';
此时查询数据,可得下图
select * from t_access
[图片上传失败...(image-899bbf-1546140371809)]
5、分区表
在表目录中为数据文件创建分区子目录,以便于在查询时,MR 程序可以针对分区子目录中的数据进行处理,缩减读取数据的范围(不然就要全部读取)。
比如:网站每天产生的浏览记录,浏览记录应该建一个表来存放,但是,有时候,我们可能只需要对某一天的浏览记录进行分析,这时,就可以将这个表建为分区表,每天的数据导入其中的一个分区,当然,每日的分区目录,应该有一个目录名(分区字段)。
partitioned by(day string)就是分区的依据
下面是建表语句,只会建表目录,分区的目录是在放数据的时候建立,先建表再放数据
create table t_pv_log(ip string,url string,comit_time string)partitioned by(day string)row format delimited fields terminated by ',';
创建两个日志数据文件,分别是 pv15.log,pv16.log 表示15、16两日的日志信息,然后导入数据。
将数据导入分区表,local表示从本地目录,partition 表示当前数据是哪个区的。
注意要保证运行此命令的机器与文件所在机器是同一台,不然会报文件不存在错误,此问题针对于服务器、客户端方式启动 hive 的情况。
load data local inpath '/home/python/Desktop/pv15.log' into table t_pv_log partition(day='0615');
导入数据后在表目录下会创建一个目录 day=0615,里面存放着 pv15.log 文件
也可以查询到数据了,结果如下图(多了一个字段)
select * from t_pv_log
[图片上传失败...(image-21279f-1546140371812)]
查询不同区的数据
select * from t_pv_log where day=‘0615’;
注意:这里各个区的数据文件名字是无关紧要的,不同区的名字也可以相同,只看用户是将什么数据导入了什么区去。
另外因为分区会多一个字段,所以要注意不能是表中已有字段名
查询分区
show partiticons tablename;
6、CTAS 建表语法
通过已存在的表来建表
创建一个和 table1 一样字段的 table2 表
create table table2 like table1
创建一个表类似与已有表,不仅字段一样而且还带有数据(好像不会有分区),查出来是什么字段名新表就是什么字段名
create table table2
as
select * from table1 where ip>‘192.168.109.2’;
7、将数据导入 hive 表
方法1:手动用 hdfs 命令,将文件放到表目录下
方法2:从linux本地导入 文件,在 hive 的交互式 shell 中用 hive 命令来导入本地数据(非hdfs)到表目录,本地文件还在,并且表目录下也会有一份数据
这是 hive 命令:注意表的文件类型是 textfile 才可以导入 txt等文本文件
load data local inpath ‘/root/order.data’into table t_order;
方法3:从hdfs 系统导入文件,用 hive 命令导入 hdfs 中的数据到表目录(命令没有 local)
注意从 hdfs 中导入文件,文件会被移动到表目录下
这是 hive 命令
load data inpath ‘/opt/order.data’ into table t_order;
方法4:直接插入数据,和mysql一样
[table] 可以省略,注意
insert into [table] tablename [partition(y=,m=,d=*)] values(字段1值,字段2值,...) ,(字段1值,字段2值,...) ,,,
insert into [table] tablename (字段1,字段2,...) values (字段1值,字段2值,...),,,
会重写数据
insert overwrite table table_name 【partition(y=2018’,m=08)】
select * from 。。。
会插入数据,注意插入语句要保证数据与字段是能匹配的,不然报错
insert into table table_name【partition(y=2018’,m=08) 】
select * from 。。。
视图:
和关系型数据库有差别
a、只有逻辑视图,没有物化视图
b、视图只能查询,不能load、insert、update、Delete数据
c、视图再创建的时候,只是保存了一份元数据,当查询视图的时候,才开始执行视图对应的那些子查询
不手动指定视图的字段信息
cretate view view_name as select * from cdt;
创建视图的时候加上表注释
create view view_name(name comment '姓名',age comment '年龄')
comment '这是视图注释,可省略'
as select * from cdt;
二、Hive 的关联查询
1、内连接 ,join 或者 inner join
没有连接条件,结果会是 t_a、t_b两个表的所有行两两相连接
这种就是叫 笛卡尔积
select a.* ,b.* from t_a a join t_b b ;
有连接条件的连接语句,求交集,是inner join
select a.* ,b.* from t_a a join t_b b on a.name=b.name;
[图片上传失败...(image-9ac445-1546140371811)]
2、左连接, left join 和 left outer join是一样的
以左边为基准,左边表数据都保留,右表如果没有符合连接条件的会显示 NULL
select a.* ,b.* from t_a a left join t_b b on a.name=b.name;
[图片上传失败...(image-faa969-1546140371811)]
右连接,类似
[图片上传失败...(image-bfbb26-1546140371811)]
3、全外连接,full outer join
左右表的数据都返回,哪个表没有就补充 NULL,不是join
select a.* ,b.* from t_a a full outer join t_b b on a.name=b.name;
[图片上传失败...(image-356c2f-1546140371811)]
4、左半连接,semi join
右表数据不返回,左表数据只返回连接上的,类似 inner join 结果的一半
注意 select 结果不能有 b 表的东西,因为查出来就没有结果
select a.* from t_a a semi join t_b b on a.name=b.name;
[图片上传失败...(image-1b6c58-1546140371811)]
5、lateral view 连接:(这个一般意义上不叫连接)
可以把表扩展一些新的字段,但是后面需要连接数组(hive里面的数据类型array)、列表(tuple,使用 json_tuple 函数处理json字典数据时的结果),表扩展的对应行数据扩展后会对应行拼接起来
json 是表名,data 字段存放的是json 数据
select * from json lateral view json_tuple(data,'movie','rate','timeStamp','uid') a as a1,a2,a3,a4;
[图片上传失败...(image-fc29d0-1546140371811)]
[图片上传失败...(image-d597b7-1546140371811)]
[图片上传失败...(image-c4531a-1546140371811)]
三、分组聚合
一些函数
hive 中使用 show functions 可以查看函数命令
1、大写函数
将 url 字段内容大写
select upper(url)from t_pv_log;
[图片上传失败...(image-8c52d6-1546140371811)]
2、计数、count
3、查看分区
show partitions t_table;
求每条 url 的访问总次数
分组的表达式是对分组的数据进行逐组运算
count(1)表示一行就加一个
select url ,count(1) from t_pv_log group by url;
group by 分组后排序,使用 order by
这个是错的:会报 chn_name 字段不存在,这是因为order by 是对查询出来后的结果进行排序,必须是查询出来有的字段名
select length(chn_name),count(1) from tmp_base_info group by length(chn_name) order by length(chn_name);
下面这个才是对的:
select length(chn_name) as chn,count(1) from tmp_base_info group by length(chn_name) order by chn;
注意:分组查询的结果,只有分组条件字段可以直接写,其他字段只能是聚合函数的结果
四、子查询
把查询结果当做是一个表,用括号包起来并取一个别名,然后去查询。
五、hive 的数据类型
普通数据类型:
1、tinyint、smallint、int、bigint、float、double
2、日期类型 timestamp(时间戳)、date
eg:
有一些数据
1,zhangsan,1985-09-08
2,lisi,1979-07-18
那么可以创建一个表,带 birthday date 字段的去接收这些数据
3、string、char(字符型)
4、boolean(值为true、false)、binary(二进制)
复合数据类型:
1、array 数组类型
eg:有一个数据的一部分是 ‘吴京:杨刚:王伟’,如果将保存这个数据的字段定义为 string,那么要求获取其中一部分不太好求(要根据冒号切片),但是如果保存为数组就方便很多了。
定义为数组,里面是string
并且指定集合字段按照‘:’来切分
create table t_movie(movie_name string, actors array
row format delimited fields terminated by ','
collection items terminated by ‘:’;
[图片上传失败...(image-95253e-1546140371811)]
只取数组中一部分数据,如这里用角标取出第一个演员名字
[图片上传失败...(image-fbe77-1546140371811)]
配合函数可以实现更多功能:例如array_contains 查询包含某一演员的电影
select movie_name,actors,first_show
from t_movie
where array_contains(actors,'吴刚');
求电影有几个演员
select movie_name,actors,first_show ,size(actors)
from t_movie;
2、map 类型
eg:有一些数据如下,第二个字段是表示其家庭成员(可以 key 不一致)
1,zhangsan,father:xiaoming#mother:xiaohua#brother:xiaosu,28
2,lisi,father:mayun#mother:huangyi#sister:guanwu,22
那么可以使用一个 map 类型来对上面数据中的家庭成员进行描述
建表语句,map 里面放的是两个 string
并且分别告诉字段怎么切,元素怎切,key values 怎么切
create table t_person(id int,name string,family_members map
row format delimited fields terminated by ','
collection items terminated by '#'
map keys terminated by ':';
查询结果
select * from t_person
[图片上传失败...(image-7d2048-1546140371811)]
查询每个人的爸爸,使用字典的取值方式
select id,name,family_members【'father'】,age
from t_person;
[图片上传失败...(image-7af6fc-1546140371811)]
查出每个人有哪些亲属,只需要取 map 的 key
select id,name,map_keys(family_members)as relations
from t_family;
[图片上传失败...(image-edab34-1546140371811)]
查出每个人亲属的名字,只需要取 values
select id,name,map_values(family_members)as relations
from t_family;
[图片上传失败...(image-dc098f-1546140371811)]
查出每个人的亲人数量
select id,name,size(family_members)as relations
from t_family;
查出所有拥有兄弟的人
这里用了函数的嵌套,使用了数组判断元素的函数
select id,name,age from t_person
where array_contains(map_keys(family_members),‘brother’);
或者用子查询来实现
select id,name,age
from (select id,name,age,map_keys(family_members)as relations)tmp
where array_contains(relations,‘brother’);
[图片上传失败...(image-875979-1546140371811)]
3、struct 结构体类型:
是类与 对象的结构,就是 c 语言里面的对象,因此用点语法
eg:有以下数据
1,zhansan,18:male:深圳
2,lisi,28:female:北京
3,wangwu,38:male:广州
4,赵六,26:male:上海
5,钱琪,35:male:杭州
6,王八,48:female:南京
建表映射上面的数据,因为数据结合在一起所以用结构类型来表示
防止表存在,存在就删除,不存在不会影响
drop table [if exists] t_user
create table t_user(id int,name string,
info struct
row format delimited fields terminated by ','
collection items terminated by ':';(导入数据的时候结构体用:来分隔)
[图片上传失败...(image-a3d960-1546140371810)]
查询每个人的 id,地址,取数据用点语法
select id,name,info.addr from t_user;
[图片上传失败...(image-83696a-1546140371810)]