すべてのプロダクト
Search
ドキュメントセンター

Hologres:JSONデータ型とJSONBデータ型

最終更新日:Jul 05, 2025

このトピックでは、JSONデータ型とJSONBデータ型でサポートされている構文と、これらのデータ型の使用方法について説明します。

JSONデータ型とJSONBデータ型の概要

近年、モバイル アプリケーションの人気が高まるにつれ、アプリケーションの追跡やユーザ タグの計算などのシナリオに対する要件が増えています。これらの要件により良く対応するために、ますます多くのビッグデータ システムが、より柔軟な開発と処理のために関連データを保存するために半構造化フォーマットを使用し始めています。JSON と JSONB は、一般的に使用される半構造化データ型です。JSON データ型と JSONB データ型の違いを以下に示します。

  • JSON型のデータはテキスト形式で保存され、JSONB型のデータはバイナリデータとして保存されます。

  • JSON型のデータは高速で書き込むことができますが、データの読み取りには時間がかかります。これは、JSON型のデータがクエリされるたびに、処理関数がデータを解析する必要があるためです。JSONB型のデータは高速で読み取ることができますが、データの書き込みには時間がかかります。JSONB型のデータは、分解されたバイナリ形式で保存されます。システムがHologresにJSONB型のデータを書き込む際には、追加の変換を行う必要があります。そのため、JSONB型のデータの書き込みにはより多くの時間がかかります。ただし、JSONBデータのクエリは、再解析が不要なため、時間が短縮されます。

  • JSONデータ型は、入力テキストの正確なコピーを保存します。スペース、重複するオブジェクトキー、およびオブジェクトキーの順序は保持されます。値内のJSONオブジェクトに同じキーが複数回含まれている場合、すべてのキーと値のペアが保持されます。JSONBデータ型は、入力テキストが解析されるときに、不要なスペース、重複するオブジェクトキー、およびオブジェクトキーの順序を削除します。入力テキストで重複するオブジェクトキーが指定されている場合、最後の値のみが保持されます。

2つのデータ型の主な違いは、データ処理効率です。

  • JSONデータ型は、入力テキストの正確なコピーを保存します。処理関数は、実行ごとにコピーを再解析する必要があります。さらに、入力テキストのセマンティック制約に準拠するために、JSON型のデータにはスペースなどの重要でない文字が存在する場合があります。値内のJSONオブジェクトに同じキーが複数回含まれている場合、すべてのキーと値のペアが保持されます。処理関数は、最後の値を有効な値と見なします。

  • JSONB型のデータは、分解されたバイナリ形式で保存されます。JSON型のデータと比較して、JSONB型のデータは追加の変換処理が必要なため、書き込みに時間がかかります。ただし、JSONBデータの処理は、再解析が不要なため、時間が短縮されます。JSONBデータには、スペース、オブジェクトキーの順序、および重複するオブジェクトキーは存在しません。入力テキストで重複するオブジェクトキーが指定されている場合、最後の値のみが保持されます。

制限事項

Hologresは、JSONデータ型とJSONBデータ型をサポートしています。これらのデータ型を使用する場合は、次の制限事項に注意してください。

  • Hologres V0.9以降のみがJSONデータ型をサポートしています。HologresインスタンスのバージョンがV0.9より前の場合は、HologresコンソールでHologresインスタンスを手動でアップグレードするか、Hologres DingTalkグループに参加してインスタンスのアップグレードを申請してください。Hologresインスタンスを手動でアップグレードする方法の詳細については、「インスタンスのアップグレード」をご参照ください。Hologres DingTalkグループへの参加方法の詳細については、「Hologresのオンラインサポートを受ける」をご参照ください。

  • Hologres V1.1以降のみが、JSONBデータ型のフィールドに対するGINインデックスをサポートしています。

  • Hologres V1.3以降のみが、JSONBデータ型に対する列指向ストレージをサポートしています。JSONBデータ型の列指向ストレージは、列指向テーブルに対してのみ使用でき、行指向テーブルに対しては使用できません。列指向ストレージは、列指向テーブルに1,000以上のデータレコードが含まれている場合にのみトリガーできます。

  • Hologresは、次のJSON固有の関数をサポートしていません: json_each、jsonb_each、json_each_text、jsonb_each_text、json_extract_path、jsonb_extract_path、およびjsonb_to_record。

    jsonb_extract_path関数とjson_extract_path関数を使用する場合は、次のステートメントを実行します。

    • SELECT json_extract_path(
                              '{"key":{"key1":"key1","key2":"key2"}}'::json
                              , 'key'
                              , 'key1'
      );
      -- json_extract_path 関数と同等のステートメント:
      SELECT
          '{"key":{"key1":"key1","key2":"key2"}}'::json #> '{"key","key1"}';
    • SELECT jsonb_extract_path(
                  '{"key":{"key1":"key1","key2":"key2"}}'::jsonb
                  , 'key'
                  , 'key1'
      );
      -- jsonb_extract_path 関数と同等のステートメント:
      SELECT
          '{"key":{"key1":"key1","key2":"key2"}}'::jsonb #> '{"key","key1"}';                                    

