将csv导入hive中
1、首先在hive中创建自己的table, 并且设置分隔,如'\t'。
create table IP(ip varchar(30), country varchar(30), province varchar(30), city varchar(30), district varchar(30), linetype varchar(30)) row format delimited fields terminated by '\t' STORED AS textfile;其中STORED AS 默认保存格式为textfile
可以通过desc tablename 查看对应表结构
2、然后再输入导入的语句:
load data local inpath '/usr/testFile/result.csv' overwrite into table biao;
//(load data local inpath '文件路径' overwrite into table 表名;)
3、hive有三种导出语句
1、hive -e “select * from tablename” > /home/test.csv
2、hive -f test.sql > /home/test.csv (test.sql保存执行的查询语句)
3、insert overwrite local directory '/home/test/' select * from tablename
hive 不支持在InSert语句中直接给出一组记录的文字形式,即不支持InSert INTO ... values形式语句;
hive在加载数据的时候不会对数据进行任何处理,不会进行建索引,查询都是扫描整个数据,延迟性较高,所以不适合在线数据查询,hive大多数查询是通过Hadoop提供的MapReduce来实现的,而MapReduce本身也具有较高的延迟,MapReduce是进行并行计算,使hive可以通过MapReduce进行并行查询数据,所以即使没有索引,对大量数据进行查询也能体现出优势
hive的文件存储格式:
hive有三种文件存储格式:TEXTFILE、SEQUENCEFILE、RCFILE;
1、TEXTFILE格式:为默认格式,数据不做压缩,磁盘开销大,数据解析开销大,可以结合GZIP、Bzip2使用,但使用这种方式hive不会对数据进行切分,从而无法对数据进行并行操作;
事例:
> create table test1(str STRING)
> STORED AS TEXTFILE;
OK
Time taken: 0.786 seconds
#写脚本生成一个随机字符串文件,导入文件:
> LOAD DATA LOCAL INPATH '/home/work/data/test.txt' INTO TABLE test1;
Copying data from file:/home/work/data/test.txt
Copying file: file:/home/work/data/test.txt
Loading data to table default.test1
OK
Time taken: 0.243 seconds
2、SEQUENCEFILE格式:是Hadoop API提供的一种二进制文件支持,其具有使用方便、可切割、可压缩的特点;
sequenceFile支持三种压缩选择:NONE、RECORD、BLOCK;record压缩率低,一般建议使用BLOCK压缩;
事例:
> create table test2(str STRING)
> STORED AS SEQUENCEFILE;
OK
Time taken: 5.526 seconds
hive> SET hive.exec.compress.output=true;
hive> SET io.seqfile.compression.type=BLOCK;
hive> INSERT OVERWRITE TABLE test2 SELECT * FROM test1;
3、RCFILE格式:是一种行列存储相结合的存储方式;其首先将数据按行进行分块,保证同一个record在一个块上,其次块数据列式存储,有利于数据压缩和快速的列存取;
事例:
> create table test3(str STRING)
> STORED AS RCFILE;
OK
Time taken: 0.184 seconds
> INSERT OVERWRITE TABLE test3 SELECT * FROM test1;
除了上述三种方式外,用户还可以自定义存储方式,用户可以通过实现inputformat和outputformat来自定义输入输出格式;
例如:
> create table test4(str STRING)
> stored as
> inputformat 'org.apache.hadoop.hive.contrib.fileformat.base64.Base64TextInputFormat'
> outputformat 'org.apache.hadoop.hive.contrib.fileformat.base64.Base64TextOutputFormat';
$ cat test1.txt
aGVsbG8saGl2ZQ==
aGVsbG8sd29ybGQ=
aGVsbG8saGFkb29w
test1文件为base64编码后的内容,decode后数据为:
hello,hive
hello,world
hello,hadoop
load数据并查询:
hive> LOAD DATA LOCAL INPATH '/home/work/test1.txt' INTO TABLE test4;
Copying data from file:/home/work/test1.txt
Copying file: file:/home/work/test1.txt
Loading data to table default.test4
OK
Time taken: 4.742 seconds
hive> select * from test4;
OK
hello,hive
hello,world
hello,hadoop
Time taken: 1.953 seconds
如果表存在的时候去建立表会用上述命令会直接报错,可以在建表时添加 if not exists;如create table if not exists test(str string) row format delimited fields terminated by '\t' stored as textfile;
这样即使表存在,也不会报错,可以使用load data local inpath '/home/test.csv' overwrite into table test;(添加overwrite字段)
在创建表时可以添加external来建立外部表,内部表和外部表的区别是:在删除内部表时,会删除源数据和数据;删除外部表时,则只删除源数据,数据还会保存在hdfs中;
在创建外部表时,可以指定location参数来指定保存的路径:
如:create external table test_external(str string comment 'xingming',str1 string comment 'dianhua') comment 'this is the user data table' row format delimited fields terminated by '\t' stored as textfile location '<hdfs_location>';
创建分区:
hive在创建分区时是在创建表的时候使用partition by实现的,用来partition的维度并不是实际数据的某一列,而是根据插入内容时给定的,当查找某一分区的内容时可以采用where语句来实现
删除分区:
删除表中分区使用alter table tablename drop partition(分区属性='分区值'); 如 alter table test_partition drop partition(region='beijing');
查看表中分区:
show partition test_table;
重命名表:
alter table oldname rename to new_tablename;
修改表中列属性(包括列名、数据类型、注释、列位置或者他们的任意组合)
alter table test_table change [column] col_old_name col_new_name column_type [comment col_comment] [first|after column_name];
如:alter table test_external change str username string comment 'user_name' first;
或者:alter table test_external change str1 phone string comment 'telephone' after username;
增加或者替换表中字段:
增加字段:
alter table test_external add columns (addr string comment 'address');
替换字段:
alter table test_external replace columns(user string comment 'user_name',uid string comment 'user_id');替换表中字段是去掉表中所有字段,然后添加替换的字段;
查看有限行内容,用limit关键字
select * from test_table limit 10; 是随机在表中选10条数据;
load操作:只是单纯的复制/移动操作,将数据文件移动到hive表对应的位置;
hive不支持InSert语句一句一句的往表里插入数据,也不支持update操作,数据是以load方式加载到表中,数据一旦导入到表里,则不可修改
导出到本地
insert overwrite local directory '/home/test/' select * from test_table;
导出到hdfs
InSert overwrite directory '/data/data2/' select * from test_table;
导出到另一张表中(可以同时导出到多张表中或者本地文件中)
FROM src
INSERT OVERWRITE TABLE dest1 SELECT src.* WHERE src.key < 100
INSERT OVERWRITE TABLE dest2 SELECT src.key, src.value WHERE src.key >= 100 and src.key < 200
INSERT OVERWRITE TABLE dest3 PARTITION(ds='2008-04-08', hr='12') SELECT src.key WHERE src.key >= 200 and src.key < 300
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/dest4.out' SELECT src.value WHERE src.key >= 300;
hive是一个shell工具,可以用来运行于交互或者批处理方式配置单元查询
hive -e 'select * from test_table'
hive -f command.sql
sort by语法:(只能在淡季范围内排序)
sort顺序将根据列类型而定,如果数字类型的列,则排序顺序也以数字顺序,如果字符串类型,则排序顺序将按照字典顺序;
join语法:
hive支持等值连接(equality joins)、外链接(outer joins)、和左/右连接(left/right joins),不支持所有的非等值连接(非等值连接非常难转化到map/reduce任务);hive支持多余2个表的连接;
例如:
SELECT a.* FROM a JOIN b ON (a.id = b.id)
SELECT a.* FROM a JOIN b
ON (a.id = b.id AND a.department = b.department)
是正确的,然而:
SELECT a.* FROM a JOIN b ON (a.id b.id)
是错误的
1.
可以 join 多于 2 个表。
例如
SELECT a.val, b.val, c.val FROM a JOIN b
ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
如果join中多个表的 join key 是同一个,则 join 会被转化为单个 map/reduce 任务,例如:
SELECT a.val, b.val, c.val FROM a JOIN b
ON (a.key = b.key1) JOIN c
ON (c.key = b.key1)
被转化为单个 map/reduce 任务,因为 join 中只使用了 b.key1 作为 join key。
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1)
JOIN c ON (c.key = b.key2)
而这一 join 被转化为 2 个 map/reduce 任务。因为 b.key1 用于第一次 join 条件,而 b.key2 用于第二次 join。
join时每次的map/reduce逻辑是:reducer会缓存join序列中除了最后一张表的所有表记录,然后再通过最后一张表将结果序列化到文件系统中(所以应该把最大的表放到最后面),这一实现有助于减少内存的使用量;
1、如果所有表join的key值一样,则使用1次map/reduce任务计算,如下:
SELECT a.val, b.val, c.val FROM a
JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
reduce会缓存a表和b表的记录,然后每次取得一个c表的记录就计算一次join结果;
2、如果join的key值不同,如下:
SELECT a.val, b.val, c.val FROM a
JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
上例用了2次map/reduce任务,第一次缓存a表,用b表序列化;第二次缓存第一次map/reduce任务的结果,然后用c表序列化;
left semi join是in/exists子查询更高效的实现,hive当前没有实现in/exists子查询,可以使用left semi join来实现,但join子句中的右边表只能在on子句中设置过滤条件,在where子句、SELECT子句或者其他地方过滤都不行;
如:select a.key,a.value from a where a.key in(
select b.key from b
)
可以被重写为:
select a.key,a.value from a left semi join b on(a.key=b.key)
udtf函数限制:1、select里面不能有其他字段,如select id,count(*) as countNum from ....;
2、不能嵌套:如select explode(explode(adid_list)) AS myCol...
3、不支持group by /cluster by/distribute by/sort by
explode函数:
将数组进行转置:如:
hive> select myCol from test2;
表中数据为:
[1,2,3]
[7,8,9]
select explode(myCol) as myNewCol from test2;
输出结果为:
1
2
3
7
8
9
hive不支持having操作,也不支持where自剧中的子查询
SQL标准中,任何对null的操作(数值比较,字符串操作等)结果都为null。Hive对null值处理的逻辑和标准基本一致,除了Join时的特殊逻辑。
这里的特殊逻辑指的是,Hive的Join中,作为Join key的字段比较,null=null是有意义的,且返回值为true。
hive对分号字符识别不是很智能,如select concat(cookie_id,concat(';',’zoo’)) from c02_clickstat_fatdt1 limit 2;语句,hive解析语句时是遇到分号就认为语句结束,而无论是否用引号包含起来
解决办法是:使用分号的八进制ASCII码进行转义,如上述语句:select concat(cookie_id,concat('\073','zoo')) from c02_clickstat_fatdt1 limit 2;(使用十六进制分号,则hive将其当做字符串进行处理,并没有转义,好像仅支持八进制)
INSERT OVERWRITE TABLE在插入数据时, 后面的字段的初始值应注意与表定义中的一致性. 例如, 当为一个STRING类型字段初始为NULL时:
NULL AS field_name // 这可能会被提示定义类型为STRING, 但这里是void
CAST(NULL AS STRING) AS field_name // 这样是正确的
又如, 为一个BIGINT类型的字段初始为0时:
CAST(0 AS BIGINT) AS field_name
hive中优化主要是避免数据倾斜问题
join的实现过程:
1、map:以join on条件中的列作为key,如果有多个列,则key是这些列的组合
以join之后所关系的列作为value,当有多个列时,value是这些列的组合,在value中会包含表的tag信息,标明该value属于哪个表
按照key进行排序
2、shuffle:根据key的值进行hash,并将key/value对按照hash值推至不同对reduce中;
3、reduce:reducer根据key值进行join操作,并通过tag来识别不同表中的数据。