עבודה עם נתוני JSON ב-GoogleSQL
במאמר הזה מוסבר איך ליצור טבלה עם עמודת JSON, להוסיף נתוני JSON לטבלה ב-BigQuery ולשלוח שאילתות לנתוני JSON.
ב-BigQuery יש תמיכה מובנית בנתוני JSON באמצעות סוג הנתונים JSON.
JSON הוא פורמט נפוץ שמאפשר נתונים חצי-מובְנים, כי הוא לא דורש סכימה. אפליקציות יכולות להשתמש בגישה של "סכימה בקריאה", שבה האפליקציה מטמיעה את הנתונים ואז שולחת שאילתות על סמך הנחות לגבי הסכימה של הנתונים האלה. הגישה הזו שונה מהסוג STRUCT ב-BigQuery, שדורש סכימה קבועה שנאכפת על כל הערכים שמאוחסנים בעמודה מסוג STRUCT.
בעזרת סוג הנתונים JSON, אתם יכולים לטעון נתוני JSON חצי-מובְנים ל-BigQuery בלי לספק מראש סכימה לנתוני ה-JSON.
כך אפשר לאחסן נתונים שלא תמיד תואמים לסכימות ולסוגי נתונים קבועים, ולשלוח שאילתות לגביהם. כשמטמיעים נתוני JSON כסוג הנתונים JSON, המערכת של BigQuery יכולה לקודד ולעבד כל שדה JSON בנפרד. לאחר מכן תוכלו לשלוח שאילתות לגבי הערכים של השדות ורכיבי המערך בנתוני ה-JSON באמצעות אופרטור הגישה לשדות, מה שהופך את השאילתות ב-JSON לאינטואיטיביות וחסכוניות.
מגבלות
- אם אתם משתמשים במשימת טעינה באצווה כדי להטמיע נתוני JSON בטבלה, נתוני המקור צריכים להיות בפורמט CSV, Avro או JSON. אין תמיכה בפורמטים אחרים של טעינה בכמות גדולה.
- בסוג הנתונים
JSONיש מגבלת הטמעה של 500. - אי אפשר להשתמש ב-SQL מדור קודם כדי לשלוח שאילתה לטבלה שמכילה סוגי
JSON. - אי אפשר להחיל כללי מדיניות גישה ברמת השורה על עמודות
JSON.
למידע על המאפיינים של סוג הנתונים JSON, קראו את המאמר סוג JSON.
צור טבלה עם עמודה של JSON
אפשר ליצור טבלה ריקה עם עמודת JSON באמצעות SQL או באמצעות כלי שורת הפקודה של BigQuery.
SQL
משתמשים בהצהרה CREATE TABLE ומצהירים על עמודה עם הסוג JSON.
נכנסים לדף BigQuery במסוף Google Cloud .
בעורך השאילתות, מזינים את ההצהרה הבאה:
CREATE TABLE mydataset.table1( id INT64, cart JSON );
לוחצים על הפעלה.
מידע נוסף על הרצת שאילתות זמין במאמר הרצת שאילתה אינטראקטיבית.
BQ
משתמשים בפקודה bq mk ומספקים סכימת טבלה עם סוג הנתונים JSON.
bq mk --table mydataset.table1 id:INT64,cart:JSON
אי אפשר לחלק טבלה למחיצות או לאשכולות לפי עמודות JSON, כי אופרטורים של שוויון והשוואה לא מוגדרים בסוג JSON.
יצירת JSON ערכים
אפשר ליצור ערכי JSON בדרכים הבאות:
- משתמשים ב-SQL כדי ליצור
JSONליטרלי. - משתמשים בפונקציה
PARSE_JSONכדי להמיר ערךSTRINGלערךJSON. - משתמשים בפונקציה
TO_JSONכדי להמיר ערך SQL לערךJSON. - משתמשים בפונקציה
JSON_ARRAYכדי ליצור מערך JSON מערכי SQL. - משתמשים בפונקציה
JSON_OBJECTכדי ליצור אובייקט JSON מצמדי מפתח/ערך.
יצירת ערך JSON
בדוגמה הבאה מוסיפים ערכי JSON לטבלה:
INSERT INTO mydataset.table1 VALUES (1, JSON '{"name": "Alice", "age": 30}'), (2, JSON_ARRAY(10, ['foo', 'bar'], [20, 30])), (3, JSON_OBJECT('foo', 10, 'bar', ['a', 'b']));
המרת סוג STRING לסוג JSON
בדוגמה הבאה, הערך של STRING בפורמט JSON מומר באמצעות הפונקציה PARSE_JSON. בדוגמה הזו, עמודה מטבלה קיימת מומרת לסוג JSON והתוצאות נשמרות בטבלה חדשה.
CREATE OR REPLACE TABLE mydataset.table_new AS ( SELECT id, SAFE.PARSE_JSON(cart) AS cart_json FROM mydataset.old_table );
הקידומת SAFE שבה השתמשנו בדוגמה הזו מבטיחה שכל שגיאות ההמרה יוחזרו כערכי NULL.
המרת נתונים עם סכימה ל-JSON
בדוגמה הבאה, צמדי מפתח/ערך מומרים ל-JSON באמצעות הפונקציה JSON_OBJECT.
WITH Fruits AS ( SELECT 0 AS id, 'color' AS k, 'Red' AS v UNION ALL SELECT 0, 'fruit', 'apple' UNION ALL SELECT 1, 'fruit','banana' UNION ALL SELECT 1, 'ripe', 'true' ) SELECT JSON_OBJECT(ARRAY_AGG(k), ARRAY_AGG(v)) AS json_data FROM Fruits GROUP BY id
התוצאה היא:
+----------------------------------+
| json_data |
+----------------------------------+
| {"color":"Red","fruit":"apple"} |
| {"fruit":"banana","ripe":"true"} |
+----------------------------------+
המרת סוג SQL לסוג JSON
בדוגמה הבאה, הערך STRUCT של SQL מומר לערך JSON באמצעות הפונקציה TO_JSON:
SELECT TO_JSON(STRUCT(1 AS id, [10,20] AS coordinates)) AS pt;
התוצאה היא:
+--------------------------------+
| pt |
+--------------------------------+
| {"coordinates":[10,20],"id":1} |
+--------------------------------+
הטמעת נתוני JSON
אפשר להטמיע נתוני JSON בטבלה ב-BigQuery בדרכים הבאות:
- אפשר להשתמש במשימת טעינה באצווה כדי לטעון לעמודות
JSONמהפורמטים הבאים. - משתמשים ב-BigQuery Storage Write API (gRPC).
- משתמשים ב-BigQuery Storage Write API (REST).
טעינה מקובצי CSV
בדוגמה הבאה, נניח שיש לכם קובץ CSV בשם file1.csv שמכיל את הרשומות הבאות:
1,20
2,"""This is a string"""
3,"{""id"": 10, ""name"": ""Alice""}"
שימו לב שהעמודה השנייה מכילה נתוני JSON שמקודדים כמחרוזת. לשם כך, צריך להוסיף תווי בריחה (escape) למירכאות בפורמט CSV. בפורמט CSV, מירכאות מוחלפות ברצף של שני התווים "".
כדי לטעון את הקובץ באמצעות כלי שורת הפקודה של BigQuery, משתמשים בפקודה bq load:
bq load --source_format=CSV mydataset.table1 file1.csv id:INTEGER,json_data:JSON
bq show mydataset.table1
Last modified Schema Total Rows Total Bytes
----------------- -------------------- ------------ -------------
22 Dec 22:10:32 |- id: integer 3 63
|- json_data: json
טעינה מקובצי JSON שמופרדים בשורה חדשה
בדוגמה הבאה, נניח שיש לכם קובץ בשם file1.jsonl שמכיל את הרשומות הבאות:
{"id": 1, "json_data": 20}
{"id": 2, "json_data": "This is a string"}
{"id": 3, "json_data": {"id": 10, "name": "Alice"}}
כדי לטעון את הקובץ באמצעות כלי שורת הפקודה של BigQuery, משתמשים בפקודה bq load:
bq load --source_format=NEWLINE_DELIMITED_JSON mydataset.table1 file1.jsonl id:INTEGER,json_data:JSON
bq show mydataset.table1
Last modified Schema Total Rows Total Bytes
----------------- -------------------- ------------ -------------
22 Dec 22:10:32 |- id: integer 3 63
|- json_data: json
שימוש ב-Storage Write API (gRPC)
אתם יכולים להשתמש ב-Storage Write API (gRPC) כדי להטמיע נתוני JSON. בדוגמה הבאה משתמשים בלקוח Python של Storage Write API (gRPC) כדי לכתוב נתונים בטבלה עם עמודה מסוג נתוני JSON.
מגדירים מאגר אחסון לפרוטוקולים שיכיל את נתוני הסטרימינג שעברו סריאליזציה. נתוני ה-JSON מקודדים כמחרוזת. בדוגמה הבאה, השדה json_col מכיל נתוני JSON.
message SampleData {
optional string string_col = 1;
optional int64 int64_col = 2;
optional string json_col = 3;
}
צריך להגדיר את הפורמט של נתוני ה-JSON לכל שורה כערך STRING:
row.json_col = '{"a": 10, "b": "bar"}'
row.json_col = '"This is a string"' # The double-quoted string is the JSON value.
row.json_col = '10'
מוסיפים את השורות לזרם הכתיבה, כמו שמוצג בקוד לדוגמה. ספריית הלקוח מטפלת בהעברה לפורמט של מאגר אחסון לפרוטוקולים.
אם אתם לא יכולים לשנות את הפורמט של נתוני ה-JSON הנכנסים, אתם צריכים להשתמש בשיטה json.dumps() בקוד שלכם. לדוגמה:
import json
...
row.json_col = json.dumps({"a": 10, "b": "bar"})
row.json_col = json.dumps("This is a string") # The double-quoted string is the JSON value.
row.json_col = json.dumps(10)
...
שימוש ב-Storage Write API (REST)
בדוגמה הבאה נתונים בפורמט JSON נטענים מקובץ מקומי ומועברים בסטרימינג לטבלה ב-BigQuery, עם עמודה מסוג נתונים JSON בשם json_data, באמצעות Storage Write API (REST).
from google.cloud import bigquery
import json
# TODO(developer): Replace these variables before running the sample.
project_id = 'MY_PROJECT_ID'
table_id = 'MY_TABLE_ID'
client = bigquery.Client(project=project_id)
table_obj = client.get_table(table_id)
# The column json_data is represented as a JSON data-type column.
rows_to_insert = [
{"id": 1, "json_data": 20},
{"id": 2, "json_data": "This is a string"},
{"id": 3, "json_data": {"id": 10, "name": "Alice"}}
]
# If the column json_data is represented as a String data type, modify the rows_to_insert values:
#rows_to_insert = [
# {"id": 1, "json_data": json.dumps(20)},
# {"id": 2, "json_data": json.dumps("This is a string")},
# {"id": 3, "json_data": json.dumps({"id": 10, "name": "Alice"})}
#]
# Throw errors if encountered.
# https://docs.cloud.google.com/python/docs/reference/bigquery/latest/google.cloud.bigquery.client.Client#google_cloud_bigquery_client_Client_insert_rows
errors = client.insert_rows(table=table_obj, rows=rows_to_insert)
if errors == []:
print("New rows have been added.")
else:
print("Encountered errors while inserting rows: {}".format(errors))
למידע נוסף, קראו את המאמר הזרמת נתונים ל-BigQuery.
שאילתות על נתוני JSON
בקטע הזה מוסבר איך משתמשים ב-GoogleSQL כדי לחלץ ערכים מ-JSON. JSON תלוי אותיות רישיות (case-sensitive) ותומך ב-UTF-8 גם בשדות וגם בערכים.
בדוגמאות שבקטע הזה נעשה שימוש בטבלה הבאה:
CREATE OR REPLACE TABLE mydataset.table1(id INT64, cart JSON); INSERT INTO mydataset.table1 VALUES (1, JSON """{ "name": "Alice", "items": [ {"product": "book", "price": 10}, {"product": "food", "price": 5} ] }"""), (2, JSON """{ "name": "Bob", "items": [ {"product": "pen", "price": 20} ] }""");
חילוץ ערכים כ-JSON
אם יש לכם סוג JSON ב-BigQuery, אתם יכולים לגשת לשדות בביטוי JSON באמצעות אופרטור הגישה לשדה.
בדוגמה הבאה מוחזר השדה name של העמודה cart.
SELECT cart.name FROM mydataset.table1;
+---------+ | name | +---------+ | "Alice" | | "Bob" | +---------+
כדי לגשת לאלמנט במערך, משתמשים באופרטור של אינדקס JSON.
בדוגמה הבאה מוחזר הרכיב הראשון של המערך items:
SELECT cart.items[0] AS first_item FROM mydataset.table1
+-------------------------------+
| first_item |
+-------------------------------+
| {"price":10,"product":"book"} |
| {"price":20,"product":"pen"} |
+-------------------------------+
אפשר גם להשתמש באופרטור של אינדקס משנה ב-JSON כדי להפנות לאיברים של אובייקט JSON לפי שם:
SELECT cart['name'] FROM mydataset.table1;
+---------+ | name | +---------+ | "Alice" | | "Bob" | +---------+
בפעולות של אינדקס תחתי, הביטוי בתוך הסוגריים יכול להיות כל מחרוזת או ביטוי של מספר שלם, כולל ביטויים לא קבועים:
DECLARE int_val INT64 DEFAULT 0; SELECT cart[CONCAT('it','ems')][int_val + 1].product AS item FROM mydataset.table1;
+--------+ | item | +--------+ | "food" | | NULL | +--------+
גם אופרטורים של גישה לשדות וגם אופרטורים של אינדקסים מחזירים סוגי JSON, כך שאפשר לשרשר ביטויים שמשתמשים בהם או להעביר את התוצאה לפונקציות אחרות שמקבלות סוגי JSON.
האופרטורים האלה משפרים את הקריאוּת של הפונקציונליות הבסיסית של הפונקציה JSON_QUERY. לדוגמה, הביטוי cart.name שווה ערך ל-JSON_QUERY(cart, "$.name").
אם לא נמצא איבר עם השם שצוין באובייקט ה-JSON, או אם במערך ה-JSON אין רכיב עם המיקום שצוין, האופרטורים האלה מחזירים את הערך NULL ב-SQL.
SELECT cart.address AS address, cart.items[1].price AS item1_price FROM mydataset.table1;
+---------+-------------+ | address | item1_price | +---------+-------------+ | NULL | NULL | | NULL | 5 | +---------+-------------+
האופרטורים של השוויון וההשוואה לא מוגדרים בסוג הנתונים JSON.
לכן, אי אפשר להשתמש בערכי JSON ישירות בסעיפים כמו GROUP BY או ORDER BY. במקום זאת, השתמשו בפונקציה JSON_VALUE כדי לחלץ ערכי שדות כמחרוזות SQL, כפי שמתואר בקטע הבא.
חילוץ ערכים כמחרוזות
הפונקציה JSON_VALUE מחלצת ערך סקלרי ומחזירה אותו כמחרוזת SQL. הפונקציה מחזירה את הערך NULL ב-SQL אם cart.name לא מצביע על ערך סקלרי ב-JSON.
SELECT JSON_VALUE(cart.name) AS name FROM mydataset.table1;
+-------+ | name | +-------+ | Alice | +-------+
אפשר להשתמש בפונקציה JSON_VALUE בהקשרים שדורשים שוויון או השוואה, כמו משפטי WHERE ומשפטי GROUP BY. בדוגמה הבאה מוצג תנאי WHERE שמסנן לפי ערך JSON:
SELECT cart.items[0] AS first_item FROM mydataset.table1 WHERE JSON_VALUE(cart.name) = 'Alice';
+-------------------------------+
| first_item |
+-------------------------------+
| {"price":10,"product":"book"} |
+-------------------------------+
לחלופין, אפשר להשתמש בפונקציה STRING שמחלצת מחרוזת JSON ומחזירה את הערך הזה בתור STRING ב-SQL.
לדוגמה:
SELECT STRING(JSON '"purple"') AS color;
+--------+ | color | +--------+ | purple | +--------+
בנוסף ל-STRING, יכול להיות שתצטרכו לחלץ ערכי JSON ולהחזיר אותם כסוג נתונים אחר של SQL. אלה הפונקציות הזמינות לחילוץ ערכים:
כדי לקבל את הסוג של הערך JSON, אפשר להשתמש בפונקציה JSON_TYPE.
המרת JSON גמישה
אפשר להמיר ערך JSON לערך SQL סקלרי בצורה גמישה באמצעות פונקציות LAX conversion.
בדוגמה הבאה נעשה שימוש בפונקציה LAX_INT64 כדי לחלץ ערך INT64 מערך JSON.
SELECT LAX_INT64(JSON '"10"') AS id;
+----+ | id | +----+ | 10 | +----+
בנוסף ל-LAX_INT64, אפשר להמיר סוגי SQL אחרים ל-JSON באופן גמיש באמצעות הפונקציות הבאות:
חילוץ מערכים מ-JSON
JSON יכול להכיל מערכי JSON, שלא מקבילים ישירות לסוג ARRAY<JSON> ב-BigQuery. אפשר להשתמש בפונקציות הבאות כדי לחלץ ARRAY של BigQuery מ-JSON:
-
JSON_QUERY_ARRAY: חילוץ מערך והחזרה שלו בתורARRAY<JSON>של JSON. -
JSON_VALUE_ARRAY: מחלץ מערך של ערכים סקלריים ומחזיר אותו כ-ARRAY<STRING>של ערכים סקלריים.
בדוגמה הבאה משתמשים ב-JSON_QUERY_ARRAY כדי לחלץ מערכי JSON:
SELECT JSON_QUERY_ARRAY(cart.items) AS items FROM mydataset.table1;
+----------------------------------------------------------------+
| items |
+----------------------------------------------------------------+
| [{"price":10,"product":"book"}","{"price":5,"product":"food"}] |
| [{"price":20,"product":"pen"}] |
+----------------------------------------------------------------+
כדי לפצל מערך לרכיבים נפרדים, משתמשים באופרטור UNNEST, שמחזיר טבלה עם שורה אחת לכל רכיב במערך. בדוגמה הבאה נבחר האיבר product מכל איבר במערך items:
SELECT id, JSON_VALUE(item.product) AS product FROM mydataset.table1, UNNEST(JSON_QUERY_ARRAY(cart.items)) AS item ORDER BY id;
+----+---------+ | id | product | +----+---------+ | 1 | book | | 1 | food | | 2 | pen | +----+---------+
הדוגמה הבאה דומה, אבל משתמשת בפונקציה ARRAY_AGG כדי לצבור את הערכים בחזרה למערך SQL.
SELECT id, ARRAY_AGG(JSON_VALUE(item.product)) AS products FROM mydataset.table1, UNNEST(JSON_QUERY_ARRAY(cart.items)) AS item GROUP BY id ORDER BY id;
+----+-----------------+ | id | products | +----+-----------------+ | 1 | ["book","food"] | | 2 | ["pen"] | +----+-----------------+
מידע נוסף על מערכים זמין במאמר עבודה עם מערכים ב-GoogleSQL.
ערכי null ב-JSON
לסוג JSON יש ערך null מיוחד ששונה מהערך NULL של SQL. ערך JSON null לא מטופל כערך SQL NULL, כמו בדוגמה הבאה.
SELECT JSON 'null' IS NULL;
+-------+ | f0_ | +-------+ | false | +-------+
כשמחלצים שדה JSON עם ערך null, ההתנהגות תלויה בפונקציה:
- הפונקציה
JSON_QUERYמחזירהnullבפורמט JSON, כי זה ערךJSONתקין. - הפונקציה
JSON_VALUEמחזירה את הערךNULLשל SQL, כי הערךnullשל JSON הוא לא ערך סקלרי.
בדוגמה הבאה אפשר לראות את ההתנהגויות השונות:
SELECT json.a AS json_query, -- Equivalent to JSON_QUERY(json, '$.a') JSON_VALUE(json, '$.a') AS json_value FROM (SELECT JSON '{"a": null}' AS json);
+------------+------------+ | json_query | json_value | +------------+------------+ | null | NULL | +------------+------------+