`
solitary
  • 浏览: 73894 次
社区版块
存档分类
最新评论

写好Hive 程序的五个提示

    博客分类:
  • hive
阅读更多

原文引自:http://www.tbdata.org/archives/622

 

使用Hive可以高效而又快速地编写复杂的MapReduce查询逻辑。但是某些情况下,因为不熟悉数据特性,或没有遵循Hive的优化约定,Hive计算任务会变得非常低效,甚至无法得到结果。一个”好”的Hive程序仍然需要对Hive运行机制有深入的了解。

有一些大家比较熟悉的优化约定包括:Join中需要将大表写在靠右的位置;尽量使用UDF而不是transfrom……诸如此类。下面讨论5个性能和逻辑相关的问题,帮助你写出更好的Hive程序。

全排序

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

CREATE TABLE if not exists t_order(  id int, -- 订单编号  sale_id int, -- 销售ID  customer_id int, -- 客户ID  product _id int, -- 产品ID  amount int -- 数量  ) PARTITIONED BY (ds STRING);

在表中查询所有销售记录,并按照销售ID和数量排序:

set mapred.reduce.tasks=2;  Select sale_id, amount from t_order  Sort by sale_id, amount;

这一查询可能得到非期望的排序。指定的2reducer分发到的数据可能是(各自排序):

Reducer1

Sale_id | amount  0 | 100  1 | 30  1 | 50  2 | 20

Reducer2

Sale_id | amount  0 | 110  0 | 120  3 | 50  4 | 20

因为上述查询没有reduce keyhive会生成随机数作为reduce key。这样的话输入记录也随机地被分发到不同reducer机器上去了。为了保证reducer之间没有重复的sale_id记录,可以使用DISTRIBUTE BY关键字指定分发keysale_id。改造后的HQL如下:

set mapred.reduce.tasks=2;  Select sale_id, amount from t_order  Distribute by sale_id  Sort by sale_id, amount;

这样能够保证查询的销售记录集合中,销售ID对应的数量是正确排序的,但是销售ID不能正确排序,原因是hive使用hadoop默认的HashPartitioner分发数据。

这就涉及到一个全排序的问题。解决的办法无外乎两种:

1.) 不分发数据,使用单个reducer

set mapred.reduce.tasks=1;

这一方法的缺陷在于reduce端成为了性能瓶颈,而且在数据量大的情况下一般都无法得到结果。但是实践中这仍然是最常用的方法,原因是通常排序的查询是为了得到排名靠前的若干结果,因此可以用limit子句大大减少数据量。使用limit n后,传输到reduce端(单机)的数据记录数就减少到n* map个数)。

2.) 修改Partitioner,这种方法可以做到全排序。这里可以使用Hadoop自带的TotalOrderPartitioner(来自于Yahoo!TeraSort项目),这是一个为了支持跨reducer分发有序数据开发的Partitioner,它需要一个SequenceFile格式的文件指定分发的数据区间。如果我们已经生成了这一文件(存储在/tmp/range_key_list,分成100reducer),可以将上述查询改写为

set mapred.reduce.tasks=100;  set hive.mapred.partitioner=org.apache.hadoop.mapred.lib.TotalOrderPartitioner;  set total.order.partitioner.path=/tmp/ range_key_list;  Select sale_id, amount from t_order  Cluster by sale_id  Sort by amount;

有很多种方法生成这一区间文件(例如hadoop自带的o.a.h.mapreduce.lib.partition.InputSampler工具)。这里介绍用Hive生成的方法,例如有一个按id有序的t_sale表:

CREATE TABLE if not exists t_sale (  id int,  name string,  loc string  );

则生成按sale_id分发的区间文件的方法是:

create external table range_keys(sale_id int)  row format serde  'org.apache.hadoop.hive.serde2.binarysortable.BinarySortableSerDe'  stored as  inputformat  'org.apache.hadoop.mapred.TextInputFormat'  outputformat  'org.apache.hadoop.hive.ql.io.HiveNullValueSequenceFileOutputFormat'  location '/tmp/range_key_list';     insert overwrite table range_keys  select distinct sale_id  from source t_sale sampletable(BUCKET 100 OUT OF 100 ON rand()) s  sort by sale_id;

生成的文件(/tmp/range_key_list目录下)可以让TotalOrderPartitionersale_id有序地分发reduce处理的数据。区间文件需要考虑的主要问题是数据分发的均衡性,这有赖于对数据深入的理解。

怎样做笛卡尔积?

Hive设定为严格模式(hive.mapred.mode=strict)时,不允许在HQL语句中出现笛卡尔积,这实际说明了Hive对笛卡尔积支持较弱。因为找不到Join keyHive只能使用1reducer来完成笛卡尔积。

当然也可以用上面说的limit的办法来减少某个表参与join的数据量,但对于需要笛卡尔积语义的需求来说,经常是一个大表和一个小表的Join操作,结果仍然很大(以至于无法用单机处理),这时MapJoin才是最好的解决办法。

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

MapJoin的用法是在查询/子查询的SELECT关键字后面添加/*+ MAPJOIN(tablelist) */提示优化器转化为MapJoin(目前Hive的优化器不能自动优化MapJoin)。其中tablelist可以是一个表,或以逗号连接的表的列表。tablelist中的表将会读入内存,应该将小表写在这里。

PS:有用户说MapJoin在子查询中可能出现未知BUG。在大表和小表做笛卡尔积时,规避笛卡尔积的方法是,给Join添加一个Join key,原理很简单:将小表扩充一列join key,并将小表的条目复制数倍,join key各不相同;将大表扩充一列join key为随机数。

怎样写exist in子句?

Hive不支持where子句中的子查询,SQL常用的exist in子句需要改写。这一改写相对简单。考虑以下SQL查询语句:

SELECT a.key, a.value  FROM a  WHERE a.key in  (SELECT b.key  FROM B);

可以改写为

SELECT a.key, a.value  FROM a LEFT OUTER JOIN b ON (a.key = b.key)  WHERE b.key <> NULL;

一个更高效的实现是利用left semi join改写为:

SELECT a.key, a.val  FROM a LEFT SEMI JOIN b on (a.key = b.key);

left semi join0.5.0以上版本的特性。

Hive怎样决定reducer个数?

Hadoop MapReduce程序中,reducer个数的设定极大影响执行效率,这使得Hive怎样决定reducer个数成为一个关键问题。遗憾的是Hive的估计机制很弱,不指定reducer个数的情况下,Hive会猜测确定一个reducer个数,基于以下两个设定:

1. hive.exec.reducers.bytes.per.reducer(默认为1000^3

2. hive.exec.reducers.max(默认为999

计算reducer数的公式很简单:

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

通常情况下,有必要手动指定reducer个数。考虑到map阶段的输出数据量通常会比输入有大幅减少,因此即使不设定reducer个数,重设参数2还是必要的。依据Hadoop的经验,可以将参数2设定为0.95*(集群中TaskTracker个数)

 

合并MapReduce操作

Multi-group by

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

FROM (SELECT a.status, b.school, b.gender  FROM status_updates a JOIN profiles b  ON (a.userid = b.userid and  a.ds='2009-03-20' )  ) subq1  INSERT OVERWRITE TABLE gender_summary  PARTITION(ds='2009-03-20')  SELECT subq1.gender, COUNT(1) GROUP BY subq1.gender  INSERT OVERWRITE TABLE school_summary  PARTITION(ds='2009-03-20')  SELECT subq1.school, COUNT(1) GROUP BY subq1.school 

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

 

Multi-distinct

Multi-distinct是淘宝开发的另一个multi-xxx特性,使用Multi-distinct可以在同一查询/子查询中使用多个distinct,这同样减少了多次MapReduce操作。

分享到:
评论

相关推荐

    写好Hive程序的五个提示,淘宝数据平台团队

    标题中提到的“写好Hive程序的五个提示”指向了在大数据领域内使用Hive语言编写的程序优化和最佳实践。Hive作为一个建立在Hadoop之上的数据仓库工具,可以将SQL语句转换为MapReduce任务进行执行,非常适合处理大数据...

    数据库工具连接hive的驱动包

    在IT行业中,数据库管理和分析是至关重要的任务,而Hive作为一个大数据处理的仓库系统,它提供了对结构化数据的查询和分析能力。当需要通过图形化的数据库管理工具,如DBeaver,与Hive进行交互时,就需要用到特定的...

    hive 驱动包 hive 链接 datagrip的驱动包

    在大数据处理领域,Hive...Hive JDBC驱动程序允许Java应用程序通过JDBC接口与Hive通信,这使得像DataGrip这样的工具能够无缝地与Hive交互。掌握这些知识和步骤,你就可以更便捷地管理和分析存储在Hadoop上的大数据了。

    DataGrip连接Hive所需jar包

    这个文件可能包含Apache Hive的Java驱动程序,使得DataGrip能够理解并执行HQL语句。 在Hadoop生态系统中,Hive是构建在HDFS(Hadoop分布式文件系统)之上,提供了一种结构化的数据处理方式。它将数据存储在HDFS中,...

    tools_hive-hwi

    2. **Hive-HWI介绍**:Hive-HWI是一个轻量级的Web应用程序,它提供了一个图形化界面,用户可以在这个界面上创建Hive表、执行HQL查询、查看查询结果等,极大地提高了用户的交互体验。 3. **安装Hive-HWI**:首先,你...

    SQuirrel SQL Client配置hive驱动

    5. **测试连接**:点击“Test Connection”按钮,如果配置正确,你应该能看到“Connection successful”的提示。 6. **连接Hive**:确认连接成功后,点击“Connect”按钮,SQuirrel SQL Client将连接到Hive服务器,...

    使用IDEA工具连接CDH集群里面的hive组件

    完成以上步骤后,你的IDEA项目就配置好了连接CDH集群中Hive组件的能力,可以编写Java程序执行Hive查询,进行大数据分析工作。记得在实际操作时,确保集群的网络安全设置允许从你的开发机器访问,并且配置文件正确...

    FineBI连接hive所需要的连接驱动

    在大数据分析领域,Hive是一个基于Hadoop的数据仓库工具,它可以将结构化的数据文件映射为一张数据库表,并提供SQL查询功能,使得分析师能够通过SQL语句对存储在Hadoop集群上的大规模数据进行处理和分析。...

    hive安装文档

    ### Hive安装知识点详解 #### 一、Hive简介与安装目的 Hive 是基于 Hadoop 的数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的 SQL 查询功能,可以将 SQL 语句转换为 MapReduce 任务进行运行...

    Hive-ODBC-x86-x64安装包

    总之,Hive ODBC驱动程序为Windows用户提供了便利的数据接入途径,使得Hadoop生态中的Hive数据仓库能够更好地服务于数据分析和业务决策,实现大数据的充分利用。无论是数据科学家、分析师还是业务人员,都能从中受益...

    Apache Hive 中文手册.docx

    Apache Hive 是一个构建在Hadoop生态系统之上的数据仓库工具,其设计目的是为了简化对大量分布式存储数据的管理和分析。Hive 提供了SQL(结构化查询语言)接口,使得非编程背景的用户也能轻松地对大数据进行操作。...

    hadoop的数据仓库hive手册

    - 当出现 `Hive&gt;` 提示符时,表示 Hive 已成功启动,可以开始使用。 #### 五、Hive 的资源和支持 对于更深入的学习和使用,以下是一些有用的资源链接: - **Facebook 镜像**: [...

    CDH550@hive 使用及操作说明

    总之,Hive作为一个强大的数据仓库工具,在CDH 5.5.0环境中提供了丰富的功能和灵活性。通过对Hive的基本使用和高级特性有了深入理解之后,用户可以更有效地利用Hadoop集群来管理和分析大规模的数据集。

    cloudera-hive/impala-odbc

    安装这两个驱动后,用户可以通过Tableau或其他支持ODBC的应用程序,如Excel、Python等,轻松地连接到Hadoop集群中的Hive或Impala服务,执行SQL查询并获取结果。 在实际操作中,安装这些驱动通常包括以下步骤: 1. ...

    hive2-jdbc:Hive JDBC连接示例,包括简单和kerberos身份验证方法

    JDBC API v3.x支持JRE v4.0或v5.0 JDBC API v4.x支持JRE v6.0或更高版本JDBC API v4.1.x支持JRE v7.0或更高版本适用于Apache Hive的Cloudera JDBC驱动程序支持Hive 0.11、0.12、0.13、0.14、1.0和1.1。 有关更多...

    WP Hive-crx插件

    语言:English (United States) 在WordPress.ORG中显示插件报告 ...该扩展程序还提供了一个选项,可以重定向到特定插件的WP Hive插件页面。 当然,WordPress存储库很棒,但是WP Hive通过更好的洞察力使其更加

    PyPI 官网下载 | hive_builder-1.1.3.tar.gz

    标签“Python库”提示我们,`hive_builder`是一个Python编程语言的软件包,可能提供与Hadoop Hive相关的功能,如创建Hive表、执行HQL查询、管理Hive元数据等。Python库通常通过`setup.py`文件进行安装,开发者可以...

    hivejar.zip

    这个JAR文件是用于Kettle连接Hive的驱动程序,使得Kettle能够与Hive进行通信,执行查询和数据操作。这里的"1.1.0"是Hive的版本号,而"cdh5.16.2"则指的是Cloudera Data Hub (CDH)的一个特定版本,CDH是一个流行的...

    hivesystem:构建和连接极其灵活、可重用的 Python 组件的框架 hive 系统可用于可视化编程、大型 3D 应用程序、游戏逻辑和科学协议

    Python 组件的框架 hive 系统可用于可视化编程、大型 3D 应用程序、游戏逻辑和科学协议当前待办事项启用从 Hive GUI 导出/导入 hivemaps [完成] 尽可能镜像现有的 Logic Brick 支持为工作人员实施工具提示简化 ...

Global site tag (gtag.js) - Google Analytics