2020.9.20(Hive的远程元数据服务模式安装及Hive SQL)

回顾:hive是一个数据仓库,建了表,进行了相应的基本操作,和关系型数据库是差不多的。

01 Hive的基本介绍

1、hive产生的原因

· a) 方便对文件及数据的元数据进行管理,提供统一的元数据管理方式

​ b) 提供更加简单的方式来访问大规模的数据集,使用SQL语言进行数据分析

2、hive是什么?

The Apache Hive ™ data warehouse software facilitates reading, writing, and managing large datasets residing in distributed storage using SQL. Structure can be projected onto data already in storage. A command line tool and JDBC driver are provided to connect users to Hive.

​ Hive经常被大数据企业用作企业级数据仓库。

​ Hive在使用过程中是使用SQL语句来进行数据分析,由SQL语句到具体的任务执行还需要经过解释器,编译器,优化器,执行器四部分才能完成。

​ (1)解释器:调用语法解释器和语义分析器将SQL语句转换成对应的可执行的java代码或者业务代码

​ (2)编译器:将对应的java代码转换成字节码文件或者jar包

​ (3)优化器:从SQL语句到java代码的解析转化过程中需要调用优化器,进行相关策略的优化,实现最优的 查询性能

​ (4)执行器:当业务代码转换完成之后,需要上传到MapReduce的集群中执行

3、数据仓库–Hive(简单了解即可)

1、数据仓库基本概念

​ 数据仓库,英文名称为Data Warehouse,可简写为DW或DWH。数据仓库,是为企业所有级别的决策制定过程,提供所有类型数据支持的战略集合。它是单个数据存储,出于分析性报告和决策支持目的而创建。 为需要业务智能的企业,提供指导业务流程改进、监视时间、成本、质量以及控制。

2、数据处理分类:OLAP与OLTP

​ 数据处理大致可以分成两大类:联机事务处理OLTP(on-line transaction processing)、联机分析处理OLAP(On-Line Analytical Processing)。OLTP是传统的关系型数据库的主要应用,主要是基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。

3、OLTP

​ OLTP,也叫联机事务处理(Online Transaction Processing),表示事务性非常高的系统,一般都是高可用的在线系统,以小的事务以及小的查询为主,评估其系统的时候,一般看其每秒执行的Transaction以及Execute SQL的数量。在这样的系统中,单个数据库每秒处理的Transaction往往超过几百个,或者是几千个,Select 语句的执行量每秒几千甚至几万个。典型的OLTP系统有电子商务系统、银行、证券等,如美国eBay的业务数据库,就是很典型的OLTP数据库。

4、OLAP

​ OLAP(On-Line Analysis Processing)在线分析处理是一种共享多维信息的快速分析技术;OLAP利用多维数据库技术使用户从不同角度观察数据;OLAP用于支持复杂的分析操作,侧重于对管理人员的决策支持,可以满足分析人员快速、灵活地进行大数据复量的复杂查询的要求,并且以一种直观、易懂的形式呈现查询结果,辅助决策。

基本概念:

​ 度量:数据度量的指标,数据的实际含义
​ 维度:描述与业务主题相关的一组属性
​ 事实:不同维度在某一取值下的度量

特点:

​ (1)快速性:用户对OLAP的快速反应能力有很高的要求。系统应能在5秒内对用户的大部分分析要求做出反 应。
​ (2)可分析性:OLAP系统应能处理与应用有关的任何逻辑分析和统计分析。

​ (3)多维性:多维性是OLAP的关键属性。系统必须提供对数据的多维视图和分析,包括对层次维和多重层次 维的完全支持。
​ (4)信息性:不论数据量有多大,也不管数据存储在何处,OLAP系统应能及时获得信息,并且管理大容量信 息。

分类:

​ 按照存储方式分类:

​ ROLAP:关系型在线分析处理

​ MOLAP:多维在线分析处理

​ HOLAP:混合型在线分析处理

​ 按照处理方式分类:

​ Server OLAP和Client OLAP

操作:

OLAP

​ 钻取:在维的不同层次间的变化,从上层降到下一层,或者说将汇总数据拆分到更细节的数据,比如通过 对2019年第二季度的总销售数据进行钻取来查看2019年4,5,6,每个月的消费数据,再例如可以钻取 浙江省来查看杭州市、温州市、宁波市…这些城市的销售数据
​ 上卷:钻取的逆操作,即从细粒度数据向更高汇总层的聚合,如将江苏省、上海市、浙江省的销售数据进 行汇总来查看江浙沪地区的销售数据
​ 切片:选择维中特定的值进行分析,比如只选择电子产品的销售数据或者2019年第二季度的数据
​ 切块:选择维中特定区间的数据或者某批特定值进行分析,比如选择2019年第一季度到第二季度的销售数 据或者是电子产品和日用品的销售数据
​ 旋转:维的位置互换,就像是二维表的行列转换,比如通过旋转来实现产品维和地域维的互换