JSONデータ型とJSONBデータ型のデータでサポートされる演算子

JSONデータ型とJSONBデータ型のデータでサポートされる一般的に使用される演算子

次の表に、JSONデータ型とJSONBデータ型のデータでサポートされる一般的に使用される演算子を示します。

演算子

右オペランド型

説明

実行結果

->

int

0から始まるインデックスを持つJSON配列要素を取得します。負の整数は、末尾から逆方向に要素がカウントされることを示します。

select '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json->2

{"c":"baz"}

->

text

キーに基づいてJSONオブジェクトフィールドを取得します。

select '{"a": {"b":"foo"}}'::json->'a'

{"b":"foo"}

->>

int

JSON配列要素をテキストとして取得します。

select '[1,2,3]'::json->>2

3

->>

text

JSONオブジェクトフィールドをテキストとして取得します。

select '{"a":1,"b":2}'::json->>'b'

2

#>

text[]

指定されたパスからJSONオブジェクトを取得します。

select '{"a": {"b":{"c": "foo"}}}'::json#>'{a,b}'

{"c":"foo"}

#>>

text[]

指定されたパスからJSONオブジェクトをテキストとして取得します。

select '{"a":[1,2,3],"b":[4,5,6]}'::json#>>'{a,2}'

3

JSONデータ型とJSONBデータ型のデータでサポートされる追加の演算子

次の表に、JSONデータ型とJSONBデータ型のデータでサポートされる追加の演算子を示します。追加の演算子は、さまざまなビジネス開発要件を満たすために使用されます。

演算子

右オペランド型

説明

実行結果

@>

jsonb

左側のJSON値に右側のJSONパスまたは値が含まれているかどうかを指定します。

select '{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb

true

<@

jsonb

左側のJSONパスまたは値が右側のJSON値に含まれているかどうかを指定します。

select '{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb

true

?

text

JSON値にキーまたは要素文字列が存在するかどうかを指定します。

select '{"a":1, "b":2}'::jsonb ? 'b'

true

?|

text[]

配列文字列内のキーまたは要素文字列がJSON値に存在するかどうかを指定します。

select '{"a":1, "b":2, "c":3}'::jsonb ?| array['b', 'c']

true

?&

text[]

すべての配列文字列がJSON値に存在するかどうかを指定します。

select '["a", "b"]'::jsonb ?& array['a', 'b']

true

||

jsonb

2つのJSONB値を連結して新しいJSONB値を作成します。

説明

|| 演算子は、各 JSON 値の操作要素を連結しますが、再帰操作は実行しません。たとえば、2 つのオペランドが同じキー フィールド名を持つオブジェクトである場合、この演算子は、フィールド値が右オペランドの値である値を返します。

select '["a", "b"]'::jsonb || '["c", "d"]'::jsonb

["a", "b", "c", "d"]

-

text

左オペランドからキーまたは値を削除します。キーまたは値は、キー値に基づいて照合されます。

select '{"a": "b"}'::jsonb - 'a'

{}

-

text[]

左オペランドから複数のキーまたは値を削除します。キーまたは値は、キー値に基づいて照合されます。

select '{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[]

{}

-

integer

指定された位置にある配列要素を削除します。負の整数は、末尾から逆方向に要素がカウントされることを示します。JSONデータが配列として保存されていない場合は、エラーが返されます。

