Hadoop生态上几个技术的关系与区别:hive、pig、hbase 关系与区别(三)

简介: Hadoop生态上几个技术的关系与区别:hive、pig、hbase 关系与区别(三)

5 Hive参数


hive.exec.max.created.files


说明:所有hive运行的map与reduce任务可以产生的文件的和


默认值:100000


hive.exec.dynamic.partition


说明:是否为自动分区


默认值:false


hive.mapred.reduce.tasks.speculative.execution


说明:是否打开推测执行


默认值:true


hive.input.format


说明:Hive默认的input format


默认值:


org.apache.hadoop.hive.ql.io.CombineHiveInputFormat


如果有问题可以使用org.apache.hadoop.hive.ql.io.HiveInputFormat


hive.exec.counters.pull.interval


说明:Hive与JobTracker拉取counter信息的时间


默认值:1000ms


hive.script.recordreader


说明:使用脚本时默认的读取类


默认值: org.apache.hadoop.hive.ql.exec.TextRecordReader


hive.script.recordwriter


说明:使用脚本时默认的数据写入类


默认值: org.apache.hadoop.hive.ql.exec.TextRecordWriter


hive.mapjoin.check.memory.rows


说明: 内存里可以存储数据的行数


默认值: 100000


hive.mapjoin.smalltable.filesize


说明:输入小表的文件大小的阀值,如果小于该值,就采用普通的join


默认值: 25000000


hive.auto.convert.join


说明:是不是依据输入文件的大小,将Join转成普通的Map Join


默认值: false


hive.mapjoin.followby.gby.localtask.max.memory.usage


说明:map join做group by 操作时,可以使用多大的内存来存储数据,如果数据太大,则不会保存在内存里


默认值:0.55


hive.mapjoin.localtask.max.memory.usage


说明:本地任务可以使用内存的百分比


默认值: 0.90


hive.heartbeat.interval


说明:在进行MapJoin与过滤操作时,发送心跳的时间


默认值1000


hive.merge.size.per.task


说明: 合并后文件的大小


默认值: 256000000


hive.mergejob.maponly


说明: 在只有Map任务的时候 合并输出结果


默认值: true


hive.merge.mapredfiles


默认值: 在作业结束的时候是否合并小文件


说明: false


hive.merge.mapfiles


说明:Map-Only Job是否合并小文件


默认值:true

hive.hwi.listen.host


说明:Hive UI 默认的host


默认值:0.0.0.0

hive.hwi.listen.port


说明:Ui监听端口


默认值:9999


hive.exec.parallel.thread.number


说明:hive可以并行处理Job的线程数


默认值:8


hive.exec.parallel


说明:是否并行提交任务


默认值:false

hive.exec.compress.output


说明:输出使用压缩


默认值: false

hive.mapred.mode


说明: MapReduce的操作的限制模式,操作的运行在该模式下没有什么限制


默认值: nonstrict


hive.join.cache.size


说明: join操作时,可以存在内存里的条数


默认值: 25000


hive.mapjoin.cache.numrows


说明: mapjoin 存在内存里的数据量


默认值:25000


hive.join.emit.interval


说明: 有连接时Hive在输出前,缓存的时间


默认值: 1000

hive.optimize.groupby


说明:在做分组统计时,是否使用bucket table


默认值: true

hive.fileformat.check


说明:是否检测文件输入格式


默认值:true


hive.metastore.client.connect.retry.delay


说明: client 连接失败时,retry的时间间隔


默认值:1秒

hive.metastore.client.socket.timeout


说明: Client socket 的超时时间


默认值:20秒


mapred.reduce.tasks


默认值:-1


说明:每个任务reduce的默认值


-1 代表自动根据作业的情况来设置reduce的值


hive.exec.reducers.bytes.per.reducer


默认值: 1000000000 (1G)


说明:每个reduce的接受的数据量


如果送到reduce的数据为10G,那么将生成10个reduce任务


hive.exec.reducers.max


默认值:999


说明: reduce的最大个数

hive.exec.reducers.max


默认值:999


说明: reduce的最大个数


hive.metastore.warehouse.dir


默认值:/user/hive/warehouse


说明: 默认的数据库存放位置


hive.default.fileformat


默认值:TextFile


说明: 默认的fileformat


hive.map.aggr


默认值:true


说明: Map端聚合,相当于combiner


hive.exec.max.dynamic.partitions.pernode


默认值:100


说明:每个任务节点可以产生的最大的分区数


hive.exec.max.dynamic.partitions


默认值:1000


说明: 默认的可以创建的分区数


hive.metastore.server.max.threads


默认值:100000


说明: metastore默认的最大的处理线程数

hive.metastore.server.min.threads


默认值:200


说明: metastore默认的最小的处理线程数


6 Hive高级编程


6.1 产生背景


为了满足客户个性化的需求,Hive被设计成一个很开放的系统,很多内容都支持用户定制,包括:


文件格式:Text File,Sequence File


内存中的数据格式: Java Integer/String, Hadoop IntWritable/Text


用户提供的 map/reduce 脚本:不管什么语言,利用stdin/stdout 传输数据


1、用户自定义函数


虽然Hive提供了很多函数,但是有些还是难以满足我们的需求。因此Hive提供了自定义函数开发


自定义函数包括三种UDF、UADF、UDTF


UDF(User-Defined-Function)
UDAF(User- Defined Aggregation Funcation)
UDTF(User-DefinedTable-Generating Functions) 用来解决 输入一行输出多行(On-to-many maping) 的需求。


2、HIVE中使用定义的函数的三种方式


在HIVE会话中add 自定义函数的jar文件,然后创建function,继而使用函数


在进入HIVE会话之前先自动执行创建function,不用用户手工创建


