GoogleSQL의 JSON 데이터 작업
이 문서에서는 JSON
열이 있는 테이블을 만들고, JSON 데이터를 BigQuery 테이블에 삽입하고, JSON 데이터를 쿼리하는 방법을 설명합니다.
BigQuery는 기본적으로 JSON
데이터 유형을 사용하여 JSON 데이터를 지원합니다.
JSON은 스키마를 필요로 하지 않으므로 반구조화된 데이터를 허용하는 널리 사용되는 형식입니다. 애플리케이션은 읽기 스키마(schema-on-read) 접근 방식을 사용할 수 있습니다. 이 접근 방법에서는 애플리케이션이 데이터를 수집한 다음 해당 데이터의 스키마에 대한 가정을 기반으로 쿼리합니다. 이 접근 방식은 STRUCT
유형의 열에 저장된 모든 값에 적용되는 고정 스키마가 필요한 BigQuery의 STRUCT
유형과 다릅니다.
JSON
데이터 유형을 사용하면 JSON 데이터의 스키마를 미리 제공하지 않고도 반구조화된 JSON을 BigQuery로 로드할 수 있습니다.
이렇게 하면 항상 고정 스키마와 데이터 유형을 준수하지 않는 데이터를 저장하고 쿼리할 수 있습니다. BigQuery는 JSON 데이터를 JSON
데이터 유형으로 수집하여 각 JSON 필드를 개별적으로 인코딩하고 처리할 수 있습니다. 그런 다음 필드 액세스 연산자를 사용하여 JSON 데이터 내에서 필드 및 배열 요소의 값을 쿼리할 수 있습니다. 이렇게 하면 JSON 쿼리를 직관적이고 비용 효율적으로 만듭니다.
제한사항
- 일괄 로드 작업을 사용하여 JSON 데이터를 테이블에 수집하는 경우 소스 데이터는 CSV, Avro 또는 JSON 형식이어야 합니다. 다른 일괄 로드 형식은 지원되지 않습니다.
JSON
데이터 유형의 중첩 한도는 500입니다.- legacy SQL을 사용하여
JSON
유형이 포함된 테이블을 쿼리할 수 없습니다. - 행 수준 액세스 정책은
JSON
열에 적용할 수 없습니다.
JSON
데이터 유형의 속성에 대한 자세한 내용은 JSON
유형을 참조하세요.
먼저 JSON
열을 사용하여 테이블을 만듭니다.
SQL 또는bq 명령줄 도구를 사용하여 JSON
열이 있는 빈 테이블을 만들 수 있습니다.
SQL
CREATE TABLE
문을 사용하고 JSON
유형으로 열을 선언합니다.
Google Cloud 콘솔에서 BigQuery 페이지로 이동합니다.
쿼리 편집기에서 다음 문을 입력합니다.
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
함수를 사용하여 SQL 값에서 JSON 배열을 만듭니다.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
유형으로 변환합니다.
다음 예시에서는 PARSE_JSON
함수를 사용하여 JSON 형식의 STRING
값을 변환합니다. 이 예시에서는 기존 테이블의 열을 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_OBJECT
함수를 사용하여 키-값 쌍을 JSON으로 변환합니다.
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
유형으로 변환
다음 예시는 TO_JSON
함수를 사용하여 SQL STRUCT
값을 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를 사용합니다.
- 기존
tabledata.insertAll
스트리밍 API를 사용합니다.
CSV 파일에서 로드
다음 예시에서는 다음 레코드를 포함하는 file1.csv
라는 CSV 파일이 있다고 가정합니다.
1,20 2,"""This is a string""" 3,"{""id"": 10, ""name"": ""Alice""}"
두 번째 열에는 문자열로 인코딩된 JSON 데이터가 포함됩니다. 이를 위해서는 따옴표를 CSV 형식에 맞춰 올바르게 이스케이프 처리해야 합니다. CSV 형식에서 따옴표는 두 문자 시퀀스 ""
를 사용하여 이스케이프 처리됩니다.
bq 명령줄 도구를 사용하여 이 파일을 로드하려면 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"}}
bq 명령줄 도구를 사용하여 이 파일을 로드하려면 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 사용
Storage Write API를 사용하여 JSON 데이터를 수집할 수 있습니다. 다음 예에서는 Storage Write API Python 클라이언트를 사용하여 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) ...
기존 스트리밍 API 사용
다음 예에서는 로컬 파일에서 JSON 데이터를 로드하고 기존 스트리밍 API를 사용하여 json_data
라는 JSON 데이터 유형 열이 있는 BigQuery 테이블로 스트리밍합니다.
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://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은 대소문자를 구분하며 필드 및 값 모두에서 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으로 추출
BigQuery에서 JSON
유형을 사용할 때 필드 액세스 연산자를 사용하여 JSON표현식의 필드에 액세스할 수 있습니다.
다음 예시에서는 cart
열의 name
필드를 반환합니다.
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 배열에 지정된 위치의 요소가 없는 경우 이러한 연산자는 SQL NULL
을 반환합니다.
SELECT cart.address AS address, cart.items[1].price AS item1_price FROM mydataset.table1;
+---------+-------------+ | address | item1_price | +---------+-------------+ | NULL | NULL | | NULL | 5 | +---------+-------------+
등호 연산자와 비교 연산자는 JSON
데이터 유형에 정의되어 있지 않습니다.
따라서 GROUP BY
또는 ORDER BY
와 같은 절에서는 JSON
값을 직접 사용할 수 없습니다. 대신 JSON_VALUE
함수를 사용하여 다음 섹션에 설명된 대로 필드 값을 SQL 문자열로 추출합니다.
값을 문자열로 추출
JSON_VALUE
함수는 스칼라 값을 추출하여 SQL 문자열로 반환합니다. cart.name
이 JSON의 스칼라 값을 가리키지 않으면 SQL NULL
을 반환합니다.
SELECT JSON_VALUE(cart.name) AS name FROM mydataset.table1;
+-------+ | name | +-------+ | Alice | +-------+
WHERE
절이나 GROUP BY
절과 같이 동등이나 비교가 필요한 컨텍스트에서는 JSON_VALUE
함수를 사용할 수 있습니다. 다음 예시에서는 JSON
값으로 필터링하는 WHERE
절을 보여줍니다.
SELECT cart.items[0] AS first_item FROM mydataset.table1 WHERE JSON_VALUE(cart.name) = 'Alice';
+-------------------------------+ | first_item | +-------------------------------+ | {"price":10,"product":"book"} | +-------------------------------+
또는 JSON 문자열을 추출하고 해당 값을 SQL STRING
으로 반환하는 STRING
함수를 사용할 수 있습니다.
예를 들면 다음과 같습니다.
SELECT STRING(JSON '"purple"') AS color;
+--------+ | color | +--------+ | purple | +--------+
STRING
외에도 JSON
값을 추출하고 이를 다른 SQL 데이터 유형으로 반환해야 할 수 있습니다. 다음 값 추출 함수를 사용할 수 있습니다.
JSON
값 유형을 가져오려면 JSON_TYPE
함수를 사용하면 됩니다.
유연하게 JSON 변환
LAX Conversion
함수를 사용하여 JSON
값을 오류 없이 유연하게 스칼라 SQL 값으로 변환할 수 있습니다.
다음 예시에서는 이러한 함수의 성능을 보여줍니다. LAX_IN64
는 자동으로 입력을 올바르게 추론하고 처리합니다.
SELECT LAX_INT64(JSON '"10"') AS id;
+----+ | id | +----+ | 10 | +----+
LAX_IN64
외에도 다음 함수를 사용하여 다른 SQL 유형을 JSON으로 유연하게 변환할 수 있습니다.
JSON에서 배열 추출
JSON은 BigQuery의 ARRAY<JSON>
유형과 직접 일치하지 않는 JSON 배열을 포함할 수 있습니다. 다음 함수를 사용하여 JSON에서 BigQuery ARRAY
를 추출할 수 있습니다.
JSON_QUERY_ARRAY
: 배열을 추출하고 JSON의ARRAY<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
연산자를 사용합니다. 다음 예시에서는 items
배열의 각 구성원에서 product
구성원을 선택합니다.
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의 배열 작업을 참조하세요.
JSON null
JSON
유형에는 SQL NULL
과 다른 특별한 null
값이 있습니다. JSON null
은 다음 예시와 같이 SQL NULL
값으로 취급되지 않습니다.
SELECT JSON 'null' IS NULL;
+-------+ | f0_ | +-------+ | false | +-------+
null
값으로 JSON 필드를 추출할 때는 동작이 함수에 따라 달라집니다.
- 유효한
JSON
값이므로JSON_QUERY
함수는 JSONnull
을 반환합니다. - JSON
null
은 스칼라 값이 아니므로JSON_VALUE
함수는 SQLNULL
을 반환합니다.
다음 예시에서는 다양한 동작을 보여줍니다.
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 | +------------+------------+