4、数据库与数据仓库的区别

注意:前三条重点掌握理解,后面的了解即可

​ 1、数据库是对业务系统的支撑,性能要求高,相应的时间短,而数据仓库则对响应时间没有太多的要求,当然也是越快越好

​ 2、数据库存储的是某一个产品线或者某个业务线的数据,数据仓库可以将多个数据源的数据经过统一的规则清洗之后进行集中统一管理

​ 3、数据库中存储的数据可以修改,无法保存各个历史时刻的数据,数据仓库可以保存各个时间点的数据,形成时间拉链表,可以对各个历史时刻的数据做分析

​ 4、数据库一次操作的数据量小,数据仓库操作的数据量大

​ 5、数据库使用的是实体-关系(E-R)模型,数据仓库使用的是星型模型或者雪花模型

​ 6、数据库是面向事务级别的操作,数据仓库是面向分析的操作

现在搭建hive的第三种模式:

在这里插入图片描述
上节课搭建了hive的远程数据库模式,这种模式可能会用到,但不是企业里使用最多的方式。
想一个问题:之前已经安装好hive了,并且启动hive命令行接口,当我们敲一个hive回车启动hive的时候,元数据服务有没有启动?
启动了。有手动启动hive的元数据服务么,没有。说明当前提供hive meta store的元数据服务,只能在当前节点里使用,如果想在node03或node04中使用元数据服务,不可以使用。
搭建第三种模式,保证我们其他一些比如说sparkSQL,impala能够使用hive里面的元数据服务,独立出来一个服务。依然是要进行手动配置的。
MySQL server还是在node01
meta store client作为客户端放在node03
把meta store server元数据服务放在node04
AdminManual Metastore Administration
在这里插入图片描述
同样给出了相关的配置:
服务端的配置:
在这里插入图片描述
hive.metastore.thrift.bind.host
和之前相比多了这样一个端口:默认值是9083

客户端的配置:
在这里插入图片描述hive.metastore.uris
现在客户端与服务端是要独立开来的,意味着客户端只需要连接到meta store server,而meta store server连接到MySQL,连接MySQL的4个必要属性是在meta store server里配置的,而客户端只要能保证连接到meta store server就可以了。
所以这里需要使用thrift协议,RPC调用就可以进行访问了
hive.metastore.local
Metastore is remote. Note: This is no longer needed as of Hive 0.10. Setting hive.metastore.uri is sufficient.
meta store是远程连接,在hive0.10版本之后就不需要配置这个属性了,所以官网里虽然展示出来这个属性了,但是并不需要进行配置。
hive.metastore.warehouse.dir
远程hdfs目录

从node02节点拷贝到node03和node04:

cd /opt/bigdata
scp -r hive-2.3.4 root@node03:`pwd`
scp -r hive-2.3.4 root@node04:`pwd`

在node03中:
先做环境变量配置:

vi /etc/profile
添加:
export HIVE_HOME=/opt/bigdata/hive-2.3.4
在PATH中添加    :$

规定把第三台作为服务端,第四台作为客户端
在这里插入图片描述服务端要连接到MySQL的 ,需要在服务端配置MySQL的连接属性,客户端连接到服务端,不需要配MySQL
只需要加两个属性就可以了
在node03中:服务端这5个属性不需要做修改,但是为了和node02做区分需要改两个东西,改数据库的名称

<property>
    <name>hive.metastore.warehouse.dir</name>
    <value>/user/hive_remote/warehouse</value>
</property>
<property>
   <name>javax.jdo.option.ConnectionURL</name>
    <value>jdbc:mysql://node01/hive_remote?createDatabaseIfNotExist=true</value>
</property>

其他地方都不需要做修改。
在node04中:
只需要配两个属性就可以了,其余的删除

<property>
   <name>javax.jdo.option.ConnectionURL</name>
    <value>jdbc:mysql://node01/hive_remote?createDatabaseIfNotExist=true</value>
</property>
<property>
    <name>hive.metastore.uris</name>
    <value>thrift://node03:9083</value>
</property>

默认端口是9083的,只有这样才能保证连接成功。
该往MySQL存储相关的数据了:

mysql -uroot -pok

show databases; //现在还是3个数据库
在第三台节点执行:

schematool -dbType mysql -initSchema

这时候又多了一个数据库,hive_remote
接下来该启动服务了,启动对应的元数据服务

hive --service metastore

注意:这个窗口是一个阻塞式窗口,就会卡着不动。不用管它。
在第四台节点输入:

hive

远程模式搭建完成,安装就完成了,接下来开始讲SQL了。

Hive SQL

之前讲过hivesql了,但是那种方式是非常低效的,建表的时候仿照MySQL,但那种方式不够完整。hive完整的建表SQL应该怎么看:
还是回到官网,选择:
LanguageManual
现在属于数据库定义语言,SQL语句分三种,DDL DML DCL,这里用的DDL因为是建表语句
LanguageManual DDL

create database test;
show database;

这儿创建了一个test数据库,之前default存在配置的hdfs数据库里面,现在创建数据库之后,会在目录下建一个test.db的数据库,表会放在这里面

use test;

建表语句:从官网直接粘出来的
Create Table

CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name    -- (Note: TEMPORARY available in Hive 0.14.0 and later)
  [(col_name data_type [column_constraint_specification] [COMMENT col_comment], ... [constraint_specification])]
  [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]
  [SKEWED BY (col_name, col_name, ...)                  -- (Note: Available in Hive 0.10.0 and later)]
     ON ((col_value, col_value, ...), (col_value, col_value, ...), ...)
     [STORED AS DIRECTORIES]
  [
   [ROW FORMAT row_format]   //行格式,自己指定文件分隔符
   [STORED AS file_format]
     | STORED BY 'storage.handler.class.name' [WITH SERDEPROPERTIES (...)]  -- (Note: Available in Hive 0.6.0 and later)
  ]
  [LOCATION hdfs_path]
  [TBLPROPERTIES (property_name=property_value, ...)]   -- (Note: Available in Hive 0.6.0 and later)
  [AS select_statement];   -- (Note: Available in Hive 0.5.0 and later; not supported for external tables)
 
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
  LIKE existing_table_or_view_name
  [LOCATION hdfs_path];
 
data_type //hive里面提供了比MySQL更丰富的数据类型支持
  : primitive_type  //基础数据类型,多了string类型
  | array_type //数组类型,在array和map里,数据类型必须是一致的
  | map_type  //kv键值对的类型
  | struct_type  //C语言的结构体,和Java中的类一样
  | union_type  -- (Note: Available in Hive 0.7.0 and later) //几乎没有人用
 
primitive_type
  : TINYINT
  | SMALLINT
  | INT
  | BIGINT
  | BOOLEAN
  | FLOAT
  | DOUBLE
  | DOUBLE PRECISION -- (Note: Available in Hive 2.2.0 and later)
  | STRING
  | BINARY      -- (Note: Available in Hive 0.8.0 and later)
  | TIMESTAMP   -- (Note: Available in Hive 0.8.0 and later)
  | DECIMAL     -- (Note: Available in Hive 0.11.0 and later)
  | DECIMAL(precision, scale)  -- (Note: Available in Hive 0.13.0 and later)
  | DATE        -- (Note: Available in Hive 0.12.0 and later)
  | VARCHAR     -- (Note: Available in Hive 0.12.0 and later)
  | CHAR        -- (Note: Available in Hive 0.13.0 and later)
 
array_type
  : ARRAY < data_type >
 
map_type
  : MAP < primitive_type, data_type >
 
struct_type
  : STRUCT < col_name : data_type [COMMENT col_comment], ...>
 
union_type
   : UNIONTYPE < data_type, data_type, ... >  -- (Note: Available in Hive 0.7.0 and later)
 
row_format //FIELDS 属性  COLLECTION ITEMS 集合  MAP KEYS MAP  上面提到的结构都可以直接来进行存储  LINES 换行按什么来切割
  : DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]] [COLLECTION ITEMS TERMINATED BY char]
        [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
        [NULL DEFINED AS char]   -- (Note: Available in Hive 0.13 and later)
  | SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]
 
file_format:
  : SEQUENCEFILE
  | TEXTFILE    -- (Default, depending on hive.default.fileformat configuration)
  | RCFILE      -- (Note: Available in Hive 0.6.0 and later)
  | ORC         -- (Note: Available in Hive 0.11.0 and later)
  | PARQUET     -- (Note: Available in Hive 0.13.0 and later)
  | AVRO        -- (Note: Available in Hive 0.14.0 and later)
  | JSONFILE    -- (Note: Available in Hive 4.0.0 and later)
  | INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname
 