select '["a", "b"]'::jsonb - 1

["a"]

#-

text[]

指定されたパスを持つ要素を削除します。JSON配列の場合、負の整数は、末尾から逆方向に要素がカウントされることを示します。

select '["a", {"b":1}]'::jsonb #- '{1,b}'

["a", {}]

JSONデータ型とJSONデータ型をサポートする関数

JSON値とJSONB値を処理するための関数

次の表に、JSON値とJSONB値を処理するために使用される関数を示します。

関数

戻り値の型

説明

実行結果

json_array_length(json)

int

最上位の JSON 配列の要素数を返します。

select json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]')

5

jsonb_array_length(jsonb)

json_object_keys(json)

setof text

最上位の JSON オブジェクトのキーのセットを返します。

select json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}')

json_object_keys
------------------
 f1
 f2

jsonb_object_keys(jsonb)

json_populate_record(base anyelement, from_json json)

anyelement

from_json パラメーター内のオブジェクトを、base パラメーターで定義されたレコード型に一致する列を持つ行に展開します。

begin;
create table 
myrowtype( a text, b text, c text);commit;
select * from json_populate_record(null::myrowtype, '{"a": 1, "b": ["2", "a b"], "c": {"d": 4, "e": "a b c"}}')
 a |   b       |      c
---+-----------+-------------
 1 | {2,"a b"} | {"d": 4, "e": "a b c"}

jsonb_populate_record(base anyelement, from_json jsonb)

json_populate_recordset(base anyelement, from_json json)

setof anyelement

from_json パラメーターの最外部オブジェクト配列を、base パラメーターで定義されたレコード型と一致する列を持つ行のセットに展開します。

begin;
create table 
myrowtype(a text,b text);
commit;
select * from json_populate_recordset(null::myrowtype, '[{"a":1,"b":2},{"a":3,"b":4}]')
 a | b
---+---
 1 | 2
 3 | 4

jsonb_populate_recordset(base anyelement, from_json jsonb)

json_array_elements(json)

setof json

JSON 配列を JSON 値のセットに展開します。

select * from json_array_elements('[1,true, [2,false]]')

   value
-----------
 1
 true
 [2,false]

jsonb_array_elements(jsonb)

jsonb の集合

json_array_elements_text(json)

setof text

JSON 配列をテキスト値のセットに展開します。

select * from json_array_elements_text('["foo", "bar"]')

 value
-----------
 foo
 bar

jsonb_array_elements_text(jsonb)

json_typeof(json)

text

最も外側の JSON 値のデータ型をテキスト文字列として返します。使用可能なデータ型には、OBJECT、ARRAY、STRING、NUMBER、BOOLEAN、および NULL が含まれます。

select json_typeof('-123.4')

number

jsonb_typeof(jsonb)

json_strip_nulls(from_json json)

json

from_json パラメーター内のオブジェクトを返します。null 値を持つオブジェクトフィールドは省略されます。その他の null 値は保持されます。

select json_strip_nulls('[{"f1":1,"f2":null},2,null,3]')

[{"f1":1},2,null,3]

jsonb_strip_nulls(from_json jsonb)

jsonb

jsonb_set(target jsonb, path text[], new_value jsonb[,create_missing boolean])

jsonb

target パラメータのオブジェクトを返します。path パラメータで指定されたノードは、new_value パラメータの値に置き換えられます。create_missing パラメータの値が true で、path パラメータで指定された項目が存在しない場合、new_value パラメータの値が挿入されます。create_missing パラメータのデフォルト値は true です。パス指向演算子の要件に従って、path パラメータの値の負の整数は、要素が JSON 配列の末尾から逆方向にカウントされることを示します。

select jsonb_set('[{"f1":1,"f2":null},2,null,3]', '{0,f1}','[2,3,4]', false);

[{"f1":[2,3,4],"f2":null},2,null,3]

select jsonb_set('[{"f1":1,"f2":null},2]', '{0,f3}','[2,3,4]')

[{"f1": 1, "f2": null, "f3": [2, 3, 4]}, 2]

jsonb_insert(target jsonb, path text[], new_value jsonb, [insert_after boolean])

