web-dev-qa-db-ja.com

AWS Athenaはテーブルとパーティションを作成します

S3にセンサーデータを保存しました(5分ごとにデータを書き込みます)。

farm_iot/sensor_data/farm/farm0001/sensor01/1541252701443

1541252701443は、測定値を含むJSONファイルです。

{  "temperature": 14.78,  "pressure": 961.70,  "humidity": 68.32}

私は間違いなくいくつかのHiveスキルがありません。残念ながら、私が開始する時系列JSONデータを抽出する例は見つかりませんでした。また、Hive/Athenaがこの種のデータレスティングをサポートしているかどうかもわかりません。

このデータのAthenaテーブルの作成に苦労しています...

CREATE EXTERNAL TABLE IF NOT EXISTS farm.sensor_data (
  device string,
  sensor string,
  data_point string,
  value double
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES (
  'serialization.format' = '1'
) LOCATION 's3://farm-iot/sensor_data/farm/farm0001/sensor01/'
PARTITIONED BY (timestamp string)
TBLPROPERTIES ('has_encrypted_data'='false')

私が考えている別の道は、処理しやすい構造にデータを保存することです/データを十分にパーティション分割していないかもしれません??!

そのため、次のような構造にdtを追加する必要があります。

farm_iot/sensor_data/2018-11-03-02-45-02/farm/farm0001/sensor01/1541252701443

それでも私が行きたい場所に行かない:

+---------------+----------+----------+-------------+--------+
| timestamp     | device   | sensor   | data_point  | value  |
+---------------+----------+----------+-------------+--------+
| 1541252701443 | farm0001 | sensor01 | temperature |  14.78 |
+---------------+----------+----------+-------------+--------+
| 1541252701443 | farm0001 | sensor01 | humidity    |  68.32 |
+---------------+----------+----------+-------------+--------+
| 1541252701443 | farm0001 | sensor01 | pressure    | 961.70 |
+---------------+----------+----------+-------------+--------+

この目標へのポインタは大歓迎です。ありがとうございました!

注:接着剤を使用したくないので、手動で行う方法を理解したいと思います。接着剤の他に、昨日〜16.000テーブルをすでに作成しました:)

10
mark

何よりもまず、@ hlagosの支援に感謝します。

AWS Athenaは、jsonセンサーデータを必要な方法で変換できませんでした(@hlagos answerへのコメントでこれを説明しました)。その結果、その状況に対処する「最も簡単な」方法は、データ形式をjsonからCSVに変更して、必要な形式に近づけることでした。

センサーデータをS3にCSV形式で保存し(5分ごとにデータを書き込む)、さらに、説明した曜日とデバイスパーティションを追加しました。

結果のフォルダー構造:

farm_iot/sensor_data/farm/day=20181129/device=farm0001/1543535738493

cSVファイルのデータ内容:

sensor01,temperature,2.82
sensor01,pressure,952.83
sensor01,humidity,83.64
sensor02,temperature,2.61
sensor02,pressure,952.74
sensor02,humidity,82.41

aWS Athenaテーブル定義:

CREATE EXTERNAL TABLE IF NOT EXISTS farm.sensor_data (
  `sensor` string,
  `data_point` string,
  `value` double 
) 
PARTITIONED BY (day string, device string)
ROW FORMAT DELIMITED
    FIELDS TERMINATED BY ','
    ESCAPED BY '\\'
    LINES TERMINATED BY '\n'
LOCATION 's3://farm-iot/sensor_data/farm/'
TBLPROPERTIES ('has_encrypted_data'='false');

追加するパーティションは次のようになります(後でパーティションを作成するスクリプトがあります)。

msck repair table farm.sensor_data

これで、データをクエリできます。

select regexp_extract("$path", '[^/]+$') as timestamp, device, sensor, 
    data_point, value from farm.sensor_data where day='20181104'

Results
    timestamp       device      sensor      data_point  value
1   1541310040278   farm0001    sensor01    temperature 21.61
2   1541310040278   farm0001    sensor01    pressure    643.65
3   1541310040278   farm0001    sensor01    humidity    74.84
4   1541310040278   farm0001    sensor02    temperature 9.14
5   1541310040278   farm0001    sensor02    pressure    956.04
6   1541310040278   farm0001    sensor02    humidity    88.01
7   1541311840309   farm0001    sensor01    temperature 21.61
8   ...
3
mark

正面にあるいくつかの問題について説明してみましょう。

  • 目的の出力は、パスファイルの場所、デバイス、およびセンサーの一部であるデータを予期しているように見えますが、テーブル定義の一部として定義されておらず、テーブル定義の列または 仮想列 使えるようになる。
  • いくつかの小さなファイルがクエリのパフォーマンスに影響を与える可能性があります(ただし、これは目的の結果には影響しません)
  • 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入力のファイル名の一部であるタイムスタンプが欠落しています。次のように、仮想列INPUT__FILE__NAMEを使用して、selectステートメント中にファイル名を含めることができます

select device, sensor, temperature, preassure, humidity, INPUT__FILE__NAME as mytimestamp from farm.sensor_data

事前保証、温度、湿度、異なる行が必要な場合は、これら3つの配列を作成して展開することをお勧めします。UNIONALLを使用して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
8
hlagos