column_constraint_specification:
  : [ PRIMARY KEY|UNIQUE|NOT NULL|DEFAULT [default_value]|CHECK  [check_expression] ENABLE|DISABLE NOVALIDATE RELY/NORELY ]
 
default_value:
  : [ LITERAL|CURRENT_USER()|CURRENT_DATE()|CURRENT_TIMESTAMP()|NULL ] 
 
constraint_specification:
  : [, PRIMARY KEY (col_name, ...) DISABLE NOVALIDATE RELY/NORELY ]
    [, PRIMARY KEY (col_name, ...) DISABLE NOVALIDATE RELY/NORELY ]
    [, CONSTRAINT constraint_name FOREIGN KEY (col_name, ...) REFERENCES table_name(col_name, ...) DISABLE NOVALIDATE 
    [, CONSTRAINT constraint_name UNIQUE (col_name, ...) DISABLE NOVALIDATE RELY/NORELY ]
    [, CONSTRAINT constraint_name CHECK [check_expression] ENABLE|DISABLE NOVALIDATE RELY/NORELY ]

案例:
人员表
id,姓名,爱好,住址
1,小明,lol-book-movie,beijing:chaoyang-shanghai:pudong

建表语句:

create table psn(
id int,
name string,
likes array<string>,
address map<string,string>
)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':'
desc formatted psn;

在这里插入图片描述
分隔符都会进行展示
建完表该插入数据了,使用insert插入数据,太慢了,可以使用load,load属于DML操作,打开官方文档:
LanguageManual DML

第一个就是load操作,
Loading files into tables

Hive does not do any transformation while loading data into tables.
hive在加载表的时候并不会做任何额外操作。

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
 
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)] [INPUTFORMAT 'inputformat' SERDE 'serde'] (3.0 or later)

如果在写的时候,加了local意味着从本地Linux往里面导入数据,如果不加local指的是从hdfs的某一个目录往另外一个目录导入数据,这两个有区别的。

load data local inpath '/root/data/data' into table psn;

这个执行是比较快的

selest * from psn;

查看数据也加载成功了。这个时间2秒,使用insert插入一条数据38秒,所以一般在加载数据的时候,都会采用这样的操作

为什么使用load这么快?
Load operations are currently pure copy/move operations that move datafiles into locations corresponding to Hive tables.
虽然刚才做了一个load的操作,但本质上做了一个copy把本地的文件,拷贝到了hdfs的某一个目录里面,而不是通过mapreduce读取的。相当于hdfs dfs -put
当数据存放在hdfs某一个目录,需要从某一个目录移动到表目录是移动而不是拷贝了。两种情况要分清楚。

可以大胆做一个尝试,从本地上传文件相当于是一个拷贝的过程,能不能直接往里面put数据,如果可以成功,说明就是一个put操作。

hdfs dfs -put data2 /user/hive_remote/warehouse/psn

有数据了,证明在执行load操作的时候本身只是一个文件的上传/复制的过程,并不涉及到任何数据的转换操作。也就是说hive非常傻,它只会把当前目录下的文件都读出来,而不会管这个文件是通过何种方式上传到这个目录的。
在MySQL的时候,类型长度必须匹配才能上传成功, 叫做写时检查。而hive叫做读时检查,刚才上传文件的时候不会检测文件的格式,依然读出来的但是不符合格式所以显示null,但是在上传文件的时候不会报错。

分隔符

在不手动设置分隔符的时候,会有默认使用的分隔符(ctrl+v ctrl+a这种方式输入^A)
属性分隔符^A
集合分隔符^B
MAP分隔符^C
自己建文件的时候一定要指定好分隔符
在公司的时候可能会看到有人这样写,但自己绝对不要用:

create table psn2(
id int,
name string,
likes array<string>,
address map<string,string>
)
row format delimited
fields terminated by '\001'
collection items terminated by '\002'
map keys terminated by '\003'

在这里插入图片描述再导入数据的时候和刚才一模一样。
意味着:
\001指向^A
\002指向^B
\003指向^C

内部表和外部表

在表的描述信息里,有一个非常关键的字段叫做Table Type表类型:MANAGER_TABLE 管理表
但是注意了,这个管理表还有个名字叫做内部表,是由hive自己进行管理的,有内部表一定有外部表,EXTERNAL额外的
hive在默认情况下创建的时内部表,下面如何创建外部表以及内外部表的区别?

