让我试着解释一下我在前面看到的一些问题。
- 看起来您想要的输出需要一些数据,这些数据是路径文件位置、设备和传感器的一部分,但它没有定义为表定义的一部分,只有表定义或 virtual columns 中的列可用.
- 几个小文件可能会影响查询的性能(但这不会影响您想要的结果)
- Hive 分区用于提高查询的性能,避免扫描
所有的数据。分区指向文件夹,在这种情况下,您正在尝试访问特定文件
- 您想要的输出基本上是在几条记录中爆炸 1 条记录,这不应该在表定义中处理,可以通过您的 select 语句来完成
- Hive 分区具有
partitionname=partitionvalue 的命名约定,这不是强制性的,但如果您希望提前执行命令以根据文件夹结构自动添加分区,这很有用。
如果您主要通过传感器或设备进行查询,这就是我将如何解决您的问题
更改数据结构
理想情况下,您的文件夹结构应该来自
farm_iot/sensor_data/farm/farm0001/sensor01/1541252701443
到farm_iot/sensor_data/farm/device=farm0001/sensor=sensor01/1541252701443
更改表定义
您的表定义应该包含您的分区位置,以便能够在没有正则表达式的情况下选择它并利用它的性能改进(我猜一个常见的查询将按设备或传感器过滤。除此之外,您还需要添加所有作为文件一部分的 json 列
CREATE EXTERNAL TABLE IF NOT EXISTS farm.sensor_data (
temperature double,
preassure double,
humidity double
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES (
'serialization.format' = '1'
) LOCATION 's3://farm-iot/sensor_data/farm/'
PARTITIONED BY (device string, sensor string)
TBLPROPERTIES ('has_encrypted_data'='false')
查询您的数据
我们缺少时间戳,它本质上是带有 json 输入的文件名的一部分。我们可以在 select 语句中使用虚拟列 INPUT__FILE__NAME 包含文件名,如下所示
select device, sensor, temperature, preassure, humidity, INPUT__FILE__NAME as mytimestamp from farm.sensor_data
如果你想要压力、温度和湿度以及不同的行,我建议用这三个创建一个数组并分解它,使用 UNION ALL 运行 3 个查询来附加结果应该会非常有效
添加新分区
如果您遵循 Hive 约定,则可以利用命令 msck repair table 在包含新设备/传感器后自动添加新分区。在最坏的情况下,如果您想保留文件夹结构,您可以按如下方式添加分区
ALTER TABLE test ADD PARTITION (device='farm0001', sensor='sensor01') location 's3://farm_iot/sensor_data/farm/farm0001/sensor01'
注意:新分区不会自动添加,您始终需要添加它们
我尝试添加尽可能多的细节。如果有不清楚的地方,请告诉我。
编辑:
如果您的查询主要基于时间序列(例如日期范围),我建议在日级别(不小于此)添加一个分区以提高查询的性能。所以你的表定义看起来像
CREATE EXTERNAL TABLE IF NOT EXISTS farm.sensor_data (
temperature double,
preassure double,
humidity double
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES (
'serialization.format' = '1'
) LOCATION 's3://farm-iot/sensor_data/farm/'
PARTITIONED BY (dt=long, device string, sensor string)
TBLPROPERTIES ('has_encrypted_data'='false')
你的文件夹结构看起来像
farm_iot/sensor_data/farm/dt=20191204/device=farm0001/sensor=sensor01/1541252701443
作为澄清,您不需要为每个新分区修改表,只需将此分区添加到表中,这本质上是 Hive 将如何知道创建了一个新分区。如果你决定使用分区,这是唯一的方法,如果你不这样做(这会影响性能),还有一些其他的方法可以让它工作
EDIT2:
如果您想保持数据结构不变并且不使用分区,则可以获得如下预期结果
CREATE EXTERNAL TABLE IF NOT EXISTS yourdb.sensordata (
temperature double,
pressure double,
humidity double
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES (
'serialization.format' = '1'
)
LOCATION 's3://farm-iot/sensor_data/farm/'
TBLPROPERTIES ('has_encrypted_data'='false');
SET hive.mapred.supports.subdirectories=TRUE;
SET mapred.input.dir.recursive=TRUE;
select * from yourdb.sensordata;
select
split(input__file__name, "/")[size(split(input__file__name, "/")) - 1] as ts,
split(input__file__name, "/")[size(split(input__file__name, "/")) - 3] as device,
split(input__file__name, "/")[size(split(input__file__name, "/")) - 2] as sensor,
'temperature' as data_point,
temperature as value
from yourdb.sensordata
union all
select
split(input__file__name, "/")[size(split(input__file__name, "/")) - 1] as ts,
split(input__file__name, "/")[size(split(input__file__name, "/")) - 3] as device,
split(input__file__name, "/")[size(split(input__file__name, "/")) - 2] as sensor,
'pressure' as data_point,
pressure as value
from yourdb.sensordata
union all
select
split(input__file__name, "/")[size(split(input__file__name, "/")) - 1] as ts,
split(input__file__name, "/")[size(split(input__file__name, "/")) - 3] as device,
split(input__file__name, "/")[size(split(input__file__name, "/")) - 2] as sensor,
'humidity' as data_point,
humidity as value
from yourdb.sensordata;
如您所见,我从文件路径中获取了大部分信息,但是需要设置一些标志来告诉 Hive 递归读取文件夹
ts,device,sensor,_data_point,value
1541252701443,farm0001,sensor01,temperature,14.78
1541252701443,farm0001,sensor01,pressure,961.7
1541252701443,farm0001,sensor01,humidity,68.32