Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Embulk JSON関連のfilterプラグインを触ってみた。

More than 5 years have passed since last update.

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によるとラテン語とでてきたのですが、、、、

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away