把自定义的函数写到系统函数中,使之成为HIVE的一个默认函数,这样就不需要create temporary function。


6.2 UDF


UDF(User-Defined-Function):UDF函数可以直接应用于select语句,对查询结构做格式化处理后,再输出内容。


编写UDF函数的时候需要注意一下几点


A、自定义UDF需要继承org.apache.hadoop.hive.ql.UDF


B、需要实现evaluate函数


C、evaluate函数支持重载


D、UDF只能实现一进一出的操作,如果需要实现多进一出,则需要实现UDAF。


UDF用法代码示例


import org.apache.Hadoop.hive.ql.exec.UDF
public class Helloword extends UDF{
 public Stringevaluate(){
 return"hello world!";
 }
 public Stringevaluate(String str){
 return"hello world: " + str;
 }
}


开发步骤


开发代码


把程序打包放到目标机器上去


进入hive客户端


添加jar包:

hive>add jar/run/jar/udf_test.jar;



创建临时函数:


hive>CREATE TEMPORARY FUNCTION my_add AS'com.hive.udf.Add ‘


查询HQL语句:


SELECT my_add (8, 9) FROM scores;
SELECT my_add (scores.math, scores.art) FROM scores;


销毁临时函数:


hive> DROP TEMPORARY FUNCTION my_add ;


细节


在使用UDF的时候,会自动进行类型转换,例如:


SELECT my_add (8,9.1) FROM scores;


结果是17.1,UDF将类型为Int的参数转化成double。类型的饮食转换是通过UDFResolver来进行控制的


6.3 UDAF


UDAF


Hive查询数据时,有些聚类函数在HQL没有自带,需要用户自定义实现


用户自定义聚合函数: Sum, Average…… n –1


UDAF(User- Defined Aggregation Funcation)


用法


一下两个包是必须的import org.apache.hadoop.hive.ql.exec.UDAF和org.apache.hadoop.hive.ql.exec.UDAFEvaluator


开发步骤


函数类需要继承UDAF类,内部类Evaluator实UDAFEvaluator接口


Evaluator需要实现 init、iterate、terminatePartial、merge、terminate这几个函数


a)init函数实现接口UDAFEvaluator的init函数。


b)iterate接收传入的参数,并进行内部的轮转。其返回类型为boolean。


c)terminatePartial无参数,其为iterate函数轮转结束后,返回轮转数据,terminatePartial类似于hadoop的Combiner。


d)merge接收terminatePartial的返回结果,进行数据merge操作,其返回类型为boolean。


e)terminate返回最终的聚集函数结果。


执行步骤


执行求平均数函数的步骤


a)将java文件编译成Avg_test.jar。


b)进入hive客户端添加jar包:


hive>add jar /run/jar/Avg_test.jar。


c)创建临时函数:


hive>create temporary function avg_test 'hive.udaf.Avg';


d)查询语句:


hive>select avg_test(scores.math) from scores;


e)销毁临时函数:


hive>drop temporary function avg_test;


UDAF代码示例


public class MyAvg extends UDAF {
public static class AvgEvaluator implements UDAFEvaluator {
}
public void init() {}
public boolean iterate(Double o) {}
public AvgState terminatePartial() {}
public boolean terminatePartial(Double o) { }
public Double terminate() {}
}


6.4 UDTF


UDTF:UDTF(User-Defined Table-GeneratingFunctions) 用来解决 输入一行输出多行(On-to-many maping) 的需求。


开发步骤


必须继承org.apache.Hadoop.hive.ql.udf.generic.GenericUDTF


实现initialize, process, close三个方法


UDTF首先会调用initialize方法,此方法返回UDTF的返回行的信息(返回个数,类型),初始化完成后,会调用process方法,对传入的参数进行处理,可以通过forword()方法把结果返回.


最后close()方法调用,对需要清理的方法进行清理


使用方法


UDTF有两种使用方法,一种直接放到select后面,一种和lateral view一起使用


直接select中使用:


select explode_map(properties) as(col1,col2) from src;


不可以添加其他字段使用:


select a, explode_map(properties) as (col1,col2) from src


不可以嵌套调用:

select explode_map(explode_map(properties)) from src


不可以和group by/cluster by/distribute by/sort by一起使用:


select explode_map(properties) as (col1,col2) from src group bycol1, col2


和lateral view一起使用:


select src.id,mytable.col1, mytable.col2 from src lateral view explode_map(properties)mytable as col1, col2;

此方法更为方便日常使用。执行过程相当于单独执行了两次抽取,然后union到一个表里。



lateral view


语法:lateralView: LATERAL VIEW udtf(expression) tableAlias AScolumnAlias (',' columnAlias)* fromClause: FROM baseTable (lateralView)*


LateralView用于UDTF(user-defined table generating functions)中将行转成列,例如explode().


目前Lateral View不支持有上而下的优化。如果使用Where子句,查询可能将不被编译。


解决方法见:在查询之前执行set hive.optimize.ppd=false;


例子


pageAds。它有两个列
string pageid
Array<int> adid_list
" front_page"
[1, 2, 3]
"contact_page "
[ 3, 4, 5]
1
SELECT pageid, adid FROM pageAds LATERAL VIEWexplode(adid_list) adTable AS adid;
将输出如下结果
string pageid int adid
"front_page" 1
…….
“contact_page"3


代码示例


public class MyUDTF extends GenericUDTF{
public StructObjectInspector initialize(ObjectInspector[] args) {}
public void process(Object[] args) throws HiveException { }
}


7 HiveQL


7.1 DDL


1、DDL功能


建表


删除表


修改表结构


创建/删除视图


创建数据库


显示命令


增加分区、删除分区


重命名表


修改列的名字、类型、位置、注释


增加/更新列


增加表的元数据信息