create external table psn4(
id int,
name string,
likes array<string>,
address map<string,string>
)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':'
location '/data';
hdfs dfs -mkdir /data

需要加external关键字,加location指定外部表位置。
往表中添加数据:

load data local inpath '/root/data/data' into table psn4;

同样有数据,看hdfs里的目录,数据是不在hive默认的位置存放了,而是在我们指定的目录下,而且只有数据文件没有表名称。

1. 内部表和外部表的区别:

1.内部表创建的时候,数据存储在hive的默认目录中,外部表创建的时候需要指定external关键字,同时需要指定location,指定存储目录(多张表也可以指定同一个location)
2.不管是内部表还是外部表,在MySQL里面一定都是由数据的

use hive_remote;
select * from TBLS;

在这里插入图片描述从psn到psn3叫做MANAGED_TABLE内部表,到了psn4叫做EXTERNAL_TABLE外部表,现在把表删了

drop table psn;

内部表在进行删除的时候,将数据和元数据全部删除。

drop table psn4;

外部表在删除的时候,只会删除元数据,不会删除数据。
面试hive的时候,经常被问到。

3. 应用场景:

内部表先创建表再添加数据,外部表可以先创建表,添加数据,也可以先添加数据再创建表。
根据公司的业务来决定,但是外部表确实用的比较多。
大数据是从2014年才在中国火起来的,公司积累了很大的数据在关系型数据库里存着,这个时候想用大数据做分析,直接把数据文件导入到hdfs里面,需要用hive分析的时候,直接用表和数据匹配起来就ok了,而不需要先建表,再根据表的方式往里面load。

提问:每次select都是一次MR么?
刚才做过很多select * 的操作,但实际发现并不是MR的操作,这个需要强调一个问题,所有的SQL语句操作都会转成mapreduce,但是hive里面帮我们做了优化,叫做抓取策略,一个叫mull 一个叫null,在说hive优化的时候会说清楚。

提问:metastore是单点么,会不会出现单点故障?
所有的连接都连接到了meta store server上了,通过9083直接访问到server,server和数据库发生连接,意味着是一次连接。在企业中hive是通过另外一种方式用的,叫hiveserver2

提问:hive在企业中实际的应用场景是什么?
hive本质上是mapreduce,而且很慢,如果公司有一些业务场景比如说离线分析的,今天产生上PG的文件,第二天需要分析结果。凌晨的时候会把前一天的结果做一个分析,分析完之后把结果存起来,涉及到全量分析和增量分析的概念。全量分析,每天产生1G数据,10天10G,每天都要把全部数据跑一遍,没有这个必要,只要把前一天增量数据跑一下就可以了。所有一般在晚上时候会排一些定时任务,到某个时间点的时候,直接进行执行。

现在在企业里,你的集群服务器是7*24小时工作的,但注意了,在晚上的时候,服务器也是非常非常忙的。因为白天积累了很多的离线任务都需要晚上跑,所有并不是晚上就闲着了,只是相对于白天而言,晚上资源更空闲一点,仅此而已。

对于某些实时性要求没那么高的数据,一般是放在晚上跑,如果实时性要求比较高一般放在白天跑。所有在公司如果有专业的运维人员,他对于资源的控制和把控是非常关键的,晚上也要做好资源的分配。

我们现在是把大数据和架构分开的,大数据是一个什么课程,需要学很多的组件,描述的是什么?数据流的流向,从数据的产生到数据的分析,到最后的可视化,中间都是需要N多个组件的,各个组件都需要足够了解。大数据也是类似架构的工作。

在公司如果做的是数据分析方面的工作,每天大数据工作就是写sql语句。mapreduce代码开发效率太低了,现在公司里要求在很短时间内完成一个需求,肯定会对开发效率做影响。

大数据是把很大的数据量,做了一个集中的分析处理,分析完之后一定会有一个结果数据,可能很庞大,比如上千万条,需要把大数据分析结果放到传统关系型数据库里面,进行外部展示。直接调大数据的话可能会有问题,所有都是直接查结果。大数据是做分析,不是立刻返回结果。每天查询SQL的需求是多变的,每天都不一样,结果也不一样,依然很慢。有一种新的开发模式叫做预处理,阿帕奇麒麟就是预处理的过程。

hive的分区:

在这里插入图片描述

