状態データベースの問合せ

このトピックでは、ブロックチェーン台帳の現在の状態データが格納されている状態データベースを問い合せる方法を理解するのに役立つ情報を示します。

状態データベースとは

ブロックチェーン・レジャーの現在の状態データは、状態データベースに格納されます。

Oracle Blockchain Platformチェーンコードを開発するときに、リッチ問合せを実行することで状態データベースからデータを抽出できます。Oracle Blockchain Platformでは、SQLリッチ問合せ構文およびCouchDB検索式を使用してリッチ問合せがサポートされています。「SQLリッチ問合せの構文」および「CouchDBリッチ問合せの構文」を参照してください。

Hyperledger Fabricでは、SQLリッチ問合せがサポートされていません。Oracle Blockchain PlatformネットワークにHyperledger Fabric参加者が含まれている場合は、次のことを確認する必要があります:

  • チェーンコードにSQLリッチ問合せ構文が含まれる場合、これらのチェーンコードはOracle Blockchain Platformを使用するメンバー・ピアにのみインストールします。

  • チェーンコードをOracle Blockchain PlatformおよびHyperledger Fabricピアにインストールする必要がある場合は、チェーンコードでCouchDB構文を使用し、Hyperledger FabricピアがCouchDBを状態データベース・リポジトリとして使用するように設定されていることを確認します。Oracle Blockchain Platformでは、CouchDBを処理できます。

Oracle Blockchain PlatformはBerkeley DBとどのように連携しますか。

Oracle Blockchain Platformは、状態データベースとしてOracle Berkeley DBを使用します。Oracle Blockchain Platformは、SQLite拡張に基づいてBerkeley DBにリレーショナル表を作成します。このアーキテクチャは、SQLリッチ問合せを検証するための堅牢でパフォーマンスの高い方法を提供します。

チャネル・チェーンコードごとに、Oracle Blockchain PlatformによってBerkeley DB表が作成されます。この表には状態情報データが格納されており、JSON形式データを使用しているかどうかによって、少なくともkeyという名前のキー列と、valueまたはvalueJsonという名前の値列があります。

列名 タイプ 説明
key テキスト 状態表のキー列。
value テキスト 状態表の値列。
valueJson テキスト 状態表のJSON形式の値列。

valueJson列とvalue列は相互排他的です。したがって、チェーンコードでJSON値がキーに割り当てられると、valueJson列はその値を保持し、value列はnullに設定されます。チェーンコードがキーに非JSON値を割り当てた場合、valueJson列はnullに設定され、value列に値が保持されます。

状態データベースの例

Car Dealerサンプルの状態データベースのキーとその値の例を次に示します:

キー valueJson
abg1234 null {"docType": "vehiclePart", "serialNumber": "abg1234", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 2020", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
abg1235 null {"docType": "vehiclePart", "serialNumber": "abg1235", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 4050", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
ser1236 null {"docType": "vehiclePart", "serialNumber": "ser1236", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "seatbelt 10020", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
bra1238 null {"docType": "vehiclePart", "serialNumber": "bra1238", "assembler": "bobs-bits", "assemblyDate": 1502688979, "name": "brakepad 4200", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
dtrt10001 null {"docType": "車"、 "chassisNumber": "dtrt10001"、 "メーカー": "デトロイトオート"、 "モデル": "クーペ"、 "assemblyDate": 1502688979、 "airbagSerialNumber": "abg1235"、 "所有者": "サムディーラー"、 "リコール": false、 "recallDate": 1502688979

コンソールでのリッチ問合せ

管理者は、コンソールからリッチ・クエリーを実行および分析できます。

  1. コンソールに移動し、チャネル・タブを選択します。
  2. チャネル表で、問合せを実行するチャネルを探し、チャネルの他のアクションボタンをクリックして、リッチ問合せの分析をクリックします。「リッチ問合せの分析」ダイアログが表示されます。
  3. 状態データベースに対してリッチ問合せを実行するには、「問合せ実行」を選択します。
    1. 「チェーンコード」で、問い合せるチャネルにデプロイされているチェーンコードを選択します。
    2. 「ピア」で、問い合せるピアを選択します。
      選択したチェーンコードを実行している現在の組織の同僚のみが使用可能です。
    3. 「リッチ問合せ」に、実行および分析するリッチ問合せを入力します。
      問合せ形式は、リッチ問合せ構文に従う必要があります。リッチ問合せ構文の詳細は、「サポートされるリッチ問合せ構文」を参照してください。
    4. 「結果行制限」で、スライダをフェッチする結果行の最大数に移動します。最大50行の結果をフェッチできます。
  4. 問合せの実行計画を取得するには、「問合せ計画の説明」を選択します。問合せ実行計画は、問合せを実行するために実行された一連の操作です。
    1. 「チェーンコード」で、問い合せるチャネルにデプロイされているチェーンコードを選択します。
    2. 「ピア」で、問い合せるピアを選択します。
    3. 「コレクション」で、状態データベースまたはプライベート・データ収集を選択します。
    4. 「リッチ問合せ」に、リッチ問合せを入力します。
      この問合せには、explainキーワードは必要ありません。
      たとえば: select * from <state>
  5. 「実行」をクリックします。「結果」フィールドには、問合せ結果表または実行計画が表示されます。結果表を.csvファイルとしてエクスポートするには、「Export」をクリックします。
    結果表のサイズは1MBに制限されます。この制限を超えないように、問合せを絞り込む必要がある場合があります。

サポートされているリッチ問合せの構文

Oracle Blockchain Platformでは、SQLリッチ問合せとCouchDBリッチ問合せの2種類のリッチ問合せ構文がサポートされています。

SQLリッチ問合せ構文

Berkeley DB JSON拡張は、SQL関数の形式をとっています。

始める前に

次の点に注意してください。

  • アクセスできるのは、問合せを実行しているチャネル・チェーンコード(<STATE>)のみです。
  • SELECT文のみがサポートされます。
  • 状態データベース表は変更できません。
  • リッチ問合せ式に使用できるSELECT文は1つのみです。
  • このトピックの例では、リッチ問合せを作成する方法をいくつか示します。SQLデータベースに問合せするための通常の完全なSQL構文に対するアクセス権があります。
  • JSON1拡張(SQLite拡張)にアクセスできます。JSON1 ExtensionおよびSQL As Understood by SQLiteを参照してください。

チェーンコードの作成およびテストの詳細は、「チェーンコードの開発」を参照してください。

問合せにおける状態データベースの参照方法

状態データベース表名は、Oracle Blockchain Platformによって内部管理されるため、チェーンコードの記述時にデータベースの物理名を知っている必要はありません。

かわりに、<STATE>別名を使用して表名を参照する必要があります。たとえば、select key, value from <STATE>です。

<STATE>別名は大/小文字が区別されないため、<state><STATE>または<StAtE>のようなものを使用できます。

すべてのキーの取得

次の構文を使用します:

SELECT key FROM <STATE>

たとえば、この構文を使用してCar Dealerサンプルを問い合せると、次のキーのリストが取得されます:

キー

abg1234

abg1235

ser1236

bra1238

dtrt10001

すべてのキーと値の取得 キーのアルファベット順

次の構文を使用します:

SELECT key AS serialNumber, valueJson AS details FROM  <state> ORDER BY key

たとえば、この構文を使用してCar Dealerサンプルを問い合せると、次の結果が得られます:

serialNumber 詳細
abg1234 {"docType": "vehiclePart", "serialNumber": "abg1234", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 2020", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
abg1235 {"docType": "vehiclePart", "serialNumber": "abg1235", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 4050", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
bra1238 {"docType": "vehiclePart", "serialNumber": "bra1238", "assembler": "bobs-bits", "assemblyDate": 1502688979, "name": "brakepad 4200", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
dtrt10001 {"docType": "車"、 "chassisNumber": "dtrt10001"、 "メーカー": "デトロイトオート"、 "モデル": "クーペ"、 "assemblyDate": 1502688979、 "airbagSerialNumber": "abg1235"、 "所有者": "サムディーラー"、 "リコール": false、 "recallDate": 1502688979
ser1236 {"docType": "vehiclePart", "serialNumber": "ser1236", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "seatbelt 10020", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}

"abg"で始まるすべてのキーおよび値の取得

次の構文を使用します:

SELECT key AS serialNumber, valueJson AS details FROM <state> WHERE key LIKE 'abg%'SELECT key, value FROM <STATE>

たとえば、この構文を使用してCar Dealerサンプルを問い合せると、次の結果が得られます:

serialNumber 詳細
abg1234 {"docType": "vehiclePart", "serialNumber": "abg1234", "assembler": "panama-parts", "assemblyDate": "1502688979", "name": "airbag 2020", "owner": "Detroit Auto", "recall": "false", "recallDate": "1502688979"}
abg1235 {"docType": "vehiclePart", "serialNumber": "abg1235", "assembler": "panama-parts", "assemblyDate": "1502688979", "name": "airbag 4050", "owner": "Detroit Auto", "recall": "false", "recallDate": "1502688979"}

"Detroit Auto"が所有する車両部品を含む値を持つすべてのキーの取得

次の構文を使用します:

SELECT key FROM <state> WHERE json_extract(valueJson, '$.docType') = 'vehiclePart' AND json_extract(valueJson, '$.owner') = 'Detroit Auto'

たとえば、この構文を使用してCar Dealerサンプルを問い合せると、次のキーのリストが取得されます:

キー

abg1234

abg1235

ser1236

bra1238

"Sam Dealer"が所有するすべての車のモデルおよびメーカーの取得

次の構文を使用します:

SELECT json_extract(valueJson, '$.model') AS model, json_extract(valueJson, '$.manufacturer') AS manufacturer FROM <state> WHERE json_extract(valueJson, '$.docType') = 'vehicle' AND json_extract(valueJson, '$.owner') = 'Sam Dealer'

たとえば、この構文を使用してCar Dealerサンプルを問い合せると、次の結果が得られます:

モデル メーカー
クーペ型自動車 デトロイトオート

状態値がJSON配列の場合、次の構文を使用して、Sam Dealerが所有するすべての車のモデルと製造元を取得できます:

SELECT json_extract(j.value, '$.model') AS model, json_extract(j.value, '$.manufacturer') AS manufacturer FROM <state> s, json_each(json_extract(s.valueJson,'$')) j WHERE json_valid(j.value) AND json_extract(j.value, '$.owner') = 'Sam Dealer'

CouchDBリッチ問合せの構文

CouchDB構文を含むチェーンコードをOracle Blockchain Platformに移行する場合またはOracle Blockchain Platformネットワークに参加しているHyperledger Fabricピアにインストールするチェーンコードを記述する必要がある場合、このトピックの情報を使用します。

新しいチェーンコードを作成する場合は、Oracleでは、Berkeley DBでOracle Blockchain Platformが提供するパフォーマンス上のメリットを活用するために、SQLリッチ問合せを使用することをお薦めします。

チェーンコードの作成およびテストの詳細は、「チェーンコードの開発」を参照してください。

サポートされていない問合せパラメータおよびセレクタ構文

Oracle Blockchain Platformでは、use_indexパラメータはサポートされていません。これを使用した場合、Oracle Blockchain Platformではこのパラメータが無視され、問題のStateDBに定義されている索引が自動的に選択されます。

パラメータ タイプ 説明
use_index json 特定の索引を使用するように問合せに指示します。

車のすべてのモデル、メーカーおよび所有者の取得と所有者による順序付け

次の式を使用します:

{ 
  "fields": ["model", "manufacturer", "owner"], 
  "sort": [   
    "owner" 
   ]
}

"Sam Dealer"が所有するすべての自動車のモデルとメーカーの取得

次の式を使用します:

{ 
  "fields": ["model", "manufacturer"], 
  "selector": {   
    "docType"  : "vehicle",
     "owner" : "Sam Dealer" 
  }
}

状態データベースの索引

状態データベースには大量のデータが格納されていることがあります。このような場合、Oracle Blockchain Platformでは索引を使用してデータ・アクセスを改善します。

デフォルト索引

チェーンコードをデプロイすると、Oracle Blockchain Platformによって2つの索引が作成されます。

  • キー索引 — キー列に作成されます。

  • 値索引 — 値列に作成されます。

カスタム索引

カスタム索引を作成する必要があります。これらの索引は、状態表のコンテキストで解決される任意の式を使用して定義します。Berkeley DBに対して作成されたカスタム索引はSQLite構文に依存しますが、それ以外の場合はHyperledger Fabricによって提供される同じCouchDB実装に従います。

大規模データ・セットに対するWHERE文とORDER BY文のパフォーマンスを大幅に向上させるために、カスタム索引を使用できることに注意してください。カスタム索引を使用するとデータ挿入が遅くなるため、その使用には適切な判断が必要です。

各カスタム索引は、複合索引をサポートする式の配列として定義され、1つのファイル内にJSONドキュメントとして表現されます(ファイルごとに1つの索引が存在します)。このファイルは、statedb/relationaldb/indexesというディレクトリ構造の"indexes"というフォルダ内のチェーンコードとともにパッケージ化する必要があります。「チェーンコードのインストール時にCouchDB索引を追加する方法」を参照してください。

カスタム索引の例

この項のカスタム索引の例は、Car Dealerサンプルを使用しています。

例1— この例では、WHEREおよびORDER BY式のコンテキストでの json_extract式の使用を索引付けします。

{"indexExpressions": ["json_extract(valueJson, '$.owner')"]}

たとえば次のようにします。

SELECT … FROM … ORDER BY json_extract(valueJson, '$.owner')

例2— この例では、WHERE式およびORDER BY式のコンテキストで、2つのjson_extract式の複合使用を索引付けしています。

{"indexExpressions": ["json_extract(valueJson, '$.docType')", "json_extract(valueJson, '$.owner')"]}

たとえば次のようにします。

SELECT … FROM … WHERE json_extract(valueJson, '$.docType') = 'vehiclePart' AND json_extract(valueJson, '$.owner') = 'Detroit Auto'

例3 - この例では、例1で説明した索引と例2で説明した索引の2つの索引が作成されます。各JSON構造は個別のファイルに含める必要があります。各ファイルには、単一の索引(例1のような単純索引または例2のような複合索引)を記述します。

索引1: {"indexExpressions": ["json_extract(valueJson, '$.owner')"]}

索引2: {"indexExpressions": ["json_extract(valueJson, '$owner')", "json_extract(valueJson, '$.docType')"]}

次の例では、索引2は問合せのWHERE部分のAND式に適用されますが、索引1はORDER BY式に適用されます:

SELECT … FROM … WHERE json_extract(valueJson, '$.docType') = 'vehiclePart' AND json_extract(valueJson, '$.owner') = 'Detroit Auto' ORDER BY json_extract(valueJson, '$.owner')

JSONドキュメントの形式

JSONドキュメントの形式は次のとおりです。

{"indexExpressions": [expr1, ..., exprN]}

たとえば次のようにします。

{"indexExpressions": ["json_extract(valueJson, '$.owner')"]}

リッチ問合せの検証の相違点

CouchDBリッチ問合せを含む標準Hyperledger Fabricと、Oracle Berkeley DBリッチ問合せの動作が異なる場合があります。

CouchDBを含む標準のHyperledger Fabricでは、問合せから返されたキーと値の各ペアはトランザクションの読取りセットに追加され、検証時に問合せを再実行することなく検証されます。Berkeley DBでは、返されたキーと値のペアは読取りセットに追加されませんが、リッチ問合せの結果はMerkleツリーでハッシュ化され、検証時に問合せの再実行に対して検証されます。

ネイティブHyperledger Fabricでは、リッチ問合せに対するデータ保護はありません。ただし、Berkeley DBには、Merkleツリー・ハッシュ値を読取りセットに追加し、リッチ問合せを再実行し、検証段階でMerkleツリー値を再計算することでリッチ問合せを保護して検証する機能があります。Berkeley DBを使用するOracle Blockchain Platformでの検証は正確さが高いため、チェーンコードの呼出しに頻繁な疑似読取りのフラグが設定されることがあります。