2、建表

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_namedata_type [COMMENT col_comment], ...)]
[COMMENTtable_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]
[ROW FORMATrow_format]
[STORED ASfile_format]
[LOCATIONhdfs_path]


CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXIST 选项来忽略这个异常


EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION)


LIKE 允许用户复制现有的表结构,但是不复制数据


COMMENT可以为表与字段增加描述


ROW FORMAT
DELIMITEDFIELDS TERMINATED BY char
 MAP KEYSTERMINATED BY char
| SERDEserde_name [WITH SERDEPROPERTIES (property_name=property_value,property_name=property_value, ...)]


用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的SerDe,Hive 通过 SerDe 确定表的具体的列的数据。


STORED AS
 SEQUENCEFILE
 |TEXTFILE
 |RCFILE
 |INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname


如果文件数据是纯文本,可以使用 STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCE 。


建立外部表


CREATE EXTERNAL TABLE page_view(viewTime INT, useridBIGINT,
 page_urlSTRING, referrer_url STRING,
 ip STRINGCOMMENT 'IP Address of the User',
 country STRINGCOMMENT 'country of origination')
COMMENT 'This isthe staging page view table'
ROW FORMATDELIMITED FIELDS TERMINATED BY '\054'
STORED AS TEXTFILE
LOCATION'<hdfs_location>';


建分区表


CREATE TABLE par_table(viewTime INT, userid BIGINT,
 page_urlSTRING, referrer_url STRING,
 ip STRINGCOMMENT 'IP Address of the User')
COMMENT 'This isthe page view table'
PARTITIONEDBY(date STRING, pos STRING)
ROW FORMAT DELIMITED ‘\t’
FIELDSTERMINATED BY '\n'
STORED AS SEQUENCEFILE;


建Bucket表


CREATE TABLE par_table(viewTime INT, userid BIGINT,
 page_urlSTRING, referrer_url STRING,
 ip STRINGCOMMENT 'IP Address of the User')
COMMENT 'This isthe page view table'
PARTITIONEDBY(date STRING, pos STRING)
CLUSTEREDBY(userid) SORTED BY(viewTime) INTO 32 BUCKETS
ROW FORMAT DELIMITED‘\t’
FIELDSTERMINATED BY '\n'
STORED AS SEQUENCEFILE;


复制一个空表


CREATE TABLE empty_key_value_store LIKE key_value_store;


删除表


DROP TABLE table_name

增加、删除分区


增加


ALTER TABLE table_name ADD [IF NOT EXISTS] partition_spec[ LOCATION 'location1' ] partition_spec [ LOCATION 'location2' ] ...
 partition_spec:
: PARTITION(partition_col = partition_col_value, partition_col = partiton_col_value, ...)


删除


ALTER TABLE table_name DROP partition_spec,partition_spec,...

重命名表


ALTER TABLE table_name RENAME TO new_table_name


修改列的名字、类型、位置、注释


ALTER TABLE table_name CHANGE [COLUMN] col_old_namecol_new_name column_type COMMENT col_comment


这个命令可以允许改变列名、数据类型、注释、列位置或者它们的任意组合


增加/更新列


ALTER TABLE table_name ADD|REPLACE COLUMNS (col_namedata_type [COMMENT col_comment], ...)


ADD是代表新增一字段,字段位置在所有列后面(partition列前)


REPLACE则是表示替换表中所有字段。


增加表的元数据信息


ALTER TABLE table_name SET TBLPROPERTIES table_propertiestable_properties:
 :[property_name = property_value…..]


用户可以用这个命令向表中增加metadata


改变表文件格式与组织


ALTER TABLE table_name SET FILEFORMAT file_format;
ALTER TABLE table_name CLUSTERED BY(userid) SORTEDBY(viewTime) INTO num_buckets BUCKETS;


这个命令修改了表的物理存储属性


创建/删除视图


CREATE VIEW [IF NOT EXISTS] view_name (column_name[COMMENT column_comment], ...) [TBLPROPERTIES(property_name = property_value, ...)] AS SELECT

增加视图


如果没有提供表名,视图列的名字将由定义的SELECT表达式自动生成


如果修改基本表的属性,视图中不会体现,无效查询将会失败


视图是只读的,不能用

LOAD/INSERT/ALTER
DROP VIEW view_name


删除视图


创建数据库


CREATE DATABASE name

显示命令


show tables;
show databases;
show partitions ;
show functions
describe extended table_name dot col_name


7.2 DML


1、DML功能


向数据表内加载文件


将查询结果插入到Hive表中


0.8新特性 insert into


2、向数据表内加载文件


LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTOTABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]


Load 操作只是单纯的复制/移动操作,将数据文件移动到 Hive 表对应的位置。


filepath


相对路径,例如:project/data1


绝对路径,例如: /user/hive/project/data1


包含模式的完整 URI,例如:


hdfs://namenode:9000/user/hive/project/data1


3、向数据表内加载文件


加载的目标可以是一个表或者分区。如果表包含分区,必须指定每一个分区的分区名


filepath 可以引用一个文件(这种情况下,Hive 会将文件移动到表所对应的目录中)或者是一个目录(在这种情况下,Hive 会将目录中的所有文件移动至表所对应的目录中)

4、LOCAL关键字


指定了LOCAL


load 命令会去查找本地文件系统中的 filepath。如果发现是相对路径,则路径会被解释为相对于当前用户的当前路径。用户也可以为本地文件指定一个完整的 URI,比如:file:///user/hive/project/data1.


load 命令会将 filepath 中的文件复制到目标文件系统中。目标文件系统由表的位置属性决定。被复制的数据文件移动到表的数据对应的位置


没有指定LOCAL


如果 filepath 指向的是一个完整的 URI,hive 会直接使用这个 URI。 否则