在今后的学习过程中可能会听过N多种的分区,在Hadoop里面有个partition,hive里有分区的概念,spark也有分区的概念,Kafka里也有分区的概念,但是每个分区的时候,虽然都叫分区,但意思都不一样。
hive里的分区用来解决什么问题?
在上传某一个数据文件的时候,一定是把数据文件上传到某一个目录里面,这时候比如说我是一个电商公司每天产生10T数据,都放到一个目录里面,这个时候突然有需求,分析一下2018.11.11的数据,好拿数据么?
参考Hadoop的设计思想,分而治之!把很大批量的数据分成一小块一小块,给每小块的数据都加上一个标识,这个时候在获取数据的时候,是不是可以直接从某个格子里拿数据了,而不用把所有数据都遍历一次。这个效率是非常高的。
分区:为了提高检索数据的效率
实现:PARTITIONED BY (col_name data_type [COMMENT col_comment], …)
可以按照表的某一个字段进行分区操作
还是这一批数据,数据里有id,爱好,姓名,住址,现在要把这些人按照年龄进行分区,意味着每个字段里都要有男有女。要分析某个批次性别为女有多少人,如果没做标识的话,要把所有数据都load以下,如果奇数号是男,偶数号是女做好标识的话,直接取奇数条就可以了。

怎么建分区:
要创建分区表。

create table psn5(
id int,
name string,
likes array<string>,
address map<string,string>
)
partitioned by (gender string)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':'

表中没有gender字段,如果在属性里添加gender字段,会报错:
FAILED:SemanticException [Error 10035]:Column repeated in partitioning columns
在建数据表的时候,分区字段也是一个普通的列,只不过没有显示出来。

desc formatted psn5;

在往表里加载数据的时候是必须指定性别这个字段的。

load data local inpath '/root/data/data' into table psn5;

FAILED: SemanticException [Error 10062]: Need to specify partition columns because the destination table is partitioned
必须要指定分区列,因为这张表是一张分区表。
那怎么办呢?

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
 
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)] [INPUTFORMAT 'inputformat' SERDE 'serde'] (3.0 or later)

我们在往里面插入数据的时候,可以动态的往里面加上属性名称。

load data local inpath '/root/data/data' into table psn5 partition(gender='man');

后面多了一个man的字段,是在插入数据的时候,手动添加的,这个列就是分区列。

load data local inpath '/root/data/data' into table psn5 partition(gender='boy');

在这里插入图片描述分区表最直观的展示,这样有什么好处,以后在取数据的时候,直接取这个目录里的数据就可以了,而不需要全量扫描了。

现在建立的表叫单分区,还有多分区。

create table psn6(
id int,
name string,
likes array<string>,
address map<string,string>
)
partitioned by (gender string,age int)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':'

在这里插入图片描述分区列变成了两个,gender和age。
插入数据还可以用原来的方式么?
不成功的,如果建立的是一张多分区的表,就要求插入数据的时候,必须要把所有的分区列都指定数据,不能只指定其中一个分区列。

load data local inpath '/root/data/data' into table psn5 partition(gender='boy',age=12);

在这里插入图片描述如果有10个分区列,目录层次就是10层。

第二个问题?这两个分区列的顺序能互换么?
可以的,在匹配过程中并不是按照顺序进行匹配,而是按照字段名称进行匹配的,谁在前谁在后没有要求,但在hdfs中的文件路径是固定的。

load data local inpath '/root/data/data' into table psn5 partition(age13,gender='boy');

总结:
当创建的分区表包含多个分区列的时候,插入数据的时候,必须要将所有的分区列都添加值,不可以只写其中一个,分区列的顺序无所谓

分区的添加和删除

现在想删数据可以删么?
在load操作的时候,先建了分区的目录,然后再把数据文件放进去的。
能不能只添加分区目录不上传数据?
可以的。分区的语法操作:
在这里插入图片描述
Add Partitions

ALTER TABLE table_name ADD [IF NOT EXISTS] PARTITION partition_spec [LOCATION 'location'][, PARTITION partition_spec [LOCATION 'location'], ...];

这里添加分区的意思,不是指的添加分区字段,而是给分区字段添加值。

alter table psn6 add partition(gender='girl');

不能成功,当需要单独添加分区列的时候,必须要添加所有的分区列!

alter table psn6 add partition(gender='girl',age=13);

分区列有age和gender是添加了分区列么?不是,是添加了分区列里的一个值。

删除分区
Drop Partitions

ALTER TABLE table_name DROP [IF EXISTS] PARTITION partition_spec[, PARTITION partition_spec, ...]
  [IGNORE PROTECTION] [PURGE]; 
alter table psn6 drop partition(age=12);

