MR与hive_sql替换
// MR:
public static class Map extends Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(); private Text word = new Text(); public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString(); StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken()); context.write(word, one); } } } public static class Reduce extends Reducer<Text, IntWritable, Text, IntWritable> { public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; for (IntWritable value : values) { sum += value.get(); } context.write(key, new IntWritable(sum)); } } public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = new Job(conf, "WC"); job.setOutputKeyClass(Text.class); job.setOutputValueClass(Text.class); job.setMapperClass(Map.class); job.setReducerClass(Reduce.class); job.setInputFormatClass(TextInputFormat.class); job.setOutputFormatClass(TextOutputFormat.class); FileInputFormat.addInputPath(job, new Path("path")); FileOutputFormat.setOutputPath(job, new Path("path")); job.waitForCompletion(true); }
// HIVE_SQL:
create table dosc(line string);
load data inpath 'hdfa目录' overwrite into table dosc;
create table word_count as select w.word, count(1) as count from
(select expload(split(line, '\s')) as word from docs) w
group by w.word
order by w.word
什么是Hive
hive是基于Hadoop的一个数据仓库工具,
可以将结构化的数据文件映射为一张数据表,并提供类sql查询功能
为什么使用Hive
- 直接使用Hadoop所面临的问题
- 人员学习成本太高
- 项目周期要求太短
- MapReduce实现复杂查询逻辑开发难度太大
- hive优点
- 操作接口采用类SQL语法,提供快速开发能力
- 避免去写MapReduce, 减少开发人员的学习成本
- 扩展功能很方便
Hive的特点
1.可扩展: Hive可以自由的扩展集群的规模,一般情况下不需要重启服务。 2.延展性: Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数 3.容错: 良好的容错性,节点出现问题SQL仍可完成执行
Hive的架构图
- hive
1.Driver 2.Cli为shell命令行 3.JDBC/ODBC是hive的java实现,与传统数据库JDBC类似 4.WebGUI是通过浏览器访问Hive用户接口 5.metastore Driver: 1.解释器、编译器、优化器、执行器 2.解释器、编译器。优化器完成HQL查询语句从词法分析、语法分析、编译、优化以及查询计划的生成。生成的查询计划存储在HDFS中,并在随后有MapReduce调用执行。 metastore: 1.元数据存储 2.通常是存储在关系型数据库,如: mysql,derby中 3.hive将元数据存储在数据库中,hive中的元数据包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),标的数据所在目录等。
- Hadoop
1.Job Tracker 2..TaskTracker 相当于: nodemanager + yarn 3.Resourcemanager+AppMasterName Node 4.Data Node + Task Tracker
Hive与Hadoop的关系
1.hive利用HDFS存储数据,利用MapReduce查询数据 2.运行流程 2.1:发出SQL 2.2:Hive处理,转换成MapReduce 2.3:提交任务到Hadoop 2.4:MapReduce运行基于HDFS
Hive与传统数据库的对比
--- Hive RDBMS(关系型数据库)
查询语句 HQL SQL
数据存储 HDFS RAW DEVICE Local FS
执行 MapReduce Excutor
执行延迟 高 低
处理数据规模 大 小
索引 0.8版本后有位图索引 复杂的索引
Hive的数据存储
Hive中所有的数据都存储在HDFS中,元数据存储在(derby(一次只能和metastore连接,其他的连接报错) 或 mysql),没有专门的数据存储格式(可支持Text,SequenceFile,ParquetFile,RCFLIE等) => 只需要早创建表的时候告诉Hive数据中的列分隔符和行分隔符,Hive就可以解析数据。 Hive中包含以下数据模型 1.DB:在HDFS中表现为${hive.metastore.warehouse.dir}目录下一个文件夹 2.Table:在HDFS中表现所属db目录下一个文件夹。删除表后,在hdfs上的文件都被删了 3.External table:外部表与table类似,不过其数据存放位置可以任意指定路径,external创建不在当前目录下创建文件,只在mysql中创建对应元数据,external外部表被删除后,hdfs上的文件没有被删除,只删除元数据 4.Partition:在hdfs中表现为table目录下的子目录 5.Bucket:桶,在HDFS中表现为同一个表目录下根据hash散列之后的多个文件,会根据不同的文件把数据放到不同的文件中
Hive的基本操作
- 创建数据库
语句: create database two; use two; 现象: 1.HDFS目录/user/hive/warehouse:多了two.db目录 2.MYSQL数据库DBS 增加了一条记录 3.DB_LOCATION_URI: hdfs://mycluster/user/hive/warehouse/two.db
- DDL
- 创建表
语法: create [external] table [if not exists] table_name external可以创建外部表,同时需要指定数据路径location,Hive创建内部表时,会将数据移动到数据仓库指向的路径。 若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。再删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。 [col_name data_type] [comment col_comment] [comment table_comment] [partitioned by (col_name data_type [comment col_comment])] [clustered by (col_name, col_name......)] [sorted by (col_name[ASC|DESC], ...) INTO num_buckets buckets] 对于每一个表(table)或者分区,就Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分,Hive也是针对某一列进行桶的组织。 Hive采用对列值哈希,然后除以桶的个数求余的方式决定改条记录放在哪个桶当中。 把表或者(分区)组织成桶(Bucket)理由 1.查询效率高、数据少 2.取样高效、方便开发调试:在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分上试运行查询没会带来更多方便。 3.join的时候数据少 [row format row_format] delimited [fields terminated by char] [collection items terminated by char] [map keys terminated by char] [lines terminated by char] 或者 serde serde_name [with serdeproperties (property_name=property_value)] 用户在创建表的时候可以自定义Serde或者使用自带的serde.如果没有指定row format delimited,将会使用自带的Serde. 在创建表的时候,用户还需要为表指定列,用户在指定表的列的同事也会指定自定义的serde,Hive通过serde确定表的具体列的数据。 [stored as file_format] 如果数据需要压缩 stored as sequencefile 如果文件数据是纯文件 stored as textfile [location hdfs_path] like: like允许用户复制现有的表结构,但是不复制数据 创建内部表: create table if not exists mytable (sit int, sname string) row format delimited fields terminated by ',' stored as textfile; 现象: 1.two.db目录多了mytable空目录 2.desc extended mytable: tableType:MANAGED_TABLE 3.mysql表TBLS多了一条记录 创建外部表: create external table if not exists external_table (yid int, yanma string comment 'this you name') row format delimited fields terminated by ',' location '/xiaoke002/'; create external table if not exists external_table (yid int, yanma string comment 'this you name') row format delimited fields terminated by ',' location 'hdfs://mycluster/xiaoke002/'; 现象: 1.two.db目录没有文件 2.mysql表TBLS多了一条记录 3.desc extended mytable: tableType:EXTERNAL_TABLE 创建分区表: create table student_p (sno int, sname string, sex string, sage int, sdept string) partitioned by (part string) row format delimited fields terminated by ',' stored as textfile; 现象: 1.desc有分区信息 2.two.db目录下多了student_p空目录 hive> desc student_p; OK sno int sname string sex string sage int sdept string part string # Partition Information # col_name data_type comment part string Time taken: 0.255 seconds, Fetched: 11 row(s) 创建带桶的表: create table student_b (id int, age int, name string) partitioned by (stat_data string) clustered by (id) sorted by(age) into 2 buckets row format delimited fields terminated by ','; 现象: 1.desc有分区信息,没有桶信息 2.two.db目录下多了student_b空目录 3.插入数据必须指定分区:insert into student_b partition(stat_data='c') values(1,10,'wang'); hive> desc student_b; OK id int age int name string stat_data string # Partition Information # col_name data_type comment stat_data string Time taken: 0.063 seconds, Fetched: 9 row(s)
- 查看表
show table; show databases; show partitions table_name; show function table_name; desc [extended] table_name;
- 修改表
增加分区 create table student_table (sno int, sname string, sex string, sage int, sdept string) partitioned by (part string) row format delimited fields terminated by ',' stored as textfile; alter table student_table add partition(part='c', part='d'); 因为原表只有一个分区,所有只会增加分区: part=d HDFS目录student_table下增加: part=d 删除分区 alter table student_table drop partition(part='a') 重命名表 alter table student_table rename to t_student; 增加列 alter table t_student add columns(new_col string); add代表新增一列,字段位置在所有列后面,partition列前面 hive> desc t_student; OK sno int sname string sex string sage int sdept string new_col string part string # Partition Information # col_name data_type comment part string Time taken: 0.091 seconds, Fetched: 12 row(s) 更新所有列 alter table t_student replace columns (id int, address string, name string); replace 则表示替换表中所有字段,不会替换分区的字段 (desc仍是能查看到桶信息,但是已经没用了) hive> desc t_student; OK id int address string name string part string # Partition Information # col_name data_type comment part string Time taken: 0.068 seconds, Fetched: 9 row(s) 更新单个列 alter table t_student change name sname string comment "名称"; 列的位置对应的类型不可以改变,既sting不能修改为int,int不能修改为string
- 所有的插入、更新、删除的操作引起的一切变化都被保存在一个较小的增量文件中,由metastore在后台运行的mapreduce作业会定期将这些增量文件合并到'基表'文件中
- 动态分区
insert overwrite table target partition(dt) select col1, col2, dt from source;
- 多表插入
from source insert overwrite table target select col1, col2; 相当于(效率一样) insert overwrite table target select col1, col2, dt from source; 但是对于多表插入, from开头效率高,因为原数据只查一次 from record2 insert overwrite table table_name1 select year, count(distinct station) group by year insert overwrite table table_name2 select year, count(station) group by year insert overwrite table table_name3 select year, count(station) where month > 10 group by year
- 排序
1. order by 全排序 2. sort by 在reduce端排序 3.distribute by 将数据分到对应的year中,然后每个year根据温度自行排序 from record2 select year, temperature distribute by year sort by year asc, temperature desc; 4.当sort by 和distribute by 字段一样的时候,可以使用cluster by
- 桶
1.查询处理效率高, 两张表字段都有桶标识, map join效率高 2.采样 3.创建桶 create table bucketed_users(id int, name string) clustered by(id) sorted by(id asc) into 4 buckets; 4.取桶内1/4数据 select * from bucketed_users tablesample(bucket 1 out if 4 on id); 5.取桶内1/2数据 select * from bucketed_users tablesample(bucket 1 out if 2 on id); 6.对没有分桶的数据取样(虽然取得小一部分, 但是得全表扫描) select * from users tablesample(buckt 1 out of 4 on rand())
- load进去的数据如何查询正确性
select * from table limit 10;
- 创建表
Hive Shell参数-i 从文件初始化HQL
-e 从命令行执行指定的HQL -f 执行HQL脚本 -v 输出执行的HQL语句到控制台 Hive参数配置方式 (开发Hive应用时,不可避免地需要设定Hive的参数,设定Hive的参数可以调优HQL代码的执行效率,或帮助定位问题) 1.配置文件 1.1用户自定义配置文件:$HIVE_CONF_DIR/hive-site.xml 1.2默认配置文件:$HIVE_CONF_DIR/hive-default.xml 1.3用户自定义配置会覆盖默认配置 1.4HIVE也会读入Hadoop的配置,因为hive是作为Hadoop的客户端启动的,Hive的配置会覆盖Hadoop的配置 1.5配置文件的设定对本机启动的所有hive进程都有效 2.命令行参数 2.1 启动Hive(客户端或Serve方式)时,可以在命令行添加 hive -hiveconf hive.root.logger=INFO,console 2.2 作用域:session
2.3 重新定义查找hive-site.xml文件目录: hive --config /tmp/bigdata/hive/conf/tmp/ (文件目录,下一层是hive-site.xml)
2.4 hive --hiveconf fs.default.defaultFS=hdfs://path 指定文件系统(如果不设置默认本地)
2.5 hive --hiveconf --mapreduce.framework.name=yarn
hive --hiveconf yarn.resourcemanager.address=localhost:port 指定资源管理器
3.参数声明 3.1可以在HQL中使用set关键字设定参数 如: set.mapred.reduce.tasks=100 3.2作用域:session
3.3set 查看hive的所有属性值
3.4set -v查看hive和 hadoop的属性值
3.5set hive.execution.engline=tez使用apache的tez引擎
4.上述三种设定方式的优先级依次递增。既参数声明覆盖命令行参数,命令行参数覆盖配置文件设定。注意某些系统级的参数,例如log4j相关的设定,必须用前两种方式设定,因为那些参数的读取在Session建立以前已经完成了。
Hive函数
- 自定义函数级别 => UDF(java语言)
1.先开发一个java类,集成UDF,并重载evaluate方法 2.打成jar包上传到服务器 3.将jar包添加到hive的classpath add jar /tmp/hadoop/udf.jar; 4.创建临时函数与开发好的java class关联 create temporary function toprovince as 'cn.lyx.bigdata.udf.ToProvince'; 5.既可在hql中使用自定义的函数toprovince select toprovince(name), age from t_test;
UDF(java)两个条件,1.必须实现org.apache.adoop.hive.ql.exec.UDF2. 至少实现一个evaluate()方法
- Transform实现(python)
Hive自定义函数和Transform,当hive提供的内置函数无法满足你的业务处理需求时,此时就可以考虑使用用户自定义函数 Hive调用python脚本实现数据清洗、统计过程 说明:Hive的 TRANSFORM 关键字提供了在SQL中调用自写脚本的功能, 本实例通过python脚本对电影数据进行清洗,帮助读者了解hive调用python脚本的整个流程。 1、创建基表 CREATE TABLE u_data ( userid INT comment '用户ID', movieid INT comment '电影ID', rating INT comment '电影评分', unixtime STRING comment '时间戳') ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n' STORED AS TEXTFILE; 2、加载数据 load data local inpath '/tmp/bigdata/u.data' overwrite into table u_data; 3、查询数据 hive> select * from u_data limit 2; OK 196 242 3 881250949 186 302 3 891717742 4、建立python脚本 if __name__ == '__main__': for line in sys.stdin: # 去除头尾的空格 line = line.strip() # 分割一条数据 userid, movieid, rating, unixtime = line.split('\t') # 转化unixtime时间戳为日期时间,获取对应的星期值 weekday = datetime.datetime.fromtimestamp(float(unixtime)).isoweekday() # 输出清洗后的数据 print('\t'.join([userid, movieid, rating, str(weekday)])) 保存为weekday_mapper.py,保存路径为:/tmp/bigdata/ 注意: hive中运行: 1.一定要把汉字去掉 2.带main函数 5、 创建子表 CREATE TABLE u_data_new ( userid INT, movieid INT, rating INT, weekday INT) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'; 6、 添加python脚本 add FILE /tmp/bigdata/weekday_mapper.py; list file; 7、 插入数据 将原数据表u_data中经过python脚本清洗后的数据,加载到子表u_data_new中 insert overwrite table u_data_new select transform(userid, movieid, rating, unixtime) using 'python weekday_mapper.py' as (userid, movieid, rating, weekday) from u_data; 8、查询清洗后的数据 hive> select * from u_data_new limit 2; OK 196 242 3 4 186 302 3 7
- 查看函数
show functions 函数使用帮助 describe function length;
- 类型转换
cast('1' as int)
Hive数据倾斜解决方案
- 数据倾斜定义
简单的讲,数据倾斜就是我们在数据计算的时候,由于数据的分散度不够,导致大量的数据集中到了一台或者几台机器上计算, 这些机器的计算速度远远低于整个集群的平均计算速度,导致整个计算过程十分缓慢。
- 常见数据倾斜现象
1.用Hive数据计算的时候reduce阶段卡在99.99% 2.用SparkStreaming做实时算法的时候,一直会有executor出现OOM的错误,但是其余的executor内存使用率却很低。 3.Hadoop中的数据倾斜主要表现在 ruduce阶段卡在99.99%,一直99.99%不能结束。 3.1有一个或几个reduce卡住 3.2各种container报错OOM(内存溢出) 3.3读写的数据量极大,至少远远超过其它正常的reduce,伴随着数据倾斜,会出现任务被kill等各种诡异的表现。 经验:Hive的数据倾斜,一般都发生在Sql中Group和On上,而且和数据逻辑绑定比较深。
- 产生的原因
以hive为例,我们在做数据运算的时候,往往会涉及到count distinct、group by、join等操作,这些都会触发Shuffle动作,一旦触发,所有相同key的值就会拉到一个或几个节点上,就容易发生单点问题,造成数据倾斜。
- 如何解决
举例:比如就说订单场景吧,我们在某一天在北京和上海两个城市多了强力的推广,结果可能是这两个城市的订单量增长了10000%,其余城市的数据量不变。 然后我们要统计不同城市的订单情况,这样,一做group操作,可能直接就数据倾斜了。 解决数据倾斜有这几个思路 (1)业务逻辑,我们从业务逻辑的层面上来优化数据倾斜,比如上面的例子, 我们单独对这两个城市来做count,最后和其它城市做整合。 (2)程序层面,比如说在Hive中,经常遇到count(distinct)操作,distinct会导致group by无法在map阶段做一次聚合操作,导致数据在传输到reduce端时,数据量未能减少,reduce如果需要处理的数据量太大,就会导致整个Job很难完成,我们可以先group 再在外面包一层count,就可以了。 (3)调参方面,Hadoop和Spark都自带了很多的参数和机制来调节数据倾斜,合理利用它们就能解决大部分问题。 (4)MapJoin:当大表关联一个小表时,容易发生数据倾斜,通过MapJoin把小表数据全部加载到内存在map端进行join,避免reducer处理。 步骤二举例: SELECT day, COUNT(DISTINCT id) AS uv FROM lxw1234 GROUP BY day; 更换 SELECT day, COUNT(id) AS uv FROM (SELECT day,id FROM lxw1234 GROUP BY day,id)a GROUP BY day; 步骤三举例: 如:在hive中,通过设置hive.groupby.skewindata=true来自动进行负载均衡。 如:select count(distinct uid) from XXX group by XXX,当选项设定为 true,生成的查询计划会有两个 Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group ByKey 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce中),最后完成最终的聚合操作。 但是,当选项设定为 true时,hive不支持多列上的去重操作,如以下会报错: SELECT ip, count(DISTINCTuid), count(DISTINCT uname) FROMlog GROUP BY ip;
explain
explain的输出中有很多查询执行计划的详情信息,包含抽象语法树、hive执行各阶段之间的依赖图以及每个极端的信息,
一个阶段可能是像MapReduce作业文件移动这样的一个操作。如果要查看更详细的信息,使用explain extended
视图
视图是只读的,和正常的sql效率一样,视图无法为基表加载和插入数据。
索引
不使用,原因 1.每次查询时候都要先用一个job扫描索引表,如果索引列的值非常稀疏,那么索引表本身也会非常大; 2.索引表不会自动rebuild,如果表有数据新增或删除,那么必须手动rebuild索引表数据;
数据类型
数据类型
hql mysql类型对比 tinyint shot smallint byte int int bigint long 数据类型用于存储变长的二进制数据 bigcimal decimal decimal(5, 2)范围 [-999.99, 999.99] decimal(5) 范围 [-99999, 99999] string varchar timestamp 纳秒时间戳(未封装时区, 可以使用to_utc_timestamp和from_utc_timestamp函数转换) date date日期 复杂类型 array map struct 记录类型鸣凤庄了命名字段集合 union 从集中数据类型中指明选择一种,union的值必须与这些数据类型之一完全匹配 create table complex( c1 array<int>, c2 map<string, int>, c3 struct<a:string, b:int, c:double>, c4 union<string, int> ) select c1[0], c2['b'], c3, c4 from complex; => (1, 2, 1.0, {'a':63})
锁
默认不开启, show locaks 查看锁信息
日志
日志默认目录 ${java.io.tmpdir}/${user.name}/hive.log ${java.io.tmpdir} = /tmp 修改日志文件存放目录 hive -hiveconf hive.log.dir=/tmp/${user.name} 修改日志级别 1.conf/hive-loh4j.properties 2.hive -hiveconf hive.root.logger=DEBUG,console
hive服务连接
hive服务连接 hive --service help hive客户端 hive(相当于hive --service hiveserver2) jdbc:hive://host/dbname
总体流程图