如果没有指定 schema 或者 authority,Hive 会使用在 hadoop 配置文件中定义的 schema 和 authority,fs.default.name指定了 Namenode 的 URI


如果路径不是绝对的,Hive 相对于 /user/ 进行解释。 Hive 会将 filepath 中指定的文件内容移动到 table (或者 partition)所指定的路径中


5、OVERWRITE


指定了OVERWRITE


目标表(或者分区)中的内容(如果有)会被删除,然后再将 filepath 指向的文件/目录中的内容添加到表/分区中。


如果目标表(分区)已经有一个文件,并且文件名和 filepath 中的文件名冲突,那么现有的文件会被新文件所替代。



6、将查询结果插入Hive表


将查询结果插入Hive表


将查询结果写入HDFS文件系统


基本模式


INSERT OVERWRITE TABLE tablename1 [PARTITION(partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement


多插入模式


FROM from_statement
INSERT OVERWRITE TABLE tablename1 [PARTITION(partcol1=val1, partcol2=val2 ...)] select_statement1
[INSERT OVERWRITE TABLE tablename2 [PARTITION ...]select_statement2] ...


自动分区模式


INSERT OVERWRITETABLE tablename PARTITION (partcol1[=val1], partcol2[=val2] ...)select_statement FROM from_statement


7、将查询结果写入HDFS文件系统


INSERT OVERWRITE [LOCAL] DIRECTORY directory1 SELECT ...FROM ...
 FROMfrom_statement
 INSERTOVERWRITE [LOCAL] DIRECTORY directory1 select_statement1
 [INSERTOVERWRITE [LOCAL] DIRECTORY directory2 select_statement2]


数据写入文件系统时进行文本序列化,且每列用^A 来区分,\n换行


8、INSERT INTO


INSERT INTO TABLEtablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1FROM from_statement


7.3 HiveQL 查询操作


1、SQL操作


基本的Select 操作


基于Partition的查询


Join


2、基本的Select 操作


SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list [HAVING condition]]
[ CLUSTER BYcol_list
| DISTRIBUTE BYcol_list
]
[LIMIT number]


使用ALL和DISTINCT选项区分对重复记录的处理。默认是ALL,表示查询所有记录。DISTINCT表示去掉重复的记录


Where 条件


类似我们传统SQL的where 条件


目前支持 AND,OR ,0.9版本支持between


IN, NOT IN


不支持EXIST ,NOT EXIST


ORDER BY与SORT BY的不同


ORDER BY 全局排序,只有一个Reduce任务


SORT BY 只在本机做排序


3、Limit


Limit 可以限制查询的记录数


SELECT * FROM t1 LIMIT 5


实现Top k 查询


下面的查询语句查询销售记录最大的 5 个销售代表。


SET mapred.reduce.tasks = 1


SELECT * FROMtest SORT BY amount DESC LIMIT 5


REGEX Column Specification


SELECT 语句可以使用正则表达式做列选择,下面的语句查询除了 ds 和 hr 之外的所有列:


SELECT (ds|hr)?+.+ FROM test


基于Partition的查询


一般 SELECT 查询会扫描整个表,使用PARTITIONED BY 子句建表,查询就可以利用分区剪枝(input pruning)的特性


Hive 当前的实现是,只有分区断言出现在离 FROM 子句最近的那个WHERE 子句中,才会启用分区剪枝


4、Join


Syntax


join_table:


table_referenceJOIN table_factor [join_condition]
| table_reference{LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition
| table_referenceLEFT SEMI JOIN table_reference join_condition
table_reference:
 table_factor
| join_table
table_factor:
 tbl_name[alias]
| table_subqueryalias
| (table_references )
join_condition:
 ONequality_expression ( AND equality_expression )*
equality_expression:
 expression =expression


Hive 只支持等值连接(equality joins)、外连接(outer joins)和(left semi joins)。Hive 不支持所有非等值的连接,因为非等值连接非常难转化到 map/reduce 任务


LEFT,RIGHT和FULL OUTER关键字用于处理join中空记录的情况


LEFT SEMI JOIN 是 IN/EXISTS 子查询的一种更高效的实现


join 时,每次 map/reduce 任务的逻辑是这样的:reducer 会缓存 join 序列中除了最后一个表的所有表的记录,再通过最后一个表将结果序列化到文件系统


实践中,应该把最大的那个表写在最后


5、join 查询时,需要注意几个关键点


只支持等值join


SELECT a.* FROM a JOIN b ON (a.id = b.id)
SELECT a.* FROM a JOIN b
 ON (a.id = b.idAND a.department = b.department)


可以 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 任务


LEFT,RIGHT和FULL OUTER


例子:


SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)


如果你想限制 join 的输出,应该在 WHERE 子句中写过滤条件——或是在 join 子句中写。


容易混淆的问题是表分区的情况


SELECT c.val, d.val FROM c LEFT OUTER JOIN d ON(c.key=d.key)
WHEREa.ds='2010-07-07' AND b.ds='2010-07-07‘


如果 d 表中找不到对应 c 表的记录,d 表的所有列都会列出 NULL,包括ds 列。也就是说,join 会过滤 d 表中不能找到匹配 c 表 join key 的所有记录。这样的话,LEFT OUTER 就使得查询结果与 WHERE 子句无关


解决办法


SELECT c.val, d.val FROM c LEFT OUTER JOIN d
ON (c.key=d.keyAND d.ds='2009-07-07' AND c.ds='2009-07-07')


LEFT SEMI JOIN


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.val
FROM a LEFT SEMIJOIN b on (a.key = b.key)


UNION ALL


用来合并多个select的查询结果,需要保证select中字段须一致


select_statement UNION ALL select_statement UNION ALLselect_statement ...


7.4 从SQL到HiveQL应该转变的几个习惯


1、Hive不支持等值连接


SQL中对两表内联可以写成:


select * from dual a,dual b where a.key = b.key;


Hive中应为


select * from dual a join dual b on a.key = b.key;


2、分号字符


分号是SQL语句结束标记,在HiveQL中也是,但是在HiveQL中,对分号的识别没有那么智慧,例如:


select concat(key,concat(';',key)) from dual;


但HiveQL在解析语句时提示:


FAILED:Parse Error: line 0:-1 mismatched input '<EOF>' expecting ) in functionspecification