当删除表的分区列的值的时候,可以只指定一个分区列,会把当前表的所有满足条件的分区列都删除

这种插入数据的方式太死了,最好是按照记录里某一个列来确定往某一个分区里添加数据,这时候就要用到动态分区了。

当前处理方式存在问题?当数据进入hive时候,需要根据数据的某一个字段向hive表插入数据,此时无法满足需求,因此需要使用动态分区。

提问:如果是以文件名来区分分区,而不是以文件来区分分区,是不是更快一点?
hdfs里的文件只能append,不能修改不能删除,如果以文件名来区分,比如按日期,同一天的数据都往里面扔,如果一天产生1T数据,效率依然是非常低的。不利于后续的处理,后面会有以文件来区分的方式,叫做hive的分桶操作。

需求:刚刚建分区表的时候都是内部表,如果有一张外部表,在hdfs

hdfs dfs -mkdir /kb09/age=10;
hdfs dfs -mkdir /kb09/age=20;
hdfs dfs -put data /kb09/age=10;
hdfs dfs -put data /kb09/age=20;
create external table psn7(
id int,
name string,
likes array<string>,
address map<string,string>
)
partitioned by (age int)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':'
location '/kb09'
select * from psn7;

能不能查到数据,没有数据。
为什么没有?
在进行查询的时候,第一件事一定是查询元数据,刚刚是直接在hdfs里创建目录和数据的,这时候,在hive里面知道有这个分区么?
不知道。hive不知道有这个分区查不到数据。对应的MySQL的这张表里并没有分区列

select * from PARTITIONS;

不可能把数据删掉,重新再建一份,这效率太低了,因此在官网里有这样的点,叫做修复分区。
在这里插入图片描述

msck repair table psn7;

在这里插入图片描述
现在再查询就有结果了。
当hdfs目录中存在数据,并且符合分区的格式,此时创建外部表的时候,一定要修复分区,才可以查询到对应的结果,否则是没有结果的。

在建表的时候只是指定了一个分区列,但那个列没有值,所以才需要添加。

如果内部表没写external只写了location,数据会放在哪里?
没有报错,数据会放在指定的位置

DML数据的增删改查

在这里插入图片描述

增加 insert :

Inserting data into Hive Tables from queries通过查询结果插入数据
语法:

Standard syntax:
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 FROM from_statement;
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement;
 
Hive extension (multiple inserts):
FROM from_statement
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1
[INSERT OVERWRITE TABLE tablename2 [PARTITION ... [IF NOT EXISTS]] select_statement2]
[INSERT INTO TABLE tablename2 [PARTITION ...] select_statement2] ...;
FROM from_statement
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1
[INSERT INTO TABLE tablename2 [PARTITION ...] select_statement2]
[INSERT OVERWRITE TABLE tablename2 [PARTITION ... [IF NOT EXISTS]] select_statement2] ...;
 
Hive extension (dynamic partition inserts):
INSERT OVERWRITE TABLE tablename PARTITION (partcol1[=val1], partcol2[=val2] ...) select_statement FROM from_statement;
INSERT INTO TABLE tablename PARTITION (partcol1[=val1], partcol2[=val2] ...) select_statement FROM from_statement;

官网示例:

FROM page_view_stg pvs
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country)
       SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip, pvs.cnt

要求,psn9这张表必须要提前创建好。

create external table psn9(
id int,
name string,
)
row format delimited
fields terminated by ','

插入数据:

insert overwrite table psn9
select id,name from psn

不推荐使用,效率慢,但实际需求在工作过程中用的非常非常多!
hive的扩展操作,刚才的sql语句可以改写:

create external table psn10(
id int
)
from psn
insert overwrite table psn9
select id,name
insert into table psn10
select id

有什么用处?不可能把表里所有的记录数都拿出来,假如有一张表有100个字段,可以把其中几个字段拿出来当做一个子表。在实际工作中用的非常多,不可能一条sql语句把所有结果都得到了,中间会产生很多临时表,把临时表数据暂时进行存储。

Writing data into the filesystem from queries把查询结果作为文件存储
语法:

Standard syntax:
INSERT OVERWRITE [LOCAL] DIRECTORY directory1
  [ROW FORMAT row_format] [STORED AS file_format] (Note: Only available starting with Hive 0.11.0)
  SELECT ... FROM ...
 
