Embulk JSON関連のfilterプラグインを触ってみた。
Embulkアドベントカレンダー、19日目の記事が埋まらないので私のメモを公開します。
embulkのJSON関連のfilterプラグインは、現在のところ、全て@Civitaspoさんが作成されています。ありがとうございます。
プラグインのサンプルを実際に動かしてみて、各プラグインの動作を確認しました。(各プラグインのexampleディレクトリにあるものを動かしただけとも言います)
名前 | 説明 |
---|---|
embulk-filter-expand_json | jsonから値を抽出して、独立したカラムに値をセットする |
embulk-filter-flatten_json | 配列やハッシュでネストしたJSONを平坦化する |
embulk-filter-json_key | JSONに値を追加したり、JSONから値を削除したりる |
embulk-filter-expand_json
embulk-filter-expand_jsonは、jsonから値を抽出して、独立したカラムに分離するプラグインです。
サンプル を実行して動作を確認してみましょう。
元データのdata.tsvはタブ区切りのテキストで、JSONのデータはjson_payloadカラムに格納されています。
field_name | data |
---|---|
time | 2015-10-11 08:06:23 +0900 |
id | 0 |
name | Avis Lind |
score | -3256.869635206057 |
json_payload | {"phone_numbers":"1-276-220-7263",... |
json_payloadの中身は次のような形式になっています。処理の内容を分かり易くするためにコメントをいれてあります。元のサンプルにコメントはありません。
{
// (1) 独立したカラムに値を抽出(文字列)
"phone_numbers": "1-276-220-7263",
// (2) 独立したカラムに値を抽出(整数)
"app_id": 0,
// (3) 独立したカラムに値を抽出(浮動小数点)
"point": -1601.6890336884562,
// (4) 独立したカラムに値を抽出(日付部分のみ抽出)
"created_at": "2015-10-07 20:23:57 +0900",
"profile": {
"like_words": [ // (5) 配列全体を抽出
"maiores",
"eum", // (6) 配列の一部を抽出
"aut" // (7) 配列の一部を抽出
],
"anniversary": { // (8) ハッシュ全体を
"voluptatem": "dolor",
"et": "ullam" // (9) ハッシュ内の一要素を抽出
}
}
}
次に、embulkのフィルタプラグインの設定です。embulk-filter-expand_jsonは、JSONのパスをJsonPathを使って指定します。
filters:
- type: expand_json
json_column_name: json_payload # 元データの格納先としてjson_payloadカラムを指定
root: "$." # JsonPATHで、rootを起点とするように設定
expanded_columns:
- {name: "phone_numbers", type: string} # (1)
- {name: "app_id", type: long} # (2)
- {name: "point", type: double} # (3)
- {name: "created_at", type: timestamp, format: "%Y-%m-%d"} # (4)
- {name: "profile.anniversary.et", type: string} # (9)
- {name: "profile.anniversary", type: string} # (8)
- {name: "profile.like_words[1]", type: string} # (5)
- {name: "profile.like_words[2]", type: string} # (6)
- {name: "profile.like_words", type: string} # (7)
プレビューを実行すると次のようになり、json_payloadから様々な値が抽出されていることが確認できます。
*************************** 1 ***************************
time (timestamp) : 2015-10-11 00:00:00 UTC
id ( long) : 0
name ( string) : Avis Lind
score ( double) : -3256.869635206057
phone_numbers ( string) : 1-276-220-7263 # (1)
app_id ( long) : 0 # (2)
point ( double) : -1601.6890336884562 # (3)
created_at (timestamp) : 2015-10-07 00:00:00 UTC # (4) 日付のみ抽出されている
profile.anniversary.et ( string) : ullam # (9)
profile.anniversary ( string) : {"voluptatem":"dolor","et":"ullam"} # (8)
profile.like_words[1] ( string) : eum # (5)
profile.like_words[2] ( string) : aut # (6)
profile.like_words ( string) : ["maiores","eum","aut"] # (7)
(4)の元データは、2015-10-07 20:23:57 +0900
でしたが、日付の部分のみ抽出したので、2015-10-07 0:0:0 UTC
となり日本時刻にすると2015-10-07 09:00:00 +0900
になっています。
日付を取り扱う場合は、タイムゾーンまでを取得して、出力先で工夫をするのがよいのかもしれません。
embulk-filter-flatten_json
次にembulk-filter-flatten_jsonを試します。このプラグインは、配列やハッシュでネストしたJSONを平坦化するプラグインです。オリジナルのサンプルはこちらです。
元データはこちらです。コメントは追記したもので、オリジナルにはありません。
{
"phone_numbers": [ // (1) ハッシュの配列になっている
"526-126-8730 x85186"
],
"profile": { // (2) ハッシュが入れ子になっている
"like_words": [ // (3) 配列になっている
"quos",
"non",
"nemo"
],
"anniversary": { // (4) ハッシュが入れ子になっている
"sint": "illo",
"excepturi": "debitis"
}
}
}
次にembulkのフィルタプラグインの設定です。
filters:
- type: flatten_json
json_columns: # 平坦化するjsonのカラムを配列で指定
- json_payload # 元データはjson_payloadカラムを利用
separator: "." # ハッシュがあった場合の区切り文字
array_index_prefix: "_" # 要素が配列だった場合に、要素番号の前に追加する文字
実行結果は次のようになります。
*************************** 1 ***************************
time (timestamp) : 2015-10-05 00:00:00 UTC
id ( long) : 0
name ( string) : Mia O'Conner
score ( double) : -4432.147926744348
json_payload ( string) : {"profile.anniversary.sint":"illo","phone_numbers._0":"526-126-8730 x85186","profile.like_words._0":"quos","profile.like_words._2":"nemo","profile.anniversary.excepturi":"debitis","profile.like_words._1":"non"}
JSON部分だけ注目します。フラットなハッシュになっていることがわかります。
{
"phone_numbers._0": "526-126-8730 x85186", // (1)
"profile.like_words._1": "non" // (2),(3)
"profile.like_words._0": "quos", // (2),(3)
"profile.like_words._2": "nemo", // (2),(3)
"profile.anniversary.excepturi": "debitis",// (4)
"profile.anniversary.sint": "illo", // (4)
}
embulk-filter-json_key
最後にembulk-filter-json_keyを試します。このプラグインは、JSONのカラムに値を追加したり、値を削除するプラグインです。オリジナルのサンプルはこちらです。
値の追加
まず値を追加する設定を試します。
オリジナルのデータのjson_payloadの値は次のようになっています。
{
"phone_numbers": "1-276-220-7263",
"profile": {
"like_words": [
"maiores",
"eum",
"aut"
],
"anniversary": {
"voluptatem": "dolor",
"et": "ullam"
}
}
}
次にembulkの設定です。
filters:
- type: json_key
column: json_payload # 元カラムの指定
nested_key_delimiter: "." # ネストした属性のデリミタ
add_keys:
# (1) キーだけ追加
- {key: add_key1}
# (2) キーと値を追加、値は文字列
- {key: add_key2, value: add_value2}
# (3) キーと値を追加、値は、数値
- {key: add_key3, value: 3}
# (4) キーと値を追加、値は配列
- {key: add_key4, value: [1,2,3,4]}
# (5) キー値を追加、値はハッシュ
- {key: add_key5, value: {key1: value, key2: 2, key3: {key: value}}}
# (6) 既存のハッシュprofileの下に、新しいキーを追加、値は文字列
- {key: profile.add_key6, value: add_value6}
実行した結果のjson_payloadカラムは次のようになりました。
{
"phone_numbers": "1-276-220-7263",
"profile": {
"like_words": [
"maiores",
"eum",
"aut"
],
"anniversary": {
"voluptatem": "dolor",
"et": "ullam"
},
"add_key6": "add_value6" // (6) 既存のパラメータに値が追加されている
},
"add_key1": null, // (1) キーだけ増えて値がnull
"add_key2": "add_value2", // (2) キーが増え、値が文字列
"add_key3": 3, // (3) キーが増えて値が数値
"add_key4": [ // (4) キーが増えて値が、配列
1,
2,
3,
4
],
"add_key5": { // (5) キーが増えて値がハッシュ
"key1": "value",
"key2": 2,
"key3": {
"key": "value"
}
}
}
値の削除
オリジナルのデータのjson_payloadの値は次のようになっています。
{
"phone_numbers": "1-276-220-7263", // (1) この値を削除
"profile": {
"like_words": [
"maiores",
"eum",
"aut" // (2) この値を削除、ハッシュの中の配列の要素
],
"anniversary": {
"voluptatem": "dolor", // (3) この値を削除、入れ子になったハッシュ
"et": "ullam"
}
}
}
次にembulkの設定です。
filters:
- type: json_key
column: json_payload # 対象カラムの指定
nested_key_delimiter: "." # ネストした属性のデリミタ
drop_keys:
# (1) phone_numbersを削除
- {key: phone_numbers}
# (2) profile.like_wordsの3番目の要素を削除
- {key: profile.like_words.2}
# (3) profile.anniversary.voluptatemを削除
- {key: profile.anniversary.voluptatem}
実行した結果のembulkは次のようになりました。
{
// (1) "phone_numbers": "1-276-220-7263"がなくなっている
"profile": {
"like_words": [
"maiores",
"eum"
// (2) "aut"がなくなっている
],
"anniversary": {
// (3) "voluptatem": "dolor" がなくなっている
"et": "ullam"
}
}
}
最後に
以上で現在利用できるjson関連のフィルタプラグインを試してみました。JSONを編集する際には、非常に役立つプラグインだと思います。
それにしても、気になるのはサンプルデータで使われている文字が何語なのかということです。Google Translateによるとラテン語とでてきたのですが、、、、