解决的办法是,使用分号的八进制的ASCII码进行转义,那么上述语句应写成:


select concat(key,concat('\073',key)) from dual;


3、IS [NOT]NULL


SQL中null代表空值, 值得警惕的是, 在HiveQL中String类型的字段若是空(empty)字符串, 即长度为0, 那么对它进行ISNULL的判断结果是False。


8 Hive Shell操作


8.1 Hive bin下脚本介绍


8.2 Hive Shell 基本操作


1、Hive 命令行


hive [-hiveconf x=y]* [<-ifilename>]* <-f filename>|<-e query-string>
-i 从文件初始化HQL
-e 从命令行执行指定的HQL
-f 执行HQL脚本
-v 输出执行的HQL语句到控制台
-p <port> connect to HiveServer on port number -hiveconf x=y Use this to set hive/hadoop configurationvariables.


Hive 命令行示例


从命令行执行指定的sql语句


$HIVE_HOME/bin/hive -e 'select a.colfrom tab1 a'


以指定的hive环境变量执行指定的sql语句


$HIVE_HOME/bin/hive -e 'select a.colfrom tab1 a' -hiveconf hive.exec.scratchdir=/home/my/hive_scratch -hiveconfmapred.reduce.tasks=32


以沉默模式执行指定的sql语句,并将执行结果导出到指定文件:


HIVE_HOME/bin/hive -e 'select a.col from tab1 a' > a.txt


以非交互式模式执行sql文件


HIVE_HOME/bin/hive -f /home/my/hive-script.sql


在进入交互模式之前,执行初始化sql文件


HIVE_HOME/bin/hive -i /home/my/hive-init.sql


Hive 交互式Shell命令


当命令 $HIVE_HOME/bin/hive以不带 -e/-f 选项的方式运行时, hive将进入到交互模式


以(;)冒号结束命令行

8.3 日志


Hive使用Log4J来处理日志


我们可以通过下面的命令设计Hive的日志级别


$HIVE_HOME/bin/hive -hiveconfhive.root.logger=INFO,console
hive.root.logger的有INFO,DEBUG, 等


8.4 资源


Hive添加资源


Hive可以动态的添加资源,如文件


一般情况下,我们是在与Hive进行交互时添加文件


实际上是使用Hadoop的 Distributed Cache来控制的



例子


ADD { FILE[S] | JAR[S] | ARCHIVE[S]} <filepath1> [<filepath2>]*
LIST { FILE[S] | JAR[S] | ARCHIVE[S]} [<filepath1> <filepath2> ..]
DELETE { FILE[S] | JAR[S] |ARCHIVE[S] } [<filepath1> <filepath2> ..]


9 Hive优化


9.1 Hadoop 计算框架的特性


1、什么是数据倾斜


由于数据的不均衡原因,导致数据分布不均匀,造成数据大量的集中到一点,造成数据热点。


2、Hadoop框架的特性


不怕数据大,怕数据倾斜


jobs数比较多的作业运行效率相对比较低,比如即使有几百行的表,如果多次关联多次汇总,产生十几个jobs,耗时很长。原因是map reduce作业初始化的时间是比较长的


sum,count,max,min等UDAF,不怕数据倾斜问题,hadoop在map端的汇总合并优化,使数据倾斜不成问题


count(distinct ),在数据量大的情况下,效率较低,因为count(distinct)是按group by 字段分组,按distinct字段排序,一般这种分布方式是很倾斜的。

9.2 优化的常用手段


解决数据倾斜问题


减少job数


设置合理的map reduce的task数,能有效提升性能。


了解数据分布,自己动手解决数据倾斜问题是个不错的选择


数据量较大的情况下,慎用count(distinct)。


对小文件进行合并,是行至有效的提高调度效率的方法。


优化时把握整体,单个作业最优不如整体最优。


9.3 Hive的数据类型方面的优化--优化原则


按照一定规则分区(例如根据日期)。通过分区,查询的时候指定分区,会大大减少在无用数据上的扫描, 同时也非常方便数据清理。


合理的设置Buckets。在一些大数据join的情况下,map join有时候会内存不够。如果使用Bucket Map Join的话,可以只把其中的一个bucket放到内存中,内存中原来放不下的内存表就变得可以放下。这需要使用buckets的键进行join的条件连结,并且需要如下设置


set hive.optimize.bucketmapjoin = true


9.4 Hive的操作方面的优化


全排序


怎样做笛卡尔积


怎样决定map个数


怎样决定reducer个数


合并MapReduce操作


Bucket 与sampling


Partition


JOIN


Group By


合并小文件


1、全排序


Hive的排序关键字是SORTBY,它有意区别于传统数据库的ORDER BY也是为了强调两者的区别–SORT BY只能在单机范围内排序。


2、怎样做笛卡尔积


当Hive设定为严格模式(hive.mapred.mode=strict)时,不允许在HQL语句中出现笛卡尔积


MapJoin是的解决办法


MapJoin,顾名思义,会在Map端完成Join操作。这需要将Join操作的一个或多个表完全读入内存


MapJoin的用法是在查询/子查询的SELECT关键字后面添加/*+MAPJOIN(tablelist) */提示优化器转化为MapJoin(目前Hive的优化器不能自动优化MapJoin)