Hive extension (multiple inserts):
FROM from_statement
INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement1
[INSERT OVERWRITE [LOCAL] DIRECTORY directory2 select_statement2] ...
 
  
row_format
  : DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]] [COLLECTION ITEMS TERMINATED BY char]
        [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
        [NULL DEFINED AS char] (Note: Only available starting with Hive 0.13)
insert overwrite local directory '/root/result' select * from psn;

千万不要指定成根目录了,千万不要忘记加local也不要直接写root目录,root目录有很多东西,会直接覆盖。这种写法也用的很少。

load用的非常多的,insert into 某一张表通过select语句插入,也用的很多,其他两种使用mapreduce效率太低

修改:update

UPDATE is available starting in Hive 0.14.
update在0.14之后就支持这样的操作了。
Updates can only be performed on tables that support ACID. See Hive Transactions for details.
update必须要支持ACID之后才能使用。
什么是ACID?
事务的4个特点,原子性, 隔离性,一致性,持久性。

update psn set name='zhangsan' where id=1

不能成功
Attempt to do update or delete using transaction manager that does not support these operations.
为什么不支持?
在这里插入图片描述
打开Hive Transactions里面有详细的介绍,只看一点limitation。
如果要支持update和delete,必须要保证事务的开启。同时,想开启事务还有一系列的限制,这些限制非常关键。
在这里插入图片描述
不讲事务也能理解,hive的数据是由hdfs存储的,hdfs里的数据支持删除和修改么?
不支持。
所以想做的话只能append,
Limitations

    BEGIN, COMMIT, and ROLLBACK are not yet supported.  All language operations are auto-commit.  The plan is to support these in a future release.
    现在事务的提交,回滚,开启还不支持。
    Only ORC file format is supported in this first release.  The feature has been built such that transactions can be used by any storage format that can determine how updates or deletes apply to base records (basically, that has an explicit or implicit row id), but so far the integration work has only been done for ORC.
    只有ORC这种文件格式在第一个版本里才适用。
    By default transactions are configured to be off.  See the Configuration section below for a discussion of which values need to be set to configure it.
    默认情况下事务是不开启的
    Tables must be bucketed to make use of these features.  Tables in the same system not using transactions and ACID do not need to be bucketed. External tables cannot be made ACID tables since the changes on external tables are beyond the control of the compactor (HIVE-13175).
    数据必须被分桶
    Reading/writing to an ACID table from a non-ACID session is not allowed. In other words, the Hive transaction manager must be set to org.apache.hadoop.hive.ql.lockmgr.DbTxnManager in order to work with ACID tables.
    At this time only snapshot level isolation is supported.  When a given query starts it will be provided with a consistent snapshot of the data.  There is no support for dirty read, read committed, repeatable read, or serializable.  With the introduction of BEGIN the intention is to support snapshot isolation for the duration of transaction rather than just a single query.  Other isolation levels may be added depending on user requests.
    The existing ZooKeeper and in-memory lock managers are not compatible with transactions.  There is no intention to address this issue.  See Basic Design below for a discussion of how locks are stored for transactions.
    Schema changes using ALTER TABLE is NOT supported for ACID tables. HIVE-11421 is tracking it.  Fixed in 1.3.0/2.0.0.
    Using Oracle as the Metastore DB and "datanucleus.connectionPoolingType=BONECP" may generate intermittent "No such lock.." and "No such transaction..." errors.  Setting "datanucleus.connectionPoolingType=DBCP" is recommended in this case. 
    LOAD DATA... statement is not supported with transactional tables.  (This was not properly enforced until HIVE-16732)

它虽然支持数据的更新和删除,但一般情况下不让这种情况产生。需要进行很多额外的配置,非常麻烦。
如果真的支持可以完成了,是怎么操作的?
把数据文件拿过来,重新写一份新文件,而不是在原文件做修改,因为hdfs明确表示了,文件只能append不能进行删除和修改。

所以就不要想数据的修改了,默认就是不修改的,之前在讲数据仓库的时候也说了,数据仓库中的文件是默认不修改的,要形成一个历史的时间拉链表。

回顾:
讲了hive的第二种搭建方式
hivesql如何建表
ddl的一些语句
hive的分区操作
hive的dml操作

comment:可以在建表语句添加,但用的很少,一般会写一个文档类似的数据字典。

分区太多也不太好,分区的粒度的问题,粒度太大或粒度太小都不好,比如现在数据是按照天来进行分区的,每天是把前一天的数进行分析。如果分区建的是年,不好,意味着要从365天把数据拿过来,如果数据是分钟,意味着要遍历N层的目录。所以要对项目需求有了解,最合适才是OK的。

猜你喜欢

转载自blog.csdn.net/m0_48758256/article/details/108694337