jsonb

new_value パラメータの値が挿入された target パラメータのオブジェクトを返します。path パラメータで指定されたノードは、JSONB 配列内にある場合があります。この場合、insert_after パラメータの値が false(デフォルト値)の場合、new_value パラメータの値は target パラメータの値の前に挿入されます。それ以外の場合、new_value パラメータの値は target パラメータの値の後に挿入されます。path パラメータで指定されたノードは、JSONB オブジェクト内にある場合があります。この場合、new_value パラメータの値は、target パラメータの値が存在しない場合にのみ挿入されます。パス指向演算子の要件に従って、path パラメータの値の負の整数は、要素が JSON 配列の末尾から逆方向にカウントされることを示します。

select jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"')

{"a": [0, "new_value", 1, 2]}

select jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"', true)

{"a": [0, 1, "new_value", 2]}

jsonb_pretty(from_json jsonb)

text

from_json パラメーター内のオブジェクトをインデント付き JSON テキストとして返します。

select jsonb_pretty('[{"f1":1,"f2":null},2,null,3]')

[
    {
        "f1": 1,
        "f2": null
    },
    2,
    null,
    3
]

jsonb_agg

jsonb

NULL 値を含む値を JSON 配列に集約します。

DROP TABLE IF EXISTS t;

CREATE TABLE t (
    k int PRIMARY KEY,
    class int NOT NULL,
    v text NOT NULL
);

INSERT INTO t (k, class, v)
SELECT
    (1 + s.v),
    CASE (s.v) < 3
    WHEN TRUE THEN
        1
    ELSE
        2
    END,
    chr(97 + s.v)
FROM
    generate_series(0, 5) AS s (v);

SELECT
    class,
    jsonb_agg(v ORDER BY v DESC) FILTER (WHERE v <> 'b') AS "jsonb_agg",
    jsonb_object_agg(v, k ORDER BY v DESC) FILTER (WHERE v <> 'e') AS "jsonb_object_agg(v, k)"
FROM
    t
GROUP BY
    class;
 class |    jsonb_agg    |  jsonb_object_agg(v, k)
-------+-----------------+--------------------------
     1 | ["c", "a"]      | {"a": 1, "b": 2, "c": 3}
     2 | ["f", "e", "d"] | {"d": 4, "f": 6}

jsonb_object_agg

jsonb

キーと値のペアを JSON オブジェクトに集約します。値は空にできますが、キーは空にできません。

DROP TABLE IF EXISTS t;

CREATE TABLE t (
    k int PRIMARY KEY,
    class int NOT NULL,
    v text NOT NULL
);

INSERT INTO t (k, class, v)
SELECT
    (1 + s.v),
    CASE (s.v) < 3
    WHEN TRUE THEN
        1
    ELSE
        2
    END,
    chr(97 + s.v)
FROM
    generate_series(0, 5) AS s (v);

SELECT
    class,
    jsonb_agg(v ORDER BY v DESC) FILTER (WHERE v <> 'b') AS "jsonb_agg",
    jsonb_object_agg(v, k ORDER BY v DESC) FILTER (WHERE v <> 'e') AS "jsonb_object_agg(v, k)"
FROM
    t
GROUP BY
    class;
 class |    jsonb_agg    |  jsonb_object_agg(v, k)
-------+-----------------+--------------------------
     1 | ["c", "a"]      | {"a": 1, "b": 2, "c": 3}
     2 | ["f", "e", "d"] | {"d": 4, "f": 6}

is_valid_json

BOOLEAN

JSON 文字列を検証します。入力文字列が有効な JSON 文字列の場合、ブール値 true (t) が返されます。それ以外の場合、ブール値 false (f) が返されます。

説明
  • Hologres V1.3.12 以降でのみ、この関数がサポートされています。

  • ARRAY データ型も JSON データ型です。ARRAY 型のデータは、JSON 列または JSONB 列に書き込むことができます。

DROP TABLE IF EXISTS test_json;

CREATE TABLE test_json (
    id int,
    json_strings text
);

INSERT INTO test_json
    VALUES (1, '{"a":2}'), (2, '{"a":{"b":{"c":1}}}'), (3, '{"a": [1,2,"b"]}');