其中tablelist可以是一个表,或以逗号连接的表的列表。tablelist中的表将会读入内存,应该将小表写在这里


在大表和小表做笛卡尔积时,规避笛卡尔积的方法是,给Join添加一个Join key,原理很简单:将小表扩充一列join key,并将小表的条目复制数倍,join key各不相同;将大表扩充一列join key为随机数


3、控制Hive的Map数


通常情况下,作业会通过input的目录产生一个或者多个map任务


主要的决定因素有: input的文件总个数,input的文件大小,集群设置的文件块大小(目前为128M, 可在hive中通过setdfs.block.size;命令查看到,该参数不能自定义修改)


是不是map数越多越好


答案是否定的。如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的map数是受限的


是不是保证每个map处理接近128m的文件块,就高枕无忧了?


答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,


如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。


针对上面的问题3和4,我们需要采取两种方式来解决:即减少map数和增加map数;


是不是保证每个map处理接近128m的文件块,就高枕无忧了?


答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,


如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。


针对上面的问题3和4,我们需要采取两种方式来解决:即减少map数和增加map数;


举例


a) 假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数


b) 假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数


即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块


4、怎样决定reducer个数


Hadoop MapReduce程序中,reducer个数的设定极大影响执行效率


不指定reducer个数的情况下,Hive会猜测确定一个reducer个数,基于以下两个设定:


参数1:hive.exec.reducers.bytes.per.reducer(默认为1G)


参数2 :hive.exec.reducers.max(默认为999)


计算reducer数的公式


N=min(参数2,总输入数据量/参数1)


依据Hadoop的经验,可以将参数2设定为0.95*(集群中TaskTracker个数)


reduce个数并不是越多越好


同map一样,启动和初始化reduce也会消耗时间和资源;


另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题


什么情况下只有一个reduce


很多时候你会发现任务中不管数据量多大,不管你有没有设置调整reduce个数的参数,任务中一直都只有一个reduce任务;


其实只有一个reduce任务的情况,除了数据量小于


hive.exec.reducers.bytes.per.reducer参数值的情况外,还有以下原因:


a) 没有group by的汇总


b) 用了Order by


5、合并 MapReduce操作


Multi-group by


Multi-group by是Hive的一个非常好的特性,它使得Hive中利用中间结果变得非常方便


FROM log


insert overwrite table test1 select log.id group by log.id
insert overwrite table test2select log.name group by log.name


上述查询语句使用了Multi-group by特性连续group by了2次数据,使用不同的groupby key。这一特性可以减少一次MapReduce操作。


6、Bucket 与 Sampling


Bucket是指将数据以指定列的值为key进行hash,hash到指定数目的桶中。这样就可以支持高效采样了


Sampling可以在全体数据上进行采样,这样效率自然就低,它还是要去访问所有数据。而如果一个表已经对某一列制作了bucket,就可以采样所有桶中指定序号的某个桶,这就减少了访问量。


如下例所示就是采样了test中32个桶中的第三个桶。


SELECT * FROM test 、、、TABLESAMPLE(BUCKET 3 OUT OF 32);


7、JOIN 原则


在使用写有 Join 操作的查询语句时有一条原则:应该将条目少的表/子查询放在 Join 操作符的左边


原因是在 Join 操作的 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生 OOM 错误的几率。


8、Map Join


Join 操作在 Map阶段完成,不再需要Reduce,前提条件是需要的数据在 Map的过程中可以访问到


例如:


INSERT OVERWRITE TABLE phone_traffic
SELECT /*+MAPJOIN(phone_location) */ l.phone,p.location,l.traffic from phone_location p join log l on(p.phone=l.phone)


相关的参数为:


hive.join.emit.interval = 1000How many rows in the right-most join operand Hive should buffer before emittingthe join result.
hive.mapjoin.size.key = 10000
hive.mapjoin.cache.numrows =10000


9、Group By


Map 端部分聚合


并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在 Map 端进行部分聚合,最后在 Reduce 端得出最终结果


基于 Hash


参数包括:


hive.map.aggr = true 是否在 Map 端进行聚合,默认为 True


hive.groupby.mapaggr.checkinterval =100000 在 Map 端进行聚合操作的条目数目


有数据倾斜的时候进行负载均衡


hive.groupby.skewindata = false


当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group ByKey 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。


10、合并小文件


文件数目过多,会给 HDFS 带来压力,并且会影响处理效率,可以通过合并 Map 和 Reduce 的结果文件来消除这样的影响:


hive.merge.mapfiles = true 是否和并 Map 输出文件,默认为 True
hive.merge.mapredfiles = false 是否合并 Reduce 输出文件,默认为 False
hive.merge.size.per.task =25610001000 合并文件的大小


10 Hive体系架构


10.1 概念


用户接口:用户访问Hive的入口


元数据:Hive的用户信息与表的MetaData


解释器:分析翻译HQL的组件


编译器:编译HQL的组件


优化器:优化HQL的组件


10.2 Hive架构与基本组成


1、架构图


2、基本组成


用户接口,包括 CLI,JDBC/ODBC,WebUI


元数据存储,通常是存储在关系数据库如 mysql, derby 中


解释器、编译器、优化器、执行器


Hadoop:用HDFS 进行存储,利用 MapReduce 进行计算


3、各组件的基本功能


用户接口主要有三个:CLI,JDBC/ODBC和 WebUI


CLI,即Shell命令行


JDBC/ODBC 是Hive 的JAVA,与使用传统数据库JDBC的方式类似


WebGUI是通过浏览器访问 Hive


Hive 将元数据存储在数据库中,目前只支持 mysql、derby,下一版本会支持更多的数据库。


Hive 中的元数据包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),表的数据所在目录等


解释器、编译器、优化器完成 HQL 查询语句从词法分析、语法分析、编译、优化以及查询计划的生成。


