本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
像 Hive JSON SerDe 一樣,您可以使用 OpenX JSON 來處理 JSON 資料。這些資料也可表示為 JSON 編碼文字 (以新行分隔) 的單行字串。就像 Hive JSON SerDe 一樣,OpenX JSON SerDe 不允許在 map
或 struct
索引鍵名稱中使用重複的索引鍵。
考量與限制
-
使用 OpenX JSON SerDe 時,結果數量及其值可以是非確定性的。結果可以包含比預期更多的資料列、比預期更少的資料列,或當基礎資料中不存在非預期的 null 值時。若要解決此問題,請使用 Hive JSON SerDe,或將資料重寫至其他檔案格式類型。
-
SerDe 預期每筆 JSON 文件都以單行文字表示,而且沒有行終止字元分隔記錄中的欄位。如果 JSON 文字是美化過的列印格式,則在建立資料表後嘗試在其中查詢時可能會收到下列錯誤訊息:
HIVE_CURSOR_ERROR: Row is not a valid JSON Object
(HIVE_CURSOR_ERROR:資料列不是有效的 JSON 物件) 或HIVE_CURSOR_ERROR: JsonParseException: Unexpected end-of-input: expected close marker for OBJECT
(HIVE_CURSOR_ERROR:JsonParseException:非預期的輸入結束:預期為 OBJECT 的關閉標記)。如需詳細資訊,請參閱 GitHub 上 OpenX SerDe 文件中的 JSON 資料檔案
。
可選屬性
與 Hive JSON SerDe 不同,OpenX JSON SerDe 還具有以下可選 SerDe 屬性,可以用於解決資料的不一致性。
- 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_CURSOR_ERROR:列不是有效的 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 資料包含為關鍵字的索引鍵時,
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")
範例:廣告資料
下列 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
您可以使用 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-JsonSerDestruct
和 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
。
下表顯示查詢結果。
# | 名稱 | Address | City | Item_ID | Order_date |
---|---|---|---|---|---|
1 | Carlos | 123 Main St. | 任何城市 | 6789 | 11/11/2022 |
2 | Carlos | 123 Main St. | 任何城市 | 4352 | 12/12/2022 |