INSERT INTO test_json
    VALUES (4, '{{}}'), (5, '{1:"a"}'), (6, '[1,2,3]');

SELECT
    id,
    json_strings,
    is_valid_json (json_strings)
FROM
    test_json
ORDER BY
    id;
id | json_strings        | is_valid_json
---+---------------------+--------------
 0 | {"a":2}             | true
 2 | {"a":{"b":{"c":1}}} | true
 4 | {"a": [1,2,"b"]}    | true
 6 | {{}}                | false
 8 | {1:"a"}             | false
10 | [1,2,3]             | true

解析関数

関数

説明

実行結果

try_cast_to_jsonb(text)

TEXT 型のデータを JSONB 型のデータに変換します。データが JSONB 形式に準拠していない場合は、null 値が返されます。

説明

Hologres V2.0.24 以降のみがこの関数をサポートしています。

  • select try_cast_to_jsonb('{"key": 1}');

  • select try_cast_to_jsonb('{"key": 1');

  • {"key": 1}

  • NULL

to_json(anyelement)

有効な JSON オブジェクトとして値を返します。配列と複合型は再帰的に配列とオブジェクトに変換されます。配列または複合型ではない値の場合、キャスト関数が提供されていると、キャスト関数が呼び出されて入力値が JSON オブジェクトに変換されます。そうでない場合は、スカラー値が生成されます。スカラー値が NUMBER、BOOLEAN、または NULL データ型でない場合、スカラー値は JSON テキストで表されます。この場合、スカラー値は有効な JSON 文字列です。

select to_json('Fred said "Hi."'::text)

"Fred said \"Hi.\""

to_jsonb(anyelement)

array_to_json(anyarray [, pretty_bool])

配列を JSON 配列として返します。多次元配列を入力すると、配列の JSON 配列が返されます。pretty_bool パラメーターの値が true の場合、ディメンション 1 の要素間に改行が追加されます。

select array_to_json('{{1,5},{99,100}}'::int[])

[[1,5],[99,100]]

json_build_array(VARIADIC "any")

可変引数のリストに基づいて、異種データを含むことができる JSON 配列を作成します。

select json_build_array(1,2,'3',4,5)

[1, 2, "3", 4, 5]

jsonb_build_array(VARIADIC "any")

json_build_object(VARIADIC "any")

可変引数のリストに基づいて JSON オブジェクトを作成します。引数リストは、キーと値が交互に並んでいます。

select json_build_object('foo',1,'bar',2)

{"foo": 1, "bar": 2}

jsonb_build_object(VARIADIC "any")

json_object(text[])

テキスト配列に基づいて JSON オブジェクトを作成します。配列は、偶数個のメンバーを含む 1 次元配列にすることができます。メンバーは、キーと値のペアが交互に並んでいると見なされます。配列は 2 次元配列にすることもできます。各内部配列には 2 つの要素があり、これらはキーと値のペアと見なされます。

select json_object('{a, 1, b, "def", c, 3.5}');

{"a": "1", "b": "def", "c": "3.5"}

jsonb_object(text[])

select jsonb_object('{a, 1, b, "def", c, 3.5}');

{"a": "1", "b": "def", "c": "3.5"}

json_object(keys text[], values text[])

2 つの個別の配列に基づいてキーと値のペアを取得します。その他の点では、キーと値のペアは単一の引数と同じ形式です。

select json_object('{a, b}', '{1,2}')

{"a": "1", "b": "2"}

jsonb_object(keys text[], values text[])

JSONB フィールドのインデックス作成

Hologres V1.1 以降では、データ クエリを高速化するために、JSONB データ型のフィールドに GIN インデックスと B-tree インデックスを作成できます。JSONB データ型のフィールドに GIN インデックスを作成するには、デフォルトの jsonb_ops 演算子と jsonb_path_ops 演算子のいずれかを使用できます。このトピックでは、JSONB データ型のフィールドにインデックスが作成されます。JSON データ型ではなく、JSONB データ型のフィールドにインデックスを作成することをお勧めします。