生成的查询计划存储在 HDFS 中,并在随后有 MapReduce 调用执行


Hive 的数据存储在HDFS 中,大部分的查询由 MapReduce 完成(包含* 的查询,比如 select * from table 不会生成 MapRedcue 任务)


4、Metastore


Metastore是系统目录(catalog)用于保存Hive中所存储的表的元数据(metadata)信息


Metastore是Hive被用作传统数据库解决方案(如oracle和db2)时区别其它类似系统的一个特征


Metastore包含如下的部分:


Database 是表(table)的名字空间。默认的数据库(database)名为‘default’


Table 表(table)的原数据包含信息有:列(list of columns)和它们的类型(types),拥有者(owner),存储空间(storage)和SerDei信息


Partition 每个分区(partition)都有自己的列(columns),SerDe和存储空间(storage)。这一特征将被用来支持Hive中的模式演变(schema evolution)


5、Compiler


Driver调用编译器(compiler)处理HiveQL字串,这些字串可能是一条DDL、DML或查询语句


编译器将字符串转化为策略(plan)


策略仅由元数据操作和HDFS操作组成,元数据操作只包含DDL语句,HDFS操作只包含LOAD语句


对插入和查询而言,策略由map-reduce任务中的具有方向的非循环图(directedacyclic graph,DAG)组成


10.3 Hive运行模式


Hive的运行模式即任务的执行环境 分为 本地 与 集群两种


我们可以通过mapred.job.tracker 来指明


设置方式:hive > SET mapred.job.tracker=local


10.4 数据类型


1、原始数据类型


Integers:TINYINT - 1 byte、SMALLINT - 2 byte、INT - 4 byte、BIGINT - 8 byte
Boolean type:BOOLEAN - TRUE/FALSE
Floating point numbers:FLOAT –单精度、DOUBLE – 双精度
String type:STRING - sequence of charactersin a specified character set


2、复杂数据类型


Structs: 例子 {c INT; d INT}


Maps (key-value tuples):. 例子'group' ->gid M['group']


