

# OpenX JSON SerDe
<a name="openx-json-serde"></a>

Hive JSON SerDe と同様に、OpenX JSON を使用して JSON データを処理できます。また、データは改行で区切られ JSON 形式でエンコードされたテキストの 1 行の文字列としても表現されます。Hive JSON SerDe と同様に、OpenX JSON SerDe では、`map` または `struct` キー名の重複キーは許可されません。

## 考慮事項と制限事項
<a name="openx-json-serde-considerations-limitations"></a>
+ OpenX JSON SerDe を使用する場合、結果の数とその値は非決定的である可能性があります。結果に含まれる行数が予想よりも多かったり少なかったりする可能性があり、基になるデータに何も存在しない場合に予期しない null 値が含まれる可能性もあります。この問題を回避するには、[Hive JSON SerDe](hive-json-serde.md) を使用するか、データを別のファイル形式タイプに書き換えます。
+ SerDe では、各 JSON ドキュメントが、レコード内のフィールドを区切る行終端文字なしの、1 行のテキストに収まっていることを想定しています。JSON テキストがプリティプリント形式の場合、テーブルを作成した後にクエリを実行しようとすると、以下のようなエラーメッセージが表示される場合があります。「HIVE\$1CURSOR\$1ERROR: Row is not a valid JSON Object」、または「HIVE\$1CURSOR\$1ERROR: JsonParseException: Unexpected end-of-input: expected close marker for OBJECT」。

  詳細については、GitHub の OpenX SerDe のドキュメントで「[JSON Data Files](https://github.com/rcongiu/Hive-JSON-Serde#json-data-files)」(JSON データファイル) を参照してください。

## オプションのプロパティ
<a name="openx-json-serde-optional-properties"></a>

Hive JSON SerDe とは異なり、OpenX JSON SerDe には、データの不整合に対処するのに役立つ次のオプションの SerDe プロパティもあります。

**use.null.for.invalid.data**  
オプション。デフォルトは `FALSE` です。`TRUE` に設定すると、SerDe はテーブルスキーマで定義された列の型への逆シリアル化に失敗した列値に対して `NULL` を使用します。  
`use.null.for.invalid.data` を `TRUE` に設定すると、スキーマと一致しない列の無効なデータが、 `NULL` 値で置き換えられるため、誤った結果や予期しない結果が発生する可能性があります。このプロパティを有効にするのではなく、ファイルまたはテーブルスキーマ内のデータを修正することをお勧めします。このプロパティを有効にすると、無効なデータに対してクエリが失敗しないため、データ品質の問題を検出できなくなる可能性があります。

**ignore.malformed.json**  
オプション。`TRUE` に設定すると、不正な形式の JSON 構文を無視できます。デフォルトは `FALSE` です。

**dots.in.keys**  
オプション。デフォルトは `FALSE` です。`TRUE` に設定すると、SerDe はキー名のドットをアンダースコアに置き換えることができます。例えば、JSON データセットに `"a.b"` という名前のキーが含まれている場合は、このプロパティを使用して、Athena で列名が `"a_b"` になるように定義できます。デフォルトで (この SerDe がない場合)、Athena は列名にドットを許可しません。

**case.insensitive**  
オプション。デフォルトは `TRUE` です。`TRUE` に設定すると、SerDe はすべての大文字の列を小文字に変換します。  
データで大文字と小文字を区別するキー名を使用するには、`WITH SERDEPROPERTIES ("case.insensitive"= FALSE;)` を使用します。次に、まだすべてが小文字になっていないすべてのキーに、次の構文を使用して列名からプロパティ名へのマッピングを指定します。  

```
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES ("case.insensitive" = "FALSE", "mapping.userid" = "userId")
```
`URL` と `Url` のように小文字である 2 つのキーがある場合は、次のようなエラーが発生する可能性があります。  
HIVE\$1CURSOR\$1ERROR: Row is not a valid JSON Object - JSONException: Duplicate key "url"  
これを解決するには、次の例のように、`case.insensitive` プロパティを `FALSE` に設定し、キーを異なる名前にマッピングします。  

```
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES ("case.insensitive" = "FALSE", "mapping.url1" = "URL", "mapping.url2" = "Url")
```

**マッピングを**  
オプション。列名を、列名と同一ではない JSON キーにマップします。`mapping` パラメータは、JSON データに[キーワード](reserved-words.md)のキーが含まれている場合に便利です。例えば、`timestamp` という名前の JSON キーがある場合、次の構文を使用して、キーを `ts` という名前の列にマッピングします。  

```
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES ("mapping.ts" = "timestamp")
```
**コロンを含むネストされたフィールド名を Hive 互換の名前にマッピングする**  
`struct` の内部にコロンを含むフィールド名がある場合は、`mapping` プロパティを使用してそのフィールドを Hive 互換の名前にマップできます。例えば、列タイプの定義に `my:struct:field:string` を含めることで、`WITH SERDEPROPERTIES` で次のエントリー定義を `my_struct_field:string` にマップできます。

```
("mapping.my_struct_field" = "my:struct:field")
```
次の例は、対応する `CREATE TABLE` ステートメントを示しています。  

```
CREATE EXTERNAL TABLE colon_nested_field (
item struct<my_struct_field:string>)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES ("mapping.my_struct_field" = "my:struct:field")
```

## 例: 広告データ
<a name="openx-json-serde-ad-data-example"></a>

次の DDL ステートメントの例では、OpenX JSON SerDe を使用して、Hive JSON SerDe の例で使用したのと同じサンプルオンライン広告データに基づいてテーブルを作成します。`LOCATION` 句で、*myregion* を Athena が実行されるリージョンの識別子に置き換えます。

```
CREATE EXTERNAL TABLE impressions (
    requestbegintime string,
    adid string,
    impressionId string,
    referrer string,
    useragent string,
    usercookie string,
    ip string,
    number string,
    processid string,
    browsercokie string,
    requestendtime string,
    timers struct<
       modellookup:string, 
       requesttime:string>,
    threadid string, 
    hostname string,
    sessionid string
)   PARTITIONED BY (dt string)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://amzn-s3-demo-bucket.elasticmapreduce/samples/hive-ads/tables/impressions';
```

## 例: ネスト JSON の逆シリアル化
<a name="nested-json-serde-example"></a>

JSON SerDe を使用して、より複雑な JSON エンコードされたデータを解析できます。このためには、ネストされた構造を表すために `struct` 要素と `array` 要素を使用する `CREATE TABLE` ステートメントを使用する必要があります。

次の例は、ネストされた構造を持つ JSON データから Athena テーブルを作成します。サンプルは次の構造になっています。

```
{
"DocId": "AWS",
"User": {
        "Id": 1234,
        "Username": "carlos_salazar", 
        "Name": "Carlos",
"ShippingAddress": {
"Address1": "123 Main St.",
"Address2": null,
"City": "Anytown",
"State": "CA"
   },
"Orders": [
   {
     "ItemId": 6789,
     "OrderDate": "11/11/2022" 
   },
   {
     "ItemId": 4352,
     "OrderDate": "12/12/2022"
   }
  ]
 }
}
```

OpenX SerDe は、各 JSON レコードが 1 行のテキスト上にあることを期待することに注意してください。Amazon S3 に保存されている場合、前の例のすべてのデータを、次に示すように 1 行で表記する必要があります。

```
{"DocId":"AWS","User":{"Id":1234,"Username":"carlos_salazar","Name":"Carlos","ShippingAddress" ...
```

次の `CREATE TABLE` ステートメントは、[Openx-JsonSerDe](https://github.com/rcongiu/Hive-JSON-Serde) を `struct` および `array` コレクションデータ型とともに使用して、サンプルデータ用にオブジェクトのグループを構築します。

```
CREATE external TABLE complex_json (
   docid string,
   `user` struct<
               id:INT,
               username:string,
               name:string,
               shippingaddress:struct<
                                      address1:string,
                                      address2:string,
                                      city:string,
                                      state:string
                                      >,
               orders:array<
                            struct<
                                 itemid:INT,
                                  orderdate:string
                                  >
                              >
               >
   )
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://amzn-s3-demo-bucket/myjsondata/';
```

テーブルをクエリするには、次のような `SELECT` ステートメントを使用します。

```
SELECT 
 user.name as Name, 
 user.shippingaddress.address1 as Address, 
 user.shippingaddress.city as City, 
 o.itemid as Item_ID, o.orderdate as Order_date
FROM complex_json, UNNEST(user.orders) as temp_table (o)
```

構造体内のデータフィールドにアクセスするために、サンプルクエリはドット表記 (`user.name` など) を使用します。(`orders` フィールドと同様に) 構造体の配列内のデータにアクセスするには、`UNNEST` 関数を使用できます。`UNNEST` 関数は配列を一時テーブル (この場合は `o`) にフラット化します。これにより、構造体と同様にドット表記を使用して、ネストされていない配列要素 (`o.itemid` など) にアクセスできます。この例で説明のために使用されている名前 `temp_table` は、多くの場合、`t` と省略されます。

次の表にクエリ結果を示します。


****  

| \$1 | 名前 | Address | City | Item\$1ID | Order\$1date | 
| --- | --- | --- | --- | --- | --- | 
| 1 | Carlos | 123 Main St. | Anytown | 6789 | 11/11/2022 | 
| 2 | Carlos | 123 Main St. | Anytown | 4352 | 12/12/2022 | 