hive实践之map类型插入单条数据

  hive原本不是用来做简单的crud的,但有时候我们就是有可能这么干,怎么办呢?

  hive 还是提供了相应的功能的,查询是最必须的,就无须多说了。

  插入数据一般来说都是大批量的插入,一般用于从源数据中导入数据到hive中,然后经过hive加工后,写入到一张新的结果表。而这个表的数据一般也会很大,具体看业务复杂性。

  更新数据一般是不会被支持的,尤其是想更新某一条数据,但我们可以通过重新刷入数据的方式,达到更新数据的目的。一般hive表会有相应的分区要求,这样就可以做一定程度上的数据索引效果,以及减少大数据的量。而其底层存储为一个分区,一系列分组文件。

  删除数据就更是没有了,不过与更新数据一样的道理,我们可以通过重新进行数据加工,刷入新数据集即可完成删除的目的。不过,要想剔除其中一条数据,这个加工逻辑得好好想想了。

1. select查询

  这个最复杂的,也是最核心的。基本遵循sql92协议,也就是说基本上你会写sql, 就可以搞hive了。差别在于,hive会有很多自己支持的数据结构,以及很多特有的函数调用。另外,就是可以很方便地让用户自定义一些函数,以便满足业务需求。即udf. 因此,如果你不清楚这些udf如何使用,那么你就缺失了这方面的技能了。

  举一个例子说明即可:

with a as (
    select * from test_001 where pt='20210101'
),
 b as (
    select * from test_002 where pt='20200101'
 )
    select trim(a.name) name, 
        a.t_map['field1'] map_f1, 
        COALESCE(t1.f2, t2.f2) f2, 
        case when t1.money>1000 then 'G' else 'H' end
    from a join b on a.uid = b.uid

  总之一句话,你可以用sql表达非常复杂的业务逻辑。比如数据开发同学的重要利器就是这玩意。从一定角度上说,sql也是一门编程开发语言!骄傲了!

2. insert数据插入

  hive之类的大数据处理工具,一般只会支持大批量的插入。为什么呢?因为它的底层存储就是一个个地大文件,方便实现啊,效率高啊啥的!所以,一般地,又会多出来一个概念,分区!因为是一个个地文件,在处理的时候,能做确定数据在哪个文件上,那么它效率就会很高了。

  而像关系型数据库的索引之类的东西,这些大数据工具就不太方便有了,为什么呢?因为有大量的数据存储着,如果想要专门去建立索引,那么这个存储成本啊运算成本啊啥的,肯定就上去了。而最后可能还没有啥收益,因为我们更多地是做离线分析,并非差那几秒的性能,所以干脆不要了。

  先来看几个map类型的数据操作方式:

-- 一个泛型的map, 只要给定的值类型正确,就会得到正确类型的map了
-- map<string,string>, map<string,double>, map<string,int>
map('k', 'v1');
map('k', v1);
map('k', v1);
-- 将字符串转换为map形式,需要自行定义明确的分隔符
-- 注意,json并不能很好地转换为map形式
-- 以下结果为: {""b"":"2}","{"a"":""1""}
select str_to_map('{"a":"1","b":2}') from dual;
-- 以下结果为: {"a":"","b":"2"}
select str_to_map('a:,b:2') from dual;
-- 以下结果为: {"a":"1","b":"2"}
select map('a','1','b','2') from dual;
    
    接下来,我们来看下数据插入方式:
-- 从加工数据集中写入全量表
insert into table xxx select k1,k2,k3 from a_xxx;
-- 从加工数据集中覆盖式写入全量表
insert overwrite table xxx select * from a_xxx;
insert into table xxx partition(pt='xxx') select k1,k2,k3 from a_xxx;
insert into table xxx partition(pt='xxx') select k1,k2,k3 from a_xxx;

-- 将加工结果集创建一个新表写入
create table tableName ROW FORMAT delimited fields terminated by ',' stored as textfile  as 
    with a as (select * from t1 where pt='xxx') select a.uid from a

-- 插入一条条单独的记录
insert into values (v11, v12, v13), (v22, v22, v23);
-- 另外一种插入单条记录的方式,从虚表中选择常量集
insert into table xxx select k1,k2,k3 from dual;

3. 数据更新

  update数据与delete数据同sql标准协议,并无二致,但需要hive版本大于 0.14,且需要开启相应选项才可以。即需要支持hive的事务特性。

-- update数据与delete数据同sql标准协议
UPDATE tablename SET column = value [, column = value ...] [WHERE expression]
DELETE FROM tablename [WHERE expression]

4. 创建表操作

  创建表的方式与sql标签协议一致,只是有些特有类型可以使用,比如 map, struct...

-- 创建数据库
CREATE (DATABASE|SCHEMA) [IF NOT EXISTS] database_name
  [COMMENT database_comment]
  [LOCATION hdfs_path]
  [MANAGEDLOCATION hdfs_path]
  [WITH DBPROPERTIES (property_name=property_value, ...)];
-- 删除数据库
DROP (DATABASE|SCHEMA) [IF EXISTS] database_name [RESTRICT|CASCADE];
-- 创建表
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
  : primitive_type
  | array_type
  | map_type
  | struct_type
  | 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
  : 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 ]

-- 删除表
DROP TABLE [IF EXISTS] table_name [PURGE]; 
-- 表更名
ALTER TABLE table_name RENAME TO new_table_name;
-- 添加分区
ALTER TABLE table_name ADD [IF NOT EXISTS] PARTITION partition_spec [LOCATION 'location'][, PARTITION partition_spec [LOCATION 'location'], ...];
-- 删除分区
ALTER TABLE table_name DROP [IF EXISTS] PARTITION partition_spec IGNORE PROTECTION;

  本部分内容参考官网: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL

5. 总结

  hive中对于数据类型要求还是比较严的,实际上大部分的关系型数据库对类型要求都还是比较严的(mysql除外,它几乎可以使用string型类型插入任意字段)。

  在对数据进行插入操作时,需要注意数据类型,必要时做转换,如果不能做转换那么就需要换一种写法了。不过好在,hive对于简单类型的判定并不太严,比如 '1'与1 是相等的, 1.0 和 '1.0' 也都是可以的。而当我们使用presto进行操作时,则不会被支持,其要求的类型更严格。

  总之,针对每种类型的数据库,都有其特有的要求,我往往都需要为各自做相应的适配。所谓的标准协议,也只能从一定程度上约束大家的行为。但也已经非常不错了,至少大家是在标准的周围,扩展特有的能力,以满足不同的业务场景。

原文地址:https://www.cnblogs.com/yougewe/p/14244601.html