Arrays (indexable lists): 例子[‘1', ‘2', ‘3']


TIMESTAMP 0.8版本新加属性


10.5 Hive的元数据存储

1、存储方式与模式


Hive将元数据存储在数据库中


连接到数据库模式有三种


单用户模式


多用户模式


远程服务器模式


2、单用户模式


此模式连接到一个 In-memory 的数据库 Derby ,一般用于 Unit Test


10.6 Hive的数据存储


1、Hive数据存储的基本概念


Hive的数据存储是建立在Hadoop HDFS之上的


Hive没有专门的数据存储格式


存储结构主要包括:数据库、文件、表、视图


Hive默认可以直接加载文本文件,还支持sequence file 、RCFile


创建表时,我们直接告诉Hive数据的列分隔符与行分隔符,Hive即可解析数据


2、Hive的数据模型-数据库

类似传统数据库的DataBase


在第三方数据库里实际是一张表


简单示例:命令行hive > create database test_database;


3、内部表


与数据库中的 Table 在概念上是类似


每一个 Table 在 Hive 中都有一个相应的目录存储数据


例如,一个表 test,它在 HDFS 中的路径为:/warehouse /test


warehouse是在 hive-site.xml 中由 ${hive.metastore.warehouse.dir}指定的数据仓库的目录


所有的 Table 数据(不包括 External Table)都保存在这个目录中。


删除表时,元数据与数据都会被删除


4、内部表简单示例


创建数据文件


test_inner_table.txt


创建表


create table test_inner_table (key string)


加载数据


LOAD DATA LOCAL INPATH ‘filepath’ INTO TABLE test_inner_table


查看数据


select * from test_inner_table
select count(*) from test_inner_table


删除表


drop table test_inner_table


5、分区表


Partition 对应于数据库中的 Partition 列的密集索引


在 Hive 中,表中的一个 Partition 对应于表下的一个目录,所有的 Partition 的数据都存储在对应的目录中


例如:test表中包含 date 和position 两个 Partition,则对应于 date= 20120801, position = zh 的 HDFS 子目录为:/ warehouse /test/date=20120801/ position =zh


对应于 = 20100801, position = US 的HDFS 子目录为;/ warehouse/xiaojun/date=20120801/ position =US

6、分区表简单示例


创建数据文件test_partition_table.txt


创建表

create table test_partition_table (key string) partitioned by (dtstring)


加载数据


LOAD DATA INPATH ‘filepath’ INTO TABLE test_partition_tablepartition (dt=‘2006’)


查看数据


select * from test_partition_table
select count(*) from test_partition_table


删除表


drop table test_partition_table


7、外部表


指向已经在 HDFS 中存在的数据,可以创建 Partition


它和 内部表 在元数据的组织上是相同的,而实际数据的存储则有较大的差异


内部表 ** 的创建过程和数据加载过程(这两个过程可以在同一个语句中完成),在加载数据的过程中,实**


际数据会被移动到数据仓库目录中;之后对数据对访问将会直接在数据仓库目录中完成。删除表时,表


中的数据和元数据将会被同时删除


外部表 **只有一个过程,加载数据和创建表同时完成,并不会移动到数据仓库目录中,只是与外部数据**


建**立一个链接。当删除一个外部表 时,仅删除该链接**


8、外部表简单示例


创建数据文件test_external_table.txt


创建表


create external table test_external_table (key string)


加载数据


LOAD DATA INPATH ‘filepath’ INTO TABLE test_inner_table


查看数据


select * from test_external_table
select count(*) from test_external_table


删除表


drop table test_external_table


9、Bucket Table(桶表)


可以将表的列通过Hash算法进一步分解成不同的文件存储


例如:将age列分散成20个文件,首先要对AGE进行Hash计算,对应为0的写入/warehouse/test/date=20120801/postion=zh/part-00000,对应为1的写入/warehouse/test/date=20120801/postion=zh/part-00001


如果想应用很多的Map任务这样是不错的选择


10、Bucket Table简单示例


创建数据文件test_bucket_table.txt


创建表


create table test_bucket_table (key string)
 clustered by (key)into 20 buckets


加载数据


LOAD DATA INPATH ‘filepath’ INTO TABLE test_bucket_table


查看数据


select * from test_bucket_table
set hive.enforce.bucketing = true;


11、Hive的数据模型-视图


视图与传统数据库的视图类似


视图是只读的


视图基于的基本表,如果改变,指增加不会影响视图的呈现;如果删除,会出现问题


如果不指定视图的列,会根据select语句后的生成


示例


create view test_view as select * from test


10.7 Hive的数据存储


配置步骤:


hive-site.xml 添加


<property>
 <name>hive.hwi.war.file</name>
 <value>lib/hive-hwi-0.8.1.war</value>
</property>


启动Hive的UI sh $HIVE_HOME/bin/hive --service hwi


11 Hive原理


11.1 Hive原理


1、什么要学习Hive的原理


一条Hive HQL将转换为多少道MR作业


怎么样加快Hive的执行速度


2.编写Hive HQL的时候我们可以做什么


Hive 怎么将HQL转换为MR作业


Hive会采用什么样的优化方式


3、Hive执行流程


编译器将一个Hive QL转换操作符


操作符是Hive的最小的处理单元


每个操作符代表HDFS的一个操作或者一道MapReduce作业


4、Operator


Operator都是hive定义的一个处理过程


Operator都定义有:


protected List <Operator<? extends Serializable >> childOperators;
protected List <Operator<? extends Serializable >> parentOperators;
protected boolean done; // 初始化值为false


所有的操作构成了 Operator图,hive正是基于这些图关系来处理诸如limit, group by, join等操作。


5、Hive执行流程


b8f1d4344e91c5b177e55d657efe6e4.png


Hive通过ExecMapper和ExecReducer执行MapReduce任务


在执行MapReduce时有两种模式


本地模式


分布式模式


6、ANTLR词法语法分析工具


ANTLR—Another Tool for Language Recognition


ANTLR 是开源的


为包括Java,C++,C#在内的语言提供了一个通过语法描述来自动构造自定义语言的识别器(recognizer),编译器(parser)和解释器(translator)的框架


Hibernate就是使用了该分析工具


11.2 一条HQL引发的思考

1、案例HQL


select key from test_limit limit 1
Stage-1
TableScan Operator>Select Operator-> Limit->File OutputOperator
Stage-0
Fetch Operator
读取文件


2、Mapper与InputFormat


该hive MR作业中指定的mapper是:


mapred.mapper.class = org.apache.hadoop.hive.ql.exec.ExecMapper


input format是:


hive.input.format =
org.apache.hadoop.hive.ql.io.CombineHiveInputFormat


该hive MR作业中指定的mapper是:


mapred.mapper.class = org.apache.hadoop.hive.ql.exec.ExecMapper


input format是:


hive.input.format =
org.apache.hadoop.hive.ql.io.CombineHiveInputFormat


相关实践学习
lindorm多模间数据无缝流转
展现了Lindorm多模融合能力——用kafka API写入,无缝流转在各引擎内进行数据存储和计算的实验。
云数据库HBase版使用教程
&nbsp; 相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情:&nbsp;https://cn.aliyun.com/product/hbase &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3月前
|
分布式计算 Java Hadoop
java使用hbase、hadoop报错举例
java使用hbase、hadoop报错举例
121 4
|
2月前
|
分布式计算 Hadoop Shell
Hadoop-35 HBase 集群配置和启动 3节点云服务器 集群效果测试 Shell测试
Hadoop-35 HBase 集群配置和启动 3节点云服务器 集群效果测试 Shell测试
80 4
|
2月前
|
SQL 分布式计算 Hadoop
Hadoop-37 HBase集群 JavaAPI 操作3台云服务器 POM 实现增删改查调用操作 列族信息 扫描全表
Hadoop-37 HBase集群 JavaAPI 操作3台云服务器 POM 实现增删改查调用操作 列族信息 扫描全表
38 3
|
2月前
|
分布式计算 Hadoop Shell
Hadoop-36 HBase 3节点云服务器集群 HBase Shell 增删改查 全程多图详细 列族 row key value filter
Hadoop-36 HBase 3节点云服务器集群 HBase Shell 增删改查 全程多图详细 列族 row key value filter
60 3
|
2月前
|
SQL 分布式计算 Hadoop
Hadoop-34 HBase 安装部署 单节点配置 hbase-env hbase-site 超详细图文 附带配置文件
Hadoop-34 HBase 安装部署 单节点配置 hbase-env hbase-site 超详细图文 附带配置文件
100 2
|
2月前
|
存储 分布式计算 Hadoop
Hadoop-33 HBase 初识简介 项目简介 整体架构 HMaster HRegionServer Region
Hadoop-33 HBase 初识简介 项目简介 整体架构 HMaster HRegionServer Region
61 2
|
2月前
|
SQL 存储 分布式计算
Hive和Pig的区别是什么?如何选择?
【10月更文挑战第9天】Hive和Pig的区别是什么?如何选择?
50 0
|
6月前
|
存储 分布式计算 Hadoop
Hadoop节点文件存储HBase设计目的
【6月更文挑战第2天】
68 6
|
6月前
|
存储 分布式计算 Hadoop
Hadoop节点文件存储Hbase高可靠性
【6月更文挑战第2天】
110 2
|
6月前
|
存储 分布式计算 Hadoop
Hadoop节点文件存储Hbase面向列
【6月更文挑战第2天】
49 2