

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# JSON SerDe 程式庫
<a name="json-serde"></a>

在 Athena 中，您可以使用 SerDe 程式庫來還原序列化 JSON 資料。還原序列化會轉換 JSON 資料，讓這些資料能夠序列化 (寫出) 至 Parquet 或 ORC 等不同格式。
+ [Hive JSON SerDe](hive-json-serde.md)
+ [OpenX JSON SerDe](openx-json-serde.md) 
+ [Amazon Ion Hive SerDe](ion-serde.md)

**注意**  
Hive 和 OpenX 程式庫預期 JSON 資料位於單行上 (未格式化)，且記錄由換行字元分隔。

由於 Amazon Ion 是 JSON 的超集，因此您可以使用 Amazon Ion Hive SerDe 來查詢非 Amazon Ion JSON 資料集。與 Hive 和 OpenX JSON SerDe 程式庫不同，Amazon Ion SerDe 不期望每一資料列都位於單獨一行上。如果您想查詢使用「美化顯示」格式的 JSON 資料集，或以其他方式用新行字元分解資料列中的欄位，則此功能非常有用。

## 程式庫名稱
<a name="library-names"></a>

請使用下列其中一個：

 [org.apache.hive.hcatalog.data.JsonSerDe](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-JSON) 

 [org.openx.data.jsonserde.JsonSerDe](https://github.com/rcongiu/Hive-JSON-Serde) 

[com.amazon.ionhiveserde.IonHiveSerDe](https://github.com/amzn/ion-hive-serde)

# Hive JSON SerDe
<a name="hive-json-serde"></a>

Hive JSON SerDe 經常用來處理事件等 JSON 資料。這些事件以 JSON 編碼文字 (以新行分隔) 的單行字串表示。Hive JSON SerDe 不允許在 `map` 或 `struct` 索引鍵名稱中使用重複的索引鍵。

**注意**  
SerDe 預期每筆 JSON 文件都以單行文字表示，而且沒有行終止字元分隔記錄中的欄位。如果 JSON 文字是美化過的列印格式，則在建立資料表後嘗試在其中查詢時可能會收到下列錯誤訊息：HIVE\$1CURSOR\$1ERROR: Row is not a valid JSON Object (HIVE\$1CURSOR\$1ERROR：資料列不是有效的 JSON 物件) 或 HIVE\$1CURSOR\$1ERROR: JsonParseException: Unexpected end-of-input: expected close marker for OBJECT (HIVE\$1CURSOR\$1ERROR：JsonParseException：非預期的輸入結束：預期為 OBJECT 的關閉標記)。如需詳細資訊，請參閱 GitHub 上 OpenX SerDe 文件中的 [JSON 資料檔案](https://github.com/rcongiu/Hive-JSON-Serde#json-data-files)。

下列 DDL 陳述式範例使用 Hive JSON SerDe，以根據線上廣告資料範例建立資料表。在 `LOCATION` 子句中，請以您執行 Athena 所在位置的區域識別符 (例如 `s3://us-west-2.elasticmapreduce/samples/hive-ads/tables/impressions`) 來取代 `s3://amzn-s3-demo-bucket.elasticmapreduce/samples/hive-ads/tables/impressions` 中的 *myregion*。

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

## 使用 Hive JSON SerDe 指定時間戳記格式
<a name="hive-json-serde-timestamp-formats"></a>

若要從字串中剖析時間戳記值，您可以將 `WITH SERDEPROPERTIES` 子欄位新增至 `ROW FORMAT SERDE` 子句並使用它來指定 `timestamp.formats` 參數。在參數中，指定一個或多個時間戳記模式的逗號分隔清單，如下範例所示：

```
...
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
WITH SERDEPROPERTIES ("timestamp.formats"="yyyy-MM-dd'T'HH:mm:ss.SSS'Z',yyyy-MM-dd'T'HH:mm:ss")
...
```

如需詳細資訊，請參閱 Apache Hive 文件中[時間戳記](https://cwiki.apache.org/confluence/display/hive/languagemanual+types#LanguageManualTypes-TimestampstimestampTimestamps)。

## 載入資料表以進行查詢
<a name="hive-json-serde-loading-the-table"></a>

建立資料表後，請執行 [MSCK REPAIR TABLE](msck-repair-table.md) 以載入資料表，並讓其可從 Athena 查詢：

```
MSCK REPAIR TABLE impressions
```

## 查詢 CloudTrail 日誌
<a name="hive-json-serde-querying-cloud-trail-logs"></a>

您可以使用 Hive JSON SerDe 來查詢 CloudTrail 日誌。如需詳細資訊和範例 `CREATE TABLE` 陳述式，則請參閱 [查詢 AWS CloudTrail 日誌](cloudtrail-logs.md)。

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

像 Hive JSON SerDe 一樣，您可以使用 OpenX JSON 來處理 JSON 資料。這些資料也可表示為 JSON 編碼文字 (以新行分隔) 的單行字串。就像 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 文件都以單行文字表示，而且沒有行終止字元分隔記錄中的欄位。如果 JSON 文字是美化過的列印格式，則在建立資料表後嘗試在其中查詢時可能會收到下列錯誤訊息：HIVE\$1CURSOR\$1ERROR: Row is not a valid JSON Object (HIVE\$1CURSOR\$1ERROR：資料列不是有效的 JSON 物件) 或 HIVE\$1CURSOR\$1ERROR: JsonParseException: Unexpected end-of-input: expected close marker for OBJECT (HIVE\$1CURSOR\$1ERROR：JsonParseException：非預期的輸入結束：預期為 OBJECT 的關閉標記)。

  如需詳細資訊，請參閱 GitHub 上 OpenX SerDe 文件中的 [JSON 資料檔案](https://github.com/rcongiu/Hive-JSON-Serde#json-data-files)。

## 可選屬性
<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`，則可能會發生類似以下的錯誤：  
HIVE\$1CURSOR\$1ERROR：列不是有效的 JSON 物件 - JSONException：重複索引鍵 "url"  
若要解決這個問題，請將 `case.insensitive` 屬性設定為 `FALSE`，並將索引鍵對應至不同的名稱，如下列範例所示：  

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

**對應**  
選用。將欄名稱映射到與欄名稱不完全相同的 JSON 索引鍵。當 JSON 資料包含為[關鍵字](reserved-words.md)的索引鍵時，`mapping` 參數將十分實用。例如，如果您有一個名為 `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` 子句中，請以您執行 Athena 所在之處的區域識別符取代 *myregion*。

```
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 SerDes 來剖析更複雜的 JSON 編碼資料。這需要使用 `CREATE TABLE` 陳述式，它會使用 `struct` 和 `array` 元素來表示巢狀結構。

下列範例會根據具有巢狀結構的 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 記錄都位於單行文字上。在 Amazon S3 中存放資料時，上述範例中的所有資料都應該位於單行上，如下所示：

```
{"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 | 名稱 | 地址 | 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 | 

## 其他資源
<a name="json-serdes-additional-resources"></a>

如需有關在 Athena 中使用 JSON 和巢狀 JSON 的詳細資訊，請參閱下列資源：
+ [使用 JSONSerDe 從巢狀 JSON 和映射在 Amazon Athena 中建立資料表](https://aws.amazon.com/blogs/big-data/create-tables-in-amazon-athena-from-nested-json-and-mappings-using-jsonserde/) (AWS 大數據部落格）
+ [當我嘗試讀取 Amazon Athena 中的 JSON 資料時出現錯誤](https://aws.amazon.com/premiumsupport/knowledge-center/error-json-athena/) (AWS 知識中心文章）
+ [hive-json-schema](https://github.com/quux00/hive-json-schema) (GitHub) - 以 Java 撰寫的工具，會從 JSON 文件範例中產生 `CREATE TABLE` 陳述式。產生的 `CREATE TABLE` 陳述式會使用 OpenX JSON Serde。