説明
  • JSONB GIN インデックスは、JSONB 列指向ストレージの最適化と組み合わせて使用することはサポートされていません。 Hologres V3.0.42 および V3.1.10 以降、両方の機能が有効になっている場合、GIN インデックスは有効になりません。

  • JSONB GIN インデックスは、スパース JSONB フィールドに適しています。スパースでないシナリオでは、代わりに JSONB 列指向ストレージの最適化を使用することをお勧めします。

  • デフォルトの jsonb_ops 演算子を使用してインデックスを作成します。

    CREATE INDEX idx_name ON table_name USING gin (idx_col);
  • jsonb_path_ops 演算子を使用してインデックスを作成します。

    CREATE INDEX idx_name ON table_name USING gin (idx_col jsonb_path_ops);

jsonb_opsjsonb_path_ops の違いは、jsonb_ops はデータ内のキーと値ごとに個別のインデックス項目を作成するのに対し、jsonb_path_ops はデータ内の値ごとにのみインデックス項目を作成することです。

GIN インデックスは、ネイティブ PostgreSQL 演算子と Hologres 演算子を使用して作成できます。次のセクションでは例を示します。

PostgreSQL が提供するネイティブ演算子

  • jsonb_ops 演算子を使用してインデックスを作成します。

    -- 1. テーブルを作成します。
    BEGIN;
    DROP TABLE IF EXISTS json_table;
    
    CREATE TABLE IF NOT EXISTS json_table
    (
        id INT
        ,j jsonb
    );
    COMMIT;
    
    -- 2. jsonb_ops 演算子を使用してインデックスを作成します。
    CREATE INDEX index_json on json_table USING GIN(j);
    
    -- 3. テーブルにデータを挿入します。
    INSERT INTO json_table VALUES
    (1, '{"key1": 1, "key2": [1, 2], "key3": {"a": "b"}}') ,
    (1, '{"key1": 1}'),
    (2, '{"key2": [1, 2], "key3": {"a": "b"}}') ;
    
    -- 4. テーブルからデータをクエリします。
    SELECT  * FROM    json_table WHERE   j ? 'key1';
    -- 次の結果が返されます。
     id |                        j
    ----+-------------------------------------------------
      1 | {"key1": 1, "key2": [1, 2], "key3": {"a": "b"}}
      1 | {"key1": 1}
    
                        

    EXPLAIN ステートメントを実行して、実行プランをクエリします。サンプルコード:

    explain SELECT  * FROM    json_table WHERE   j ? 'key1';
    
    QUERY PLAN
    Gather  (cost=0.00..0.26 rows=1000 width=12)
      ->  Local Gather  (cost=0.00..0.23 rows=1000 width=12)
            ->  Decode  (cost=0.00..0.23 rows=1000 width=12)
                  ->  Bitmap Heap Scan on json_table  (cost=0.00..0.13 rows=1000 width=12)
                        Recheck Cond: (j ? 'key1'::text)
                        ->  Bitmap Index Scan on index_json  (cost=0.00..0.00 rows=0 width=0)
                              Index Cond: (j ? 'key1'::text)
    Optimizer: HQO version 1.3.0

    前の結果から、実行プランに Index Scan ステップが含まれていることがわかります。これは、クエリ中にインデックスが使用されていることを示しています。

  • jsonb_path_ops 演算子を使用してインデックスを作成します。

    -- 1. テーブルを作成します。
    BEGIN;
    DROP TABLE IF EXISTS json_table;
    
    CREATE TABLE IF NOT EXISTS json_table
    (
        id INT
        ,j jsonb
    );
    COMMIT;
    
    -- 2. jsonb_ops 演算子を使用してインデックスを作成します。
    CREATE INDEX index_json on json_table USING GIN(j jsonb_path_ops);
    
    -- 3. テーブルにデータを挿入します。
    INSERT INTO json_table (
        SELECT
            i,
            ('{
                "key1": "'||i||'"
                ,"key2": "'||i%100||'"
                ,"key3": "'||i%1000 ||'"
                ,"key4": "'||i%10000||'"
                ,"key5": "'||i%100000||'"
            }')::jsonb
        FROM generate_series(1, 1000000) i
    ) ;
    
    -- 4. テーブルから '{"key1": "10"}' を含むデータをクエリします。
    SELECT  * FROM    json_table WHERE   j @> '{"key1": "10"}'::JSONB;
    -- 次の結果が返されます。
     id |                                   j
    ----+------------------------------------------------------------------------
     10 | {"key1": "10", "key2": "10", "key3": "10", "key4": "10", "key5": "10"}
    (1 row)
                        

    EXPLAIN ステートメントを実行して、実行プランをクエリします。サンプルコード:

    explain SELECT  * FROM    json_table WHERE   j @> '{"key1": "10"}'::JSONB;
    
                                            QUERY PLAN
    -------------------------------------------------------------------------------------------
     Gather  (cost=0.00..0.26 rows=1000 width=12)
       ->  Local Gather  (cost=0.00..0.23 rows=1000 width=12)
             ->  Decode  (cost=0.00..0.23 rows=1000 width=12)
                   ->  Bitmap Heap Scan on json_table  (cost=0.00..0.13 rows=1000 width=12)
                         Recheck Cond: (j @> '{"key1": "10"}'::jsonb)
                         ->  Bitmap Index Scan on index_json  (cost=0.00..0.00 rows=0 width=0)
                               Index Cond: (j @> '{"key1": "10"}'::jsonb)
     Optimizer: HQO version 1.3.0
    (8 rows)
                        

    前の結果から、実行プランに Index Scan ステップが含まれていることがわかります。これは、クエリ中にインデックスが使用されていることを示しています。

Hologres が提供する演算子

ネイティブ PostgreSQL が提供する JSONB データ型フィールドの GIN インデックスは、正確なデータを取得するために使用できません。データは取得後に再確認する必要があります。インデックスを使用しても、クエリのパフォーマンスが向上しない場合があります。Hologres は ops_class 演算子を提供しており、この演算子はデータの再確認を必要としません。演算子を指定しない場合、デフォルトで ops_class 演算子が使用されます。

説明

ops_class 演算子は、長さが 1 ~ 127 バイトのインデックスをサポートしています。インデックスの長さが 127 バイトを超える場合、インデックスは切り捨てられます。したがって、インデックスを作成する JSONB データ型のフィールドも、インデックスの長さが 127 バイトを超える場合は切り捨てられます。この場合、データを再確認する必要があります。EXPLAIN ANALYZE ステートメントを実行して、データが再確認されているかどうかを確認できます。

jsonb_holo_ops 演算子クラスは jsonb_ops 演算子クラスに対応し、次の演算子を使用したフィルタリング操作をサポートしています:?, ?|, ?&, @>jsonb_holo_path_ops 演算子クラスは jsonb_path_ops 演算子クラスに対応します。@> 演算子を使用したフィルタリング操作のみがサポートされています。

  • jsonb_holo_ops 演算子を使用してインデックスを作成します。

    -- 1. テーブルを作成します。
    BEGIN ;
    DROP TABLE IF EXISTS json_table;
    CREATE TABLE IF NOT EXISTS json_table
    (
        id INT
        ,j jsonb
    );
    COMMIT ;
    
    -- 2. jsonb_holo_ops 演算子を使用してインデックスを作成します。
    CREATE INDEX index_json on json_table USING GIN(j jsonb_holo_ops);
    
    -- 3. テーブルにデータを挿入します。
    INSERT INTO json_table VALUES
    (1, '{"key1": 1, "key2": [1, 2], "key3": {"a": "b"}}') ,
    (1, '{"key1": 1}'),
    (2, '{"key2": [1, 2], "key3": {"a": "b"}}') ;
    
    -- 4. テーブルからデータをクエリします。
    SELECT  * FROM    json_table WHERE   j ? 'key1';
    -- 次の結果が返されます。
     id |                        j
    ----+-------------------------------------------------
      1 | {"key1": 1}
      1 | {"key1": 1, "key2": [1, 2], "key3": {"a": "b"}}
    (2 rows)
  • jsonb_holo_path_ops 演算子を使用してインデックスを作成します。

    -- 1. テーブルを作成します。
    BEGIN ;
    DROP TABLE IF EXISTS json_table;
    CREATE TABLE IF NOT EXISTS json_table
    (
        id INT
        ,j jsonb
    );
    
    -- 2. jsonb_holo_path_ops 演算子を使用してインデックスを作成します。
    CREATE INDEX index_json on json_table USING GIN(j jsonb_holo_path_ops);
    
    -- 3. テーブルにデータを挿入します。
    INSERT INTO json_table (
        SELECT
            i,
            ('{
                "key1": "'||i||'"
                ,"key2": "'||i%100||'"
                ,"key3": "'||i%1000 ||'"
                ,"key4": "'||i%10000||'"
                ,"key5": "'||i%100000||'"
            }')::jsonb
        FROM generate_series(1, 1000000) i
    ) ;
    
    -- 4. テーブルから '{"key1": "10"}' を含むデータをクエリします。
    SELECT  * FROM  json_table WHERE j @> '{"key1": "10"}'::JSONB ;
    -- 次の結果が返されます。
     id |                                   j
    ----+------------------------------------------------------------------------
     10 | {"key1": "10", "key2": "10", "key3": "10", "key4": "10", "key5": "10"}
    (1 row)

データインポートの例: Realtime Compute for Apache Flink から Hologres に JSONB データをリアルタイムでインポートする

Realtime Compute for Apache Flink から Hologres にデータをインポートする場合、SQL デプロイメントで Realtime Compute for Apache Flink によってサポートされているデータ型にフィールドのデータ型を定義する必要があります。Hologres に内部テーブルを作成する場合、Hologres によってサポートされているデータ型にフィールドのデータ型を定義する必要があります。Realtime Compute for Apache Flink と Hologres 間のデータ型のマッピングの詳細については、「Realtime Compute for Apache Flink と Hologres 間のデータ型のマッピング」をご参照ください。

Realtime Compute for Apache Flink から Hologres に JSON データをインポートする場合は、Realtime Compute for Apache Flink の SQL デプロイメントのソーステーブルと結果テーブルで JSON データのデータ型として VARCHAR を定義する必要があります。Hologres 内部テーブルでは、データ型として JSONB を定義します。例:

  • Hologres に内部テーブルを作成し、message フィールドのデータ型として JSONB を定義します。

    BEGIN ;
    DROP TABLE IF EXISTS holo_internal_table;
    CREATE TABLE IF NOT EXISTS holo_internal_table
    (
        id BIGINT NOT NULL,
        message JSONB NOT NULL
    );
    CALL set_table_property('holo_internal_table', 'distribution_key', 'id');
    COMMIT ;
  • Realtime Compute for Apache Flink の SQL デプロイメントで、ソース テーブルと結果テーブルの message フィールドのデータ型として VARCHAR を定義します。次に、Hologres にデータを書き込みます。

    CREATE TEMPORARY TABLE randomSource (
        id BIGINT,
        message VARCHAR
      )
    WITH ('connector' = 'datagen');
    
    CREATE TEMPORARY TABLE sink_holo (
        id BIGINT,
        message VARCHAR
      )
    WITH (
         'connector' = 'hologres',
        'dbname'='<yourDBname>',  -- 接続先の Hologres データベースの名前。
        'tablename'='<holo_internal_table>', -- データが書き込まれる Hologres テーブルの名前。
        'username'='<yourUsername>', -- Alibaba Cloud アカウントの AccessKey ID。
        'password'='<yourPassword>', -- Alibaba Cloud アカウントの AccessKey シークレット。
        'endpoint'='<yourEndpoint>', -- Hologres インスタンスの VPC エンドポイント。
      );
    
    INSERT INTO sink_holo
    SELECT 
      1,
      '{"k":"v"}'
    FROM
      randomSource;

JSONB データ型の列指向ストレージのサポート

GIN インデックスは、コンピューティング層でのみパフォーマンスを向上させるために使用されます。コンピューティングプロセスでは、JSON コンテンツ全体をスキャンする必要があります。Hologres V1.3 以降では、ストレージ層での最適化に基づいて、JSONB 型のデータの列指向ストレージをサポートしています。JSONB 型のデータは、構造化データのように列に格納できます。これにより、データ圧縮の効率が向上し、JSONB 形式のデータのクエリが高速化されます。

JSONB 形式のデータの列指向ストレージの詳細については、JSONB 形式のデータの列指向ストレージをご参照ください。