原文:
towardsdatascience.com/must-know-techniques-for-handling-big-data-in-hive-fa70e020141d
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8e9346e3b89821d60f53b5e7dab035a0.png
图片由 Christopher Gower 在 Unsplash 上提供
在大多数科技公司中,数据团队必须具备强大的管理和处理大数据的能力。因此,对这些团队来说,熟悉 Hadoop 生态系统是必不可少的。Apache 开发的 Hive 查询语言(HQL)是数据专业人士在 Hadoop 生态系统中操纵、查询、转换和分析数据的强大工具。
HQL 提供了一个类似 SQL 的接口,使得在 Hadoop 中进行数据处理对广泛的用户既易于访问又用户友好。如果你已经精通 SQL,你可能会发现过渡到 HQL 并不困难。然而,需要注意的是,HQL 包含许多独特的函数和特性,这些在标准 SQL 中是不可用的。在这篇文章中,我将根据我的先前经验探讨一些关键的 HQL 函数和特性,这些需要超出 SQL 的特定知识。理解和利用这些能力对于任何使用 Hive 和大数据的人来说至关重要,因为它们构成了在 Hadoop 生态系统中构建可扩展和高效数据处理管道和分析系统的基石。为了说明这些概念,我将提供带有模拟数据和相应的 HQL 语法的用例,以展示如何有效地应用这些特性。
PARTITIONED BY
让我们想象一家电子商务公司需要每天更新其销售数据。如果所有数据都存储在一个未分区的单一数据集中,几个月后表可能会变得非常大,这会显著降低查询性能。
Apache Hive 使用PARTITIONED BY子句来创建分区表,允许查询跳过无关的数据子集,从而提高效率。
在这个例子中,我首先创建了一个名为ecom_sales的表,该表包括SKU_id列——每个 SKU 的唯一标识符,units_sold列——特定 SKU 的销售单位数,以及price_USD列——每单位的价格。该表还包括一个分区列ymd。接下来,我在ymd = 20240801的分区中插入值。最后,我查询了这个分区中的所有数据。
--Create a partitioned tableforsales CREATE TABLE IF NOT EXISTS ecom_sales(SKU_id STRING,unit_sold INT,price_USD DOUBLE)PARTITIONED BY(ymd INT)STORED AS PARQUET;--Insert data into the partitioned table dated August 1st,2024INSERT INTO ecom_sales PARTITION(ymd=20240801)VALUES('S0002D',5,15.99),('S0002D',6,15.99),('S0001D',12,7.99),('S0003D',10,21.50),('S0001D',9,7.99),('S0001D',10,7.99);--Queryalldatafromthe partition table dated August 1st,2024SELECT*FROM ecom_sales WHERE ymd=20240801;在 Hive 中,分区无疑通过避免全表扫描来提高查询速度。它还使得定位和修改特定记录变得更加容易。通过分区,你可以通过在非重叠分区上运行操作(如UPDATE和DELETE)来防止并发问题。
然而,对小文件问题保持谨慎是很重要的。最好是创建 100 个每个 1GB 的分区,而不是 10,000 个每个 0.01GB 的分区。小文件可能会引起几个问题:
·查询性能降低:大量分区会增加 Hive 元数据处理的负担,从而减慢查询规划和执行速度。Hadoop 的分布式处理针对大文件进行了优化,而小文件可能导致过度的磁盘 I/O、网络开销和不必要的 MapReduce 任务。
·浪费的存储空间:在 HDFS 中,每个文件,无论其大小如何,都占用一个完整的存储块,通常是 128 MB 或 256 MB。小文件会导致存储空间使用效率低下。
·管理挑战:管理大量小文件会使得优化、数据合并、压缩和平衡等任务变得复杂,使得维护更加困难。
存储为
Hive 使用STORED AS子句来指定表存储的文件格式。文件格式的选择可以显著影响查询性能和存储效率。
在前面的PARTITIONED BY子句部分,我创建了一个名为ecom_sales的分区表,并存储为 PARQUET 格式。
--Create a partitioned tableforsaleswithfileformatPARQUET CREATE TABLE IF NOT EXISTS ecom_sales(SKU_id STRING,unit_sold INT,price_USD DOUBLE)PARTITIONED BY(ymd INT)STORED AS PARQUET;除了 PARQUET 之外,Hive 还支持几种其他文件格式:
PARQUET:一种针对分析工作负载和复杂查询优化的列式存储格式。
ORC(优化行列式):由于其高压缩率和快速的读写性能,非常适合写密集型工作负载和事务处理。
AVRO:一种基于行的格式,支持结构化和非结构化数据,使其适合于模式演变。
TEXTFILE:用于纯文本的格式,通常用于 CSV 或 TSV 文件。如果没有指定,它是默认格式。
JSONFILE:用于存储 JSON 格式的数据。
除了这五种常用的格式之外,Hive 还支持其他格式,例如:SEQUENCEFILE(由二进制键/值对组成的平面文件),RCFILE(记录列式文件),INPUTFORMAT和OUTPUTFORMAT用于自定义文件格式和可指定压缩的压缩格式。
在 Hive 中创建新表时,选择适当的格式对于确保高效的数据摄取、存储、查询和处理至关重要。
分布 BY / 聚合 BY
Hive 使用 DISTRIBUTE BY 子句将行分布到 reducer 中。
SET mapreduce.job.reduces=2;SELECT*FROM ecom_sales WHERE ymd=20240801DISTRIBUTE by SKU_id;在上面的示例中,我将 reducer 的数量设置为 2。在应用DISTRIBUTE BY子句后,所有具有相同SKU_id的行将由同一个 reducer 处理,而不同的SKU_id值可能会被发送到不同的 reducer。例如,具有SKU_idS0001D的行将进入一个 reducer,S0002D进入另一个 reducer,而‘S0003D’进入另一个。S0001D和S0002D最终是否在同一个或不同的 reducer 上取决于 Hive 使用的哈希函数。
您还可以将SORT BY子句添加到语法中,它将在每个 reducer 内部对数据进行排序。
SET mapreduce.job.reduces=2;SELECT*FROM ecom_sales WHERE ymd=20240801DISTRIBUTE BY SKU_id SORT BY SKU_id;结果将如下所示:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3a781860799ccd19b57f7f09000c5413.png
作者图片
或者,您可以使用CLUSTER BY来结合DISTRIBUTE BY和SORT BY的功能,产生相同的输出。
SET mapreduce.job.reduces=2;SELECT*FROM ecom_sales WHERE ymd=20240801CLUSTER BY SKU_id;LATERAL VIEW 与 EXPLODE
LATERAL VIEW 与 EXPLODE 函数的组合是 Hive 处理数组或映射数据类型的一个强大功能。它允许您将嵌套数据结构扁平化到更传统的关联格式中,使得分析复杂数据更加容易。为了演示这个功能,我创建了一个名为products的另一个表,具有以下列:SKU_id——每个 SKU 的唯一标识符,SKU_name——与 SKU 关联的产品名称,以及description——包含该 SKU 产品描述的数组。
CREATE TABLE products(SKU_id STRING,SKU_name STRING,description ARRAY<STRING>);INSERT INTO products VALUES('S0001D','white_shirt_small',ARRAY('shirt','white','small')),('S0002D','blue_pants_large',ARRAY('pants','blue','large')),('S0003D','yellow_jacket_large',ARRAY('pants','blue','large'));SELECT*FROM products;上面的语法创建了一个看起来像的表:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/86f534343845ed4676ad670bddc9a219.png
图片由作者提供
接下来,我使用 EXPLODE 函数将数组description分解成单独的行,其中数组的每个元素都成为单独的行。然后使用 LATERAL VIEW 为原始products表中的数组生成的每一行创建一个虚拟表,名为featureTable。
SELECT p.SKU_id,p.SKU_name,feature FROM products p LATERAL VIEW EXPLODE(p.description)featureTable AS feature;查询结果将看起来像:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/fa054f4ee2e464ef5f4f6fa06de2693c.png
图片由作者提供
COLLECT_SET
COLLECT_SET 函数是 Hive 中的一个聚合函数,它将唯一元素收集到一个数组中,有效地执行了LATERAL VIEW与EXPLODE函数的逆操作。下面的语法创建了一个名为prod_features的表,其中特定元素将被分组到数组中。
CREATE TABLE prod_features(SKU_id STRING,SKU_name STRING,feature STRING);INSERT INTO prod_features VALUES('S0001D','white_shirt_small','shirt'),('S0001D','white_shirt_small','white'),('S0001D','white_shirt_small','small'),('S0002D','blue_pants_large','pants'),('S0002D','blue_pants_large','blue'),('S0002D','blue_pants_large','large'),('S0003D','yellow_jacket_large','jacket'),('S0003D','yellow_jacket_large','blue'),('S0003D','yellow_jacket_large','large');SELECT*FROM prod_features;https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/178589efbc80238c1bf2ce5fe4142ed8.png
prod_features(图片由作者提供)
以下语法演示了 COLLECT_SET 函数如何将feature列中的所有唯一值聚合到一个数组中。
SELECT SKU_id,SKU_name,COLLECT_SET(feature)AS description FROM prod_features GROUP BY SKU_id,SKU_name;查询结果将显示为:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/701345d5d3cb9203683cd41f780eafd5.png
图片由作者提供
结论
本文讨论了 5 个 Hive 特定功能,这些功能使 Hive 与 SQL 不同,使其特别适合大数据处理和分析。
PARTITIONED BY通过优化数据存储和检索,使大型数据集的管理更加高效。
存储为通过使用针对工作负载定制的特定文件格式,提高了存储效率和查询性能。
DISTRIBUTE BY和CLUSTER BY对于分布式系统中的数据查询性能优化至关重要,因为它们在并行处理期间对 reducer 上数据分布的粒度控制。
LATERAL VIEW 与 EXPLODE将数组或映射数据类型转换为单独的行,便于对嵌套数据结构进行详细分析。
COLLECT_SET将单个元素聚合到数组中,为汇总和分组数据提供了强大的工具。
通过利用这些 Hive 特定的功能,数据专业人员可以建立更有效和健壮的大数据解决方案,解决仅使用标准 SQL 难以或无法应对的挑战。