GridDB プログラミングガイド

Revision: 4.5.0-236

1 はじめに

本書では、GridDBのアプリケーションプログラミングについて説明します。

本書は、GridDBを用いたシステム設計・開発を行う設計・開発者の方を対象としています。

本書は、以下のような構成となっています。

2 概要

2.1 開発言語

GridDBのアプリケーションプログラミングインタフェースには、基本的なデータアクセスとTQLの実行ができるNoSQLインタフェースと、 SQL92に準拠したSQLを実行できるNewSQLインタフェースの2種類があります。

NoSQLインタフェースは、NewSQLインタフェースに比べてSQLの処理部を介さないためデータ登録や検索の処理が高速に行えます。一方、NewSQLインタフェースは、 SQLを用いたデータ分析やBI(Business Intelligence)やETL(Extract Transfer Load)ツールからのアクセスなどができます。

NoSQLインタフェースとNewSQLインタフェース
NoSQLインタフェースとNewSQLインタフェース
I/F 特長 開発言語 API名称
NoSQLインタフェース - 基本的なデータアクセスとTQLの実行
- 独自のAPI
- データ登録や検索の処理が高速
Java
C
Python
Node.js
Go
Java API
C API
Python API
Node.js API
Go API
NewSQLインタフェース - SQL92に準拠したSQLの実行
- 標準仕様に準拠したAPI
- SQLの並列分散処理
Java
C
JDBC
ODBC(*1)

(*1) ODBCはBIツールなどのシステムとの連携で使用します。

[メモ]

2.2 サポート範囲

NoSQLインタフェースとNewSQLインタフェースでは、サポートしている機能やデータ型の範囲が異なります。本節では、各インタフェースのサポート範囲について説明します。サポート範囲の詳細は、「付録」をご参照ください。

2.2.1 データ型

GridDBのデータ型には、基本型と複合型の2種類のデータ型があります。それぞれのサポート範囲を以下に示します。

基本型のサポート

GridDBのデータ型 NoSQLインタフェース NewSQLインタフェース
BOOL型
STRING型
BYTE型
SHORT型
INTEGER型
LONG型
FLOAT型
DOUBLE型
TIMESTAMP型
GEOMETRY型 ×
BLOB型

(※ ○:サポート、△:一部サポート、×:未サポート)

複合型のサポート

GridDBのデータ型 NoSQLインタフェース NewSQLインタフェース
BOOL配列型 ×
STRING配列型 ×
BYTE配列型 ×
SHORT配列型 ×
INTEGER配列型 ×
LONG配列型 ×
FLOAT配列型 ×
DOUBLE配列型 ×
TIMESTAMP配列型 ×

(※ ○:サポート、×:未サポート)

2.2.2 機能

GridDBの主な機能についてのサポート範囲を以下に示します。

基本機能のサポート

GridDBの機能 NoSQLインタフェース NewSQLインタフェース
クラスタへの接続
--------------------------- -------------------------- --------------------------
コンテナ作成/削除 ○(SQL)
ロウ登録/削除 ○(SQL)
TQL実行 ×
SQL実行 ×
コミット/ロールバック × 自動コミットのみ
--------------------------- -------------------------- --------------------------
索引作成/削除 ○(SQL)
--------------------------- -------------------------- --------------------------
コンテナ名一覧の取得
カラム情報の取得

※ ○:サポート、○(SQL):SQLによるサポート、×:未サポート

拡張機能のサポート

GridDBの機能 NoSQLインタフェース NewSQLインタフェース
トリガ作成 ×
アフィニティ設定 ○(SQL)
期限解放設定
カラム圧縮設定 ×
パーティションコンテナ作成 × ○(SQL)

※ ○:サポート、△:一部サポート、×:未サポート

3 Java API (NoSQLインタフェース)

3.1 Java APIを利用したアプリケーションの開発

3.1.1 開発実行環境の構築

Java APIのアプリケーションを開発するには、以下のパッケージをインストールする必要があります。

パッケージ名 ファイル名 内容
griddb-ee-java_lib griddb-ee-java_lib-X.X.X-linux.x86_64.rpm Java APIのライブラリ(gridstore.jar, gridstore-conf.jar, gridstore-advanced.jar, gridstore-jdbc.jar)が含まれます

※: X.X.XはGridDBのバージョン

アプリケーションの開発や実行を行う際には、以下のライブラリをクラスパスに指定してください。

また、SSL機能を利用してGridDBクラスタとクライアントの通信を保護する場合には、以下のライブラリも追加でクラスパスに指定してください。

3.1.2 サンプルプログラムの実行

サンプルプログラムのコンパイルと実行方法を説明します。

コンパイルと実行の際には、クラスパスにライブラリgridstore.jarを設定します。必要に応じてロギングなどのライブラリも設定してください。

サンプルプログラム一覧

分類 プログラム名 内容 作成するコンテナ名
クラスタに接続する Connect.java マルチキャスト方式でクラスタに接続して切断します。 -
コレクションを作成する(メソッド) CreateCollectionByMethod.java メソッドでスキーマを指定する方法を用いて、コレクションを作成します。 SampleJava_collection1
コレクションを作成する(クラス定義) CreateCollectionByClass.java クラス定義でスキーマを指定する方法を用いて、コレクションを作成します。 SampleJava_collection2
時系列コンテナを作成する(メソッド) CreateTimeSeriesByMethod.java メソッドでスキーマを指定する方法を用いて、時系列コンテナを作成します。 SampleJava_timeseries1
ロウを登録する PutRow.java ひとつのコンテナにひとつのロウを登録します。 SampleJava_PutRow
複数のロウを登録する PutRows.java ひとつのコンテナに複数のロウを登録します。 SampleJava_PutRows
ロウを取得する GetRow.java ロウキーを指定してコンテナからロウを取得します。 SampleJava_GetRow
TQLでロウを検索する TQLSelect.java TQLのSELECT文でロウを取得します。 SampleJava_TQLSelect
TQLの集計関数を実行する TQLAggregation.java TQLのSELECT文で集計演算を実行します。 SampleJava_TQLAggregation
複数コンテナにロウを登録する MultiPut.java 複数のコンテナにロウを一括で登録します。 SampleJava_MultiPut1, SampleJava_MultiPut2
複数コンテナからロウを取得する MultiGet.java 複数のコンテナからロウを一括で取得します。 SampleJava_MultiGet1, SampleJava_MultiGet2
複数コンテナにTQLを実行する FetchAll.java 複数のコンテナにTQLを一括で実行します。 SampleJava_FetchAll1, SampleJava_FetchAll2
バイナリデータを登録・検索する BlobData.java バイナリデータをコンテナに登録して、コンテナから取得します。 SampleJava_BlobData
ロウを更新する UpdateRowByTQL.java TQLで取得したRowSetを用いて、ロウを更新します。 SampleJava_UpdateRowByTQL
ロウを削除する(ロウキー) RemoveRowByRowkey.java ロウキーを指定してロウを削除します。 SampleJava_RemoveRowByRowkey
ロウを削除する(TQL) RemoveRowByTQL.java TQLで検索したロウを削除します。 SampleJava_RemoveRowByTQL
索引を作成する CreateIndex.java 索引を作成します。 SampleJava_Index
時系列の演算を行う TQLTimeseries.java 時系列データに対して様々な演算を行います。 SampleJava_TQLTimeseries
期限解放を設定する TimeSeriesRowExpiration.java 期限解放を設定します。 SampleJava_RowExpiration
ロウの圧縮を設定する TimeSeriesCompression.java ロウの圧縮を設定します。 SampleJava_Compression
配列型のデータを扱う ArrayData.java 配列型のデータの登録と検索を行います。 SampleJava_ArrayData
空間型のデータを扱う GeometryData.java 空間型のデータの登録と検索を行います。 SampleJava_GeometryData
コンテナ名一覧を取得する ContainerNames.java コンテナ名の一覧を取得します。
コンテナのスキーマ情報を取得する ContainerInformation.java コンテナのスキーマ情報を取得します。 SampleJava_Info
複合ロウキーを使って複数コンテナからロウを取得する CompositeKeyMultiGet.java 複合ロウキーを使って複数のコンテナからロウを一括で取得します。 SampleJava_CompositeKeyMultiGet1, SampleJava_CompositeKeyMultiGet2

3.2 プログラミングの基礎

Java APIを用いた基礎的なプログラミングを説明します。

3.2.1 クラスタに接続する

データの登録や検索などの操作を行うためには、クラスタに接続する必要があります。接続処理では以下のメソッドを用います。

分類 メソッド
GridStoreFactoryインスタンス取得 GridStoreFactory GridStoreFactory.getInstance()
GridStoreインスタンス取得 GridStore GridStoreFactory.getGridStore(java.util.Properties properties)

クラスタへの接続を行うプログラムの例を以下に示します。

import java.util.Properties;

import com.toshiba.mwcloud.gs.GridStore;
import com.toshiba.mwcloud.gs.GridStoreFactory;

public class Connect {

    public static void main(String[] args){
        try {
            //===============================================
            // クラスタに接続する
            //===============================================
            //(1)接続情報を指定する (マルチキャスト方式)
            Properties prop = new Properties();
            prop.setProperty("notificationAddress", "239.0.0.1");
            prop.setProperty("notificationPort", "31999");
            prop.setProperty("clusterName", "myCluster");
            prop.setProperty("database", "public");
            prop.setProperty("user", "admin");
            prop.setProperty("password", "admin");
            prop.setProperty("applicationName", "SampleJava");

            //(2)GridStoreオブジェクトを生成する
            GridStore store = GridStoreFactory.getInstance().getGridStore(prop);

            //(3)コンテナ作成や取得などの操作を行うと、クラスタに接続される
            store.getContainer("dummyContainer");

            System.out.println("Connect to cluster");

            //===============================================
            // 終了処理
            //===============================================
            // (4)接続をクローズする
            store.close();
            System.out.println("success!");

        } catch ( Exception e ){
            e.printStackTrace();
        }
    }
}

接続処理の部分を説明します。

(1)クラスタのアドレスやユーザ、パスワードなどの接続情報をJavaのプロパティクラスに指定します。

(2)接続情報のプロパティを基に、GridStoreオブジェクトを生成します。

(3)GridStoreオブジェクトを用いてコンテナ作成や取得などの操作を行うと、GridDBクラスタへの接続処理が行われます。

(4)クローズで切断します。

3.2.1.1 接続方式

クラスタには、マルチキャスト方式、固定リスト方式、プロバイダ方式の3種類の接続方式があります。

接続方式 内容
マルチキャスト方式 マルチキャスト通信を用いた方式
固定リスト方式 クラスタを構成する全ノードのアドレスを直接指定する方式
プロバイダ方式 クラスタを構成する全ノードのアドレスをプロバイダを用いて提供する方式

アプリケーションからクラスタに接続する際には、クラスタ定義ファイルgs_cluster.jsonで定義されている接続方式に合わせて、アプリケーション側の設定を行う必要があります。

まずはクラスタ定義ファイルgs_cluster.jsonを参照し、使用されている接続方式を確認してください。次に接続方式に基づいて、対応する値をPropertiesオブジェクトに設定してください。

接続方式 アプリケーションで指定する
プロパティのキー
内容 指定する値
マルチキャスト方式 notificationAddress

notificationPort
マルチキャストのアドレス

マルチキャストのポート番号
/transaction/notificationAddressの値

/transaction/notificationPortの値
固定リスト方式 notificationMember クラスタを構成するノードのアドレスとポート番号のリスト /cluster/notificationMemberの/transaction/addressと/transaction/portをリスト形式にした値
プロバイダ方式 notificationProvider プロバイダのURL /cluster/notificationProvider/urlの値

3つの接続方式について、クラスタ定義ファイルgs_cluster.jsonの記述内容と対応する接続プログラムの例を示します。

マルチキャスト方式の例

固定リスト方式の例

プロバイダ方式の例

3.2.1.2 プロパティ

接続方式以外の主なプロパティは以下の項目です。その他のプロパティの詳細は、『GridDB Java APIリファレンス』(GridDB_Java_API_Reference.html)の「GridStoreFactory.getGridStore(java.util.Properties properties)」をご参照ください。

項目 プロパティのキー 必須 指定する値
クラスタ名 clusterName 必須 gs_cluster.jsonの/cluster/clusterNameに記載している値
データベース名 database publicデータベースに接続する場合は省略可
それ以外は必須
接続するデータベース名
ユーザ名 user 必須 接続するユーザ名(管理ユーザ・一般ユーザどちらも可)
パスワード password 必須 接続するユーザのパスワード
アプリケーション名 applicationName 省略可 アプリケーションを識別するための名前
(運用ツールgs_shでコネクション情報や実行中イベントを確認する時に表示されます)
タイムゾーン timeZone 省略可 時分で指定:±hh:mm または ±hhmm
タイムゾーンID:「Z」のみサポート
上位(JavaVM)の環境引継ぎ:auto
※省略時は「Z」相当
認証方式 authentication 省略可 認証方式として、INTERNAL(内部認証) / LDAP(LDAP認証)のいずれかを指定
SSL通信 sslMode 省略可 SSL通信として、PREFERRED(クラスタ設定に従う) / DISABLED(無効)のいずれかを指定
マルチキャストパケットを送出するインターフェースアドレス notificationInterfaceAddress 省略可 複数のネットワークインターフェースがあるときにクラスタのネットワーク構成をマルチキャスト方式にする場合は、マルチキャストパケットを送信するインターフェースのアドレスを指定

[メモ]

3.2.2 コンテナを作成する

コンテナを作成します。コンテナには、コレクションと時系列コンテナの2つの種類があります。コンテナ作成では、カラム名やデータ型などのスキーマを指定する必要があります。スキーマを指定する方法として、次の2つの方法があります。

[メモ]

3.2.2.1 メソッドでスキーマを指定する方法

コンテナのスキーマは、Java APIのメソッドを使用して動的に指定します。スキーマを表すコンテナ情報クラスContainerInfoやカラム情報クラスColumnInfoを用います。これらのクラスを用いてコンテナを作成するメソッドは以下の通りです。

分類 メソッド
コレクション作成 putCollection(String name, ContainerInfo info, boolean modifiable)
時系列コンテナ作成 putTimeSeries(String name, ContainerInfo info, boolean modifiable)
コンテナ(コレクション、または時系列コンテナ)作成 GridStore.putContainer(String name, ContainerInfo info, boolean modifiable)

[メモ]

3.2.2.1.1 コレクションを作成する putCollection

コレクション作成putCollectionを用いて、コレクションを作成するプログラムの全体を以下に示します。

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import com.toshiba.mwcloud.gs.Collection;
import com.toshiba.mwcloud.gs.ColumnInfo;
import com.toshiba.mwcloud.gs.ContainerInfo;
import com.toshiba.mwcloud.gs.GSType;
import com.toshiba.mwcloud.gs.GridStore;
import com.toshiba.mwcloud.gs.GridStoreFactory;
import com.toshiba.mwcloud.gs.Row;

public class CreateCollectionByMethod {

    public static void main(String[] args){
        try {
            //===============================================
            // クラスタに接続する
            //===============================================
            // 接続情報を指定する (マルチキャスト方式)
            Properties prop = new Properties();
            prop.setProperty("notificationAddress", "239.0.0.1");
            prop.setProperty("notificationPort", "31999");
            prop.setProperty("clusterName", "myCluster");
            prop.setProperty("database", "public");
            prop.setProperty("user", "admin");
            prop.setProperty("password", "admin");
            prop.setProperty("applicationName", "SampleJava");

            // GridStoreオブジェクトを生成する
            GridStore store = GridStoreFactory.getInstance().getGridStore(prop);
            // コンテナ作成や取得などの操作を行うと、クラスタに接続される
            store.getContainer("dummyContainer");

            //===============================================
            // コレクションを作成する
            //===============================================
            // (1)コンテナ情報オブジェクトを生成
            ContainerInfo containerInfo = new ContainerInfo();

            // (2)カラムの名前やデータ型をカラム情報オブジェクトにセット
            List<ColumnInfo> columnList = new ArrayList<ColumnInfo>();
            columnList.add(new ColumnInfo("id", GSType.INTEGER));
            columnList.add(new ColumnInfo("productName", GSType.STRING));
            columnList.add(new ColumnInfo("count", GSType.INTEGER));

            // (3)カラム情報をコンテナ情報オブジェクトに設定
            containerInfo.setColumnInfoList(columnList);

            // (4)ロウキーありの場合は設定する
            containerInfo.setRowKeyAssigned(true);

            // (5)コレクション作成
            Collection<Void, Row> collection = store.putCollection("SampleJava_collection1", containerInfo, false);

            System.out.println("Create Collection name=SampleJava_collection1");

            //===============================================
            // 終了処理
            //===============================================
            collection.close();
            store.close();
            System.out.println("success!");

        } catch ( Exception e ){
            e.printStackTrace();
        }
    }
}

コレクションを作成する箇所を説明します。 (2)カラム名やデータ型は、カラム情報ColumnInfoに指定します。複数のカラムがある場合は、ColumnInfoを複数生成します。 (3)ColumnInfoはリストオブジェクトに格納して、コンテナ情報ContainerInfoにセットします。 (5)この情報を用いて、putCollectionでコレクションを作成します。

[メモ]

3.2.2.1.2 時系列コンテナを作成する putTimeSeries

時系列コンテナ作成putTimeseries用いて、時系列コンテナを作成します。プログラム全体の流れはコレクションの作成と同様ですので、異なる部分のプログラムのみを示します。

//===============================================
// 時系列コンテナ作成する
//===============================================
// (1)コンテナ情報オブジェクトを生成
ContainerInfo containerInfo = new ContainerInfo();

// (2)カラムの名前やデータ型をカラム情報オブジェクトにセット
List<ColumnInfo> columnList = new ArrayList<ColumnInfo>();
columnList.add(new ColumnInfo("date", GSType.TIMESTAMP));
columnList.add(new ColumnInfo("value", GSType.DOUBLE));
containerInfo.setColumnInfoList(columnList);

// (3)ロウキーを設定 (時系列コンテナはロウキーの設定が必須)
containerInfo.setRowKeyAssigned(true);

// (4)時系列コンテナ作成
TimeSeries<Row> timeseries = store.putTimeSeries("SampleJava_timeseries1", containerInfo, false);

System.out.println("Create TimeSeries name=SampleJava_timeseries1");

[メモ]

3.2.2.1.3 コンテナを作成する putContainer

コンテナ作成putContainerメソッドは、コレクションと時系列コンテナのどちらでも作成することができます。コレクションと時系列コンテナの種別は、ContainerInfo.setTypeで指定します。

3.2.2.2 クラス定義でスキーマを指定する方法

Javaのクラス定義を用いて、コンテナのスキーマを指定します。 Javaのクラス変数が、GridDBのコンテナのカラムに対応付けされます。

例) 以下のようにJavaのクラスを定義した場合の対応付け

クラス変数の並びと同じ順番で、カラムは作成されます。データ型の対応付けの詳細は、『GridDB Java APIリファレンス』(GridDB_Java_API_Reference.html)の「Interface Container<K,R>」をご参照ください。

Javaのクラス定義を用いた方法では以下のメソッドを使用します。

分類 メソッド
コレクション作成 putCollection(String name, java.lang.Class rowType)
putCollection(String name, java.lang.Class rowType, boolean modifiable)
時系列コンテナ作成 putTimeSeries(String name, java.lang.Class rowType)
putTimeSeries(String name, java.lang.Class rowType, TimeSeriesProperties props, boolean modifiable)
コンテナ(コレクション、または時系列コンテナ)作成 putContainer(String name, java.lang.Class rowType, ContainerInfo info, boolean modifiable)

コレクション作成putCollectionを用いて、ロウキーありのコレクションを作成するプログラムの全体を以下に示します。(接続と終了処理はこれまでのプログラムと同様です。)

時系列コンテナの作成putTimeseriesとコンテナ作成putContainerの場合も、プログラムの流れは同様です。

import java.util.Properties;

import com.toshiba.mwcloud.gs.Collection;
import com.toshiba.mwcloud.gs.GridStore;
import com.toshiba.mwcloud.gs.GridStoreFactory;
import com.toshiba.mwcloud.gs.RowKey;

public class CreateCollectionByClass {

    // コレクションのスキーマ定義用のクラス
    static class Product{
        @RowKey int id; // ロウキーを設定
        String productName;
        int count;
    }

    public static void main(String[] args){
        try {
            //===============================================
            // クラスタに接続する
            //===============================================
            // 接続情報を指定する (マルチキャスト方式)
            Properties prop = new Properties();
            prop.setProperty("notificationAddress", "239.0.0.1");
            prop.setProperty("notificationPort", "31999");
            prop.setProperty("clusterName", "myCluster");
            prop.setProperty("database", "public");
            prop.setProperty("user", "admin");
            prop.setProperty("password", "admin");
            prop.setProperty("applicationName", "SampleJava");

            // GridStoreオブジェクトを生成する
            GridStore store = GridStoreFactory.getInstance().getGridStore(prop);
            // コンテナ作成や取得などの操作を行うと、クラスタに接続される
            store.getContainer("dummyContainer");

            //===============================================
            // コレクションを作成する
            //===============================================
            // (1)コレクション作成
            Collection<Integer, Product> collection = store.putCollection("SampleJava_collection2", Product.class, false);

            System.out.println("Create Collection name=SampleJava_collection2");

            //===============================================
            // 終了処理
            //===============================================
            collection.close();
            store.close();
            System.out.println("success!");

        } catch ( Exception e ){
            e.printStackTrace();
        }
    }
}

[メモ]

3.2.3 コンテナを取得する

コンテナの名前を指定して、コンテナを取得します。データの登録やTQLなどのロウ操作を行うためには、まずコンテナを取得する必要があります。

コンテナ取得には以下のメソッドがあります。ロウ操作する際のロウのタイプの違いによって2種類に分けられます。

Rowインタフェース

ユーザ定義のクラス

例) コンテナ取得(Rowインタフェースでロウ操作を行う)

// コレクション取得
Collection<Integer, Row> collection = store.getCollection("collection1");

// ロウ(Rowオブジェクト)を取得する
Row row = collection.get(0);

例) コンテナ取得(ユーザ定義のクラスでロウ操作を行う)

static class Product{
    int id;
    String productName;
    int count;
}
// 省略

// コレクション取得
Collection<Integer, Product> collection = store.getCollection("collection1", Product.class);

// ロウ(Productオブジェクト)を取得する
Product product = collection.get(0);

3.2.4 データを登録する

コンテナにロウを登録する場合は、以下のメソッドを使用します。

分類 メソッド
ロウ登録 Container.put(R row)

コレクションを作成し、ロウをひとつ登録するプログラムの全体を以下に示します。 (接続と終了処理はこれまでのプログラムと同様です。)

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import com.toshiba.mwcloud.gs.ColumnInfo;
import com.toshiba.mwcloud.gs.Container;
import com.toshiba.mwcloud.gs.ContainerInfo;
import com.toshiba.mwcloud.gs.GSType;
import com.toshiba.mwcloud.gs.GridStore;
import com.toshiba.mwcloud.gs.GridStoreFactory;
import com.toshiba.mwcloud.gs.Row;

public class PutRow {

    public static void main(String[] args){
        try {
            //===============================================
            // クラスタに接続する
            //===============================================
            // 接続情報を指定する (マルチキャスト方式)
            Properties prop = new Properties();
            prop.setProperty("notificationAddress", "239.0.0.1");
            prop.setProperty("notificationPort", "31999");
            prop.setProperty("clusterName", "myCluster");
            prop.setProperty("database", "public");
            prop.setProperty("user", "admin");
            prop.setProperty("password", "admin");
            prop.setProperty("applicationName", "SampleJava");

            // GridStoreオブジェクトを生成する
            GridStore store = GridStoreFactory.getInstance().getGridStore(prop);
            // コンテナ作成や取得などの操作を行うと、クラスタに接続される
            store.getContainer("dummyContainer");

            //===============================================
            // コレクションを作成する
            //===============================================
            ContainerInfo containerInfo = new ContainerInfo();
            List<ColumnInfo> columnList = new ArrayList<ColumnInfo>();
            columnList.add(new ColumnInfo("id", GSType.INTEGER));
            columnList.add(new ColumnInfo("productName", GSType.STRING));
            columnList.add(new ColumnInfo("count", GSType.INTEGER));
            containerInfo.setColumnInfoList(columnList);
            containerInfo.setRowKeyAssigned(true);

            String containerName = "SampleJava_PutRow";
            store.putCollection(containerName, containerInfo, false);
            System.out.println("Create Collection name="+containerName);


            //===============================================
            // ロウを登録する
            //===============================================
            //(1) Containerオブジェクトの取得
            Container<?, Row> container = store.getContainer(containerName);
            if ( container == null ){
                throw new Exception("Container not found.");
            }

            //(2) 空のロウオブジェクトの作成
            Row row = container.createRow();

            //(3) ロウオブジェクトにカラム値をセット
            row.setInteger(0, 0);
            row.setString(1, "display");
            row.setInteger(2, 150);

            //(4) ロウの登録
            container.put(row);

            System.out.println("Put Row num=1");

            //===============================================
            // 終了処理
            //===============================================
            container.close();
            store.close();
            System.out.println("success!");

        } catch ( Exception e ){
            e.printStackTrace();
        }
    }
}

ロウを登録する部分を説明します。 (1)ロウを登録するコンテナを取得します。指定した名前のコンテナが存在しない場合はnullが返ります。 (2)コンテナオブジェクトから、空のロウオブジェクトを生成します。 (3)空のロウオブジェクトに、登録するデータをセットします。 (4)コンテナにロウを登録します。

GridDBのデータ型とJavaのデータ型の対応付けはデータ型の対応付けを参照ください。

[メモ]

ひとつのコンテナに複数のロウを登録

複数のロウを一度に登録することもできます。以下のメソッドを使用します。

分類 メソッド
ロウ登録 Container.put(java.util.Collection rowCollection)

putを用いて複数のロウを登録するプログラムを示します。

//===============================================
// ロウを登録する
//===============================================
// (1)Containerオブジェクトの取得
Container<?, Row> container = store.getContainer(containerName);
if ( container == null ){
    throw new Exception("Container not found.");
}

// (2)複数のロウオブジェクトの作成
String[] nameList = {"notebook PC", "desktop PC", "keyboard", "mouse", "printer"};
int[] numberList = {108, 72, 25, 45, 62};

List<Row> rowList = new ArrayList<Row>();
for ( int i = 0; i < nameList.length; i++ ){
    Row row = container.createRow();
    row.setInteger(0, (i+1));
    row.setString(1, nameList[i]);
    row.setInteger(2, numberList[i]);
    rowList.add(row);
}

// (3)複数のロウの登録
container.put(rowList);

System.out.println("Put Rows num=" + nameList.length);

複数のロウオブジェクトを作成してリストにセットします。リストを引数としてputを実行します。

[メモ]

3.2.5 データを取得する

コンテナからロウを取得します。

ロウキーが設定されているコンテナの場合、ロウキーの値を指定してロウを取得できます。ロウキーが設定されていない場合は、後述のTQLを利用してロウを取得します。

分類 メソッド
ロウ取得 Container.get(K key)

ロウキーありのコレクションから、ロウキーの値が"0"のロウを取得するプログラムを以下に示します。

//===============================================
// ロウを取得する
//===============================================
// (1)Containerオブジェクトの取得
Container<Integer, Row> container = store.getContainer(containerName);
if ( container == null ){
    throw new Exception("Container not found.");
}

// (2)ロウキーを指定してロウを取得する
Row row = container.get(0);
if ( row == null ){
    throw new Exception("Row not found");
}

// (3)ロウからカラムの値を取り出す
int id = row.getInteger(0);
String name = row.getString(1);
int count = row.getInteger(2);

System.out.println("Get Row id="+ id + ", name=" + name + ", count=" + count);

ロウを取得する処理の部分を説明します。 (2)getにロウキーを指定して、コンテナからロウを取得します。 (3)取得したロウからカラム値を取り出すには、カラムのデータ型に合わせたgetメソッドを使用します。

3.2.6 TQLを実行する

TQLを実行します。

TQLの実行では、SELECTの選択式の種類によって、実行結果のクラスや処理方法が異なります。

SELECTの選択式の種類 内容 実行結果のクラス型
ロウ(*) コンテナに格納されているロウを取得します
例) SELECT * FROM container1
コンテナのロウオブジェクトの型
(Container<K,R>のRの型)
集計演算(MAX, MIN, COUNTなど) 集計演算の結果を取得します
例) SELECT COUNT(*) FROM container1
AggregationResult型

[メモ]

3.2.6.1 ロウを検索する

ロウの値を検索するTQLを実行する場合は、以下のメソッドを使用します。

分類 メソッド
クエリ生成 Query<R> Container<K,R>.query(java.lang.String tql)
クエリ実行 RowSet<R> Query<R>.fetch()

コレクションに対してカラムcountが50以上のロウを検索し、結果をidの昇順でソートして返すTQLのプログラムを示します。

//===============================================
// TQLで検索する
//===============================================
// (1)Containerオブジェクトの取得
Container<?, Row> container = store.getContainer(containerName);
if ( container == null ){
    throw new Exception("Container not found.");
}

// (2)TQLで検索実行
Query<Row> query = container.query("SELECT * WHERE count >= 50 ORDER BY id");
RowSet<Row> rs = query.fetch();

// (3)結果をロウで取得
while ( rs.hasNext() ) {
    Row row = rs.next();
    int id = row.getInteger(0);
    String name = row.getString(1);
    int count = row.getInteger(2);
    System.out.println("row id=" + id + ", name=" + name + ", count=" + count);
}

検索処理の部分を説明します。(2)実行するTQLでクエリオブジェクトを生成し、fetchで検索を実行します。 (3)検索結果を取得します。コンテナのカラムのデータ型に合わせて、getメソッドでロウの値を取得します。

3.2.6.2 集計演算を行う

集計演算のTQLを実行する場合は、以下のメソッドを使用します。

分類 メソッド
クエリ生成 Query<S> Container<K,R>.query(java.lang.String tql, java.lang.Class<S> rowType)
クエリ実行 RowSet<S> Query<S>.fetch()

コレクションに対して、カラムvalueの最大値を取得するプログラムを示します。

// (オブジェクトの取得は省略)

// (1)TQLで集計演算の実行
Query<AggregationResult> query = container.query("SELECT MAX(value)", AggregationResult.class);
RowSet<AggregationResult> rs = query.fetch();

// (2)結果を取得
if ( rs.hasNext() ){
    AggregationResult result = rs.next();
    long value = result.getLong();
    System.out.println("max = "+ value);
}

(1)クエリの生成時に、第2引数で集計演算結果の型であるAggregationResultを指定します。クエリを実行した結果はAggregationResultオブジェクトで返ります。 (2)実行した集計演算の種類によってAggregationResultオブジェクトの値のデータ型は異なります。データ型に合わせてgetLong、getDoubleまたはgetTimestampで値を取得します。

TQLの集計演算の一覧を以下に示します。

TQLの集計演算 内容 演算の引数 演算結果(AggregationResult)の値の型
MAX(column) 指定カラムの最大値 数値型またはTIMESTAMP型のカラム 指定カラムと同一の型
MIN(column) 指定カラムの最小値 数値型またはTIMESTAMP型のカラム 指定カラムと同一の型
COUNT(*) 集計対象のロウの個数 "*"のみ LONG型
SUM(column) 指定のカラムの合計値 数値型のカラム 指定カラムが整数型の場合LONG型
浮動小数点型の場合DOUBLE型
AVG(column) 指定のカラムの平均値 数値型のカラム DOUBLE型
VARIANCE(column) 指定のカラムの分散値 数値型のカラム DOUBLE型
STDDEV(column) 指定のカラムの標準偏差 数値型のカラム DOUBLE型

[メモ]

3.2.7 複数のコンテナに対して一括で操作を行う

データの登録や検索の処理では、複数のコンテナに対して一度に操作を行うことができます。複数コンテナ用のメソッドは以下の通りです。

分類 メソッド
複数コンテナのロウ登録 GridStore.multiPut(java.util.Map<java.lang.String,java.util.List> containerRowsMap)
複数コンテナのロウ取得 GridStore.multiGet(java.util.Map<java.lang.String,? extends RowKeyPredicate<?>> containerPredicateMap)
複数コンテナのTQL実行 GridStore.fetchAll(java.util.List> queryList)

ひとつのコンテナに対する操作と複数のコンテナに対する操作では、メソッドや取得条件などが異なりますので、用途に合わせて適切な方法をご利用ください。相違点を以下の表に示します。それぞれの方法の説明は、「本書での参照先」の部分をご参照ください。

分類 処理対象のコンテナ メソッド 取得条件の指定 本書での参照先
ロウ登録 ひとつ Container.put(R row)
Container.put(java.util.Collection rowCollection)
データを登録する
複数 GridStore.multiPut(java.util.Map<java.lang.String, java.util.List> containerRowsMap) 複数コンテナのロウ登録
ロウ取得
(ロウキー指定)
ひとつ Container.get(K key) ロウキー指定 データを取得する
複数 GridStore.multiGet(java.util.Map<java.lang.String, ? extends RowKeyPredicate<?>> containerPredicateMap) RowKeyPredicateクラスによるロウキー指定、または、ロウキー範囲指定 複数コンテナのロウ取得
ロウ取得
(TQL実行)
ひとつ GridStore.query(java.lang.String tql)
Query.fetch()
TQLのクエリ TQLを実行する
複数 GridStore.fetchAll(java.util.List> queryList) TQLのクエリ 複数コンテナのTQL実行

3.2.7.1 複数コンテナのロウ登録

複数のコンテナに対して、複数のロウを登録します。コンテナ名と登録するロウのリストの組合せを作り、multiPutでロウを登録できます。

分類 メソッド
複数コンテナのロウ登録 GridStore.multiPut(java.util.Map<java.lang.String,java.util.List> containerRowsMap)

コレクションと時系列コンテナに、それぞれロウを2個ずつ登録するプログラムを以下に示します。

//===============================================
// 複数のコンテナにロウを登録する
//===============================================
Map<String, List<Row>> paramMap = new HashMap<String, List<Row>>();

// (1)コレクション"SampleJava_MultiPut1"に対して登録するロウを生成する
{
    String containerName = "SampleJava_MultiPut1";
    Container<Integer, Row> container = store.getContainer(containerName);
    if ( container == null ){
        throw new Exception("Container not found.");
    }

    // 登録するデータ
    String[] nameList = {"notebook PC", "desktop PC", "keyboard", "mouse", "printer"};
    int[] numberList = {55, 81, 39, 72, 14};

    // ロウにデータをセットする
    List<Row> rowList = new ArrayList<Row>();
    for ( int i = 0; i < nameList.length; i++ ){
        Row row = container.createRow();
        row.setInteger(0, (i+1));
        row.setString(1, nameList[i]);
        row.setInteger(2, numberList[i]);
        rowList.add(row);
    }
    paramMap.put(containerName, rowList);
}

// (2)時系列コンテナ"SampleJava_MultiPut2"に対して登録するロウを生成する
{
    String containerName = "SampleJava_MultiPut2";
    Container<Integer, Row> container = store.getContainer(containerName);
    if ( container == null ){
        throw new Exception("Container not found.");
    }

    // 登録するデータ
    String[] dateList = {"2018/12/01 10:20:19.111+0900", "2018/12/02 03:25:45.023+0900",
                    "2018/12/03 08:29:21.932+0900", "2018/12/04 21:55:48.153+0900"};
    double[] valueList = { 129.9, 13.2, 832.7, 52.9 };

    // 日付の変換フォーマット
    SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSSZ");

    // ロウにデータをセットする
    List<Row> rowList = new ArrayList<Row>();
    for ( int i = 0; i < dateList.length; i++ ){
        Row row = container.createRow();
        row.setTimestamp(0, format.parse(dateList[i]));
        row.setDouble(1, valueList[i]);
        rowList.add(row);
    }
    paramMap.put(containerName, rowList);
}

// (3)複数のコンテナに対してロウを登録する
store.multiPut(paramMap);

System.out.println("MultiPut");

ひとつのコンテナにロウを登録する時と同様に、コンテナオブジェクトから空のロウを作成して登録するロウを作ります。コンテナとロウのリストの組合せをMapに格納し、まとめてmultiPutで登録を行います。

[メモ]

3.2.7.2 複数コンテナのロウ取得

複数のコンテナから、指定した条件に当てはまるロウを取得します。

分類 メソッド
複数コンテナのロウ取得 GridStore.multiGet(java.util.Map<java.lang.String,? extends RowKeyPredicate<?>> containerPredicateMap)

ロウキーの条件はコンテナごとに指定できます。条件には、特定の値を指定する個別条件と、値の範囲を指定する範囲条件の2種類があります。条件はRowKeyPredicateクラスのメソッドで指定します。

条件 メソッド
ロウキーの個別条件 RowKeyPredicate.add(K key)
ロウキーの範囲条件 RowKeyPredicate.setStart(K startKey)
RowKeyPredicate.setFinish(K finishKey)

[メモ]

個別条件指定で、コレクションからINTEGER型のロウキーの値が"0"に合致するロウ、別のコレクションからINTEGER型のロウキーの値が"2"または"4"に合致するロウをそれぞれ取得するプログラムを以下に示します。

//===============================================
// 複数のコンテナから一括でロウを取得する
//===============================================
// (1)取得条件を構築する
Map<String, RowKeyPredicate<Integer>> predMap = new HashMap<String, RowKeyPredicate<Integer>>();
{
  RowKeyPredicate<Integer> predicate = RowKeyPredicate.create(Integer.class);
  predicate.add(0);
  predMap.put("SampleJava_MultiGet1", predicate);
}
{
  RowKeyPredicate<Integer> predicate = RowKeyPredicate.create(Integer.class);
  predicate.add(2);
  predicate.add(4);
  predMap.put("SampleJava_MultiGet2", predicate);
}

// (2)複数コンテナからロウを取得する
Map<String, List<Row>> outMap = store.multiGet(predMap);

System.out.println("MultiGet");

// (3)ロウの値を取得する
for (Map.Entry<String, List<Row>> entry : outMap.entrySet()) {
  System.out.println("containerName="+entry.getKey());

  for (Row row : entry.getValue()) {
    int id = row.getInteger(0);
    String name = row.getString(1);
    int count = row.getInteger(2);

    System.out.println("    id=" + id + " name=" + name +" count=" + count);
  }
}

(1)RowKeyPredicateクラスを使って取得するロウの条件を生成し、コンテナ名とRowKeyPredicateの組合せをMAPに格納します。 (2)multiGetを用いて検索を実行します。 (3)コンテナ名とロウのリストの組合せで結果が返ります。

3.2.7.3 複数コンテナのTQL実行

複数のコンテナに対して、TQLを実行します。TQLはコンテナごとに指定できます。

分類 メソッド
複数コンテナのTQL実行 GridStore.fetchAll(java.util.List> queryList)

2つのコレクションに対応するそれぞれのTQLをまとめて実行し、ロウを取得するプログラムを以下に示します。

//===============================================
// 複数のコンテナにTQLを実行する
//===============================================
List<Query<Row>> queryList = new ArrayList<Query<Row>>();

// (1)コレクション"SampleJava_FetchAll1"に対するTQLのクエリを生成する
{
  Container<Integer, Row> container = store.getContainer("SampleJava_FetchAll1");
  if ( container == null ){
    throw new Exception("Container not found.");
  }
  queryList.add(container.query("select * where count > 60"));
}
// (2)コレクション"SampleJava_FetchAll2"に対するTQLのクエリを生成する
{
  Container<Integer, Row> container = store.getContainer("SampleJava_FetchAll2");
  if ( container == null ){
    throw new Exception("Container not found.");
  }
  queryList.add(container.query("select * where count > 100"));
}

// (3)複数コンテナを一括検索する
store.fetchAll(queryList);

// (4)結果を取得する
for (int i = 0; i < queryList.size(); i++) {
  System.out.println("SampleJava_FetchAll"+(i+1));
  Query<Row> query = queryList.get(i);
  RowSet<Row> rs = query.getRowSet();

  while (rs.hasNext()) {
    Row row = rs.next();
    int id = row.getInteger(0);
    String name = row.getString(1);
    int count = row.getInteger(2);
    System.out.println("    row id=" + id + ", name=" + name + ", count=" + count);
  }
}

(1)(2)コンテナオブジェクトからTQLのクエリを生成して、リストに格納します。 (3)クエリのリストを指定して、TQL一括実行fetchAllを実行します。 (4)検索結果は、(3)で指定したクエリのリストに格納されます。クエリから結果を取得する処理は、通常のTQL検索の場合と同様です。

3.2.8 バイナリデータを扱う

バイナリデータを登録、取得します。バイナリのデータ型はBlob型です。他のデータ型と同様に操作することができます。

バイナリデータの登録

バイナリデータをファイルから読み込み、ロウを登録するプログラムを以下に示します。

import java.sql.Blob;

// 省略

// (1)バイナリデータをファイルから読み込み、Blobを作成する
FileInputStream blobFile = new FileInputStream(new File("BlobData.java"));
Blob blob = container.createBlob();
OutputStream blobBuffer = blob.setBinaryStream(1);
int len = -1;
while ((len = blobFile.read()) > -1) {
  blobBuffer.write(len);
}
blobBuffer.flush();

// (2)ロウにバイナリをセットする
Row row = container.createRow();
row.setInteger(0, 0);
row.setBlob(1, blob);

// (3)ロウを登録する
container.put(row);

System.out.println("Put Row (Binary)");

blobFile.close();

(1)バイナリデータをファイルから読み込みます。バイナリデータを格納するBlobは、ContainerクラスのcreateBlobメソッドで作成できます。 SerialBlobなど、Blobを実装した他のクラスのインスタンスを使用することも可能です。 (2)ロウにsetBlobでバイナリデータをセットして、(3)ロウを登録します。

バイナリデータの取得

getBlobでバイナリデータを取得します。

// (1)ロウを取得
Row row = container.get(0);

// (2)ロウからバイナリを取得
Blob blob = row.getBlob(1);

 

3.2.9 データを更新する

ロウを更新します。ロウの更新には、ロウキーを指定して更新する方法と、TQLの実行結果から更新する方法の2種類があります。

分類 メソッド
ロウキーを指定してロウ更新 put(R row)
put(K key, R row)
put(java.util.Collection rowCollection)
TQLの実行結果からロウ更新 RowSet.update(R rowObj)

ロウキーを指定してロウ更新する方法では、putで指定したロウのロウキーと合致するデータが既に存在していたら、そのデータを更新します。ロウキーのデータが存在しなかった場合、または、ロウキーが設定されていないコレクションの場合は、putは常にロウの新規登録になります。

TQLの実行結果からロウを更新するプログラムを示します。

//===============================================
// TQLの検索結果からロウを更新する
//===============================================
// Containerオブジェクトの取得
Container<Integer, Row> container = store.getContainer(containerName);
if ( container == null ){
  throw new Exception("Container not found.");
}

// (1)手動コミットモードを指定する
container.setAutoCommit(false);

// (2)TQLで検索実行
Query<Row> query = container.query("SELECT * WHERE id = 3");
RowSet<Row> rs = query.fetch(true); // 削除するのでtrueを指定

// (3)検索でヒットしたロウを更新する
while( rs.hasNext() ){
  Row row = rs.next();

  // ロウの値をセットする
  row.setInteger(2, 77);

  // ロウを更新する
  rs.update(row);
}

// (4)コミットする
container.commit();

System.out.println("Update Row");

[メモ]

3.2.10 データを削除する

ロウを削除します。ロウの削除には、ロウキーを指定して削除する方法と、TQLの検索結果から削除する方法の2種類があります。

分類 メソッド
ロウキーを指定してロウ削除 Container.remove(K key)
TimeSeries.remove(java.util.Date key)
TQLの検索結果からロウ削除 RowSet.remove()

ロウキーを指定してロウ削除の方法を用いて、ロウキーの値"3"のロウを削除するプログラムを示します。

// (1) ロウキーを指定してロウを削除する
container.remove(3);

TQLの検索結果からロウ削除する方法を用いて、ロウを削除するプログラムを示します。

//===============================================
// TQLの検索結果からロウを削除する
//===============================================
// Containerオブジェクトの取得
Container<Integer, Row> container = store.getContainer(containerName);
if ( container == null ){
  throw new Exception("Container not found.");
}

// (1)手動コミットモードを指定する
container.setAutoCommit(false);

// (2)TQLで検索実行
Query<Row> query = container.query("SELECT * WHERE count < 50");
RowSet<Row> rs = query.fetch(true); // 削除するのでtrueを指定

// (3)検索でヒットしたロウを削除する
while( rs.hasNext() ){
  rs.next();
  rs.remove();
}

// (4)コミットする
container.commit();

System.out.println("Remove Row");

[メモ]

3.2.11 コンテナを削除する

コンテナ名を指定してコンテナを削除します。以下のメソッドで削除できます。

分類 メソッド
コレクション削除 GridStore.dropCollection(java.lang.String name)
時系列コンテナ削除 GridStore.dropTimeSeries(java.lang.String name)
コンテナ削除 GridStore.dropContainer(java.lang.String name)

[メモ]

コレクション"collection1"を削除するプログラムを以下に示します。

// コレクション"collection1"を削除する
store.dropCollection("collection1");

3.2.12 索引を作成する

コンテナのカラムに索引を作成します。

索引種別には次の3種類があります。コンテナ種別やカラムのデータ型によって、指定できる索引種別が異なります。

索引種別 内容
ハッシュ索引 - ハッシュ関数を用いた索引です。内部的なハッシュ関数でカラムの値を分散して索引を作成します。
- 等価条件(=)の検索に適しています。
- コレクションのカラムにのみ使用できます。ただし、カラムのデータ型が空間型、BLOB型、配列型の場合には使用できません。
ツリー索引 - Bツリーを用いた索引です。
- 等価条件(=)の検索や範囲検索(>や<=など)に適しています。
- カラムのデータ型が空間型、BLOB型、配列型の場合には使用できません。また、時系列コンテナのロウキーには使用できません。
- 複合索引を作成することができます。
空間索引 - 空間型用の索引です。
- 空間検索を高速に行う場合に適しています。
- コレクションでカラムのデータ型が空間型の場合のみ使用できます。

索引作成は、索引種別やカラムを指定する方法の違いで以下の3種類のメソッドがあります。

分類 メソッド
索引作成(カラム名、番号、索引種別、索引名を指定) Container.createIndex(IndexInfo info)
索引作成(カラム名を指定) Container.createIndex(java.lang.String columnName)
索引作成(カラム名と索引種別を指定) Container.createIndex(java.lang.String columnName, IndexType type)

[メモ]

索引作成createIndex(IndexInfo info)を使用して、コレクションのカラムcountにツリー索引を作成するプログラムを以下に示します。

// (コンテナオブジェクトの取得は省略)

// (1)索引情報を設定する
IndexInfo indexInfo = new IndexInfo();
indexInfo.setColumnName("count");
indexInfo.setType(IndexType.TREE);
indexInfo.setName("hash_index");

// (2)索引を作成する
container.createIndex(indexInfo);

// (3)複合索引の索引情報を設定する
IndexInfo compositeInfo = new IndexInfo();
compositeInfo.setColumnNameList(Arrays.asList("count","productName"));
compositeInfo.setType(IndexType.TREE);
compositeInfo.setName("composite_index");
            
// (4)複合索引を作成する
container.createIndex(compositeInfo);

(1)索引情報IndexInfoには、索引種別、作成対象のカラム(カラム番号またはカラム名)、索引名を指定します。
(2)IndexInfoを引数として、createIndexを実行します。
(3)複合索引の場合、索引情報IndexInfoに指定する作成対象のカラム(カラム番号またはカラム名)はList形式で指定します。
(4)IndexInfoを引数として、createIndexを実行します。

3.2.13 その他

3.2.13.1 データ型の対応付け

Java APIにおいて、GridDBのデータ型とJavaのデータ型の対応付けは以下の通りです。ロウからの値取得や設定の際には、以下のデータ型を指定してください。

GridDBのデータ型 Javaのデータ型
BOOL型 boolean
STRING型 java.lang.String
BYTE型 byte
SHORT型 short
INTEGER型 int
LONG型 long
FLOAT型 float
DOUBLE型 double
TIMESTAMP型 java.util.Date
GEOMETRY型 Geometry
BLOB型 java.sql.Blob

3.2.13.2 エラー処理

Java APIのメソッドでエラーが発生すると、GSExceptionがスローされます。

エラーコード取得getErrorCode()、スタックトレース表示printStackTrace()などを用いてエラー処理を行います。

3.2.13.3 TIMESTAMP型のユーティリティ機能

TIMESTAMP型のデータは、Java APIではjava.util.Date型として扱います。 TIMESTAMP型に対するユーティリティ機能として以下のメソッドがあります。

分類 メソッド
現在時刻の取得 TimestampUtils.current()
TimestampUtils.currentCalendar()
時刻の加算 TimestampUtils.add(java.util.Date timestamp, int amount, TimeUnit timeUnit)
TimestampUtils.add(java.util.Date timestamp, int amount, TimeUnit timeUnit, java.util.TimeZone zone)
GSTimestamp型を文字列表記に変換 TimestampUtils.format(java.util.Date timestamp)
TimestampUtils.format(java.util.Date timestamp, java.util.TimeZone zone)
文字列表記をGSTimestamp型に変換 TimestampUtils.parse(java.lang.String source)
TIMESTAMP値表記のフォーマットの取得 TimestampUtils.getFormat()
TimestampUtils.getFormat(java.util.TimeZone zone)

ロウから取得したTIMESTAMP型の値を文字列表記に変換する例を示します。

// ロウからTIMESTAMP型の値を取得する
Date date = row.getTimestamp(0);

// GSTimestampを文字列に変換する
String dateStr = TimestampUtils.format(date)

3.3 プログラミングの応用

3.3.1 時系列データを扱う

時系列コンテナに対して、時系列データ特有の演算を実行することができます。この節では、これらの時系列データ特有の演算について説明します。

演算は、TQLまたはメソッドで実行することができます。

種類 名称 TQL演算 メソッド
集計演算 重み付き平均値 TIME_AVG TimeSeries.aggregate
(Aggregation.WEIGHTED_AVERAGEを指定)
選択演算 直後の時刻 TIME_NEXT TimeSeries.get
(TimeOperator.NEXTを指定)
直後の時刻 TIME_NEXT_ONLY TimeSeries.get
(TimeOperator.NEXT_ONLYを指定)
直前の時刻 TIME_PREV TimeSeries.get
(TimeOperator.PREVIOUSを指定)
直前の時刻 TIME_PREV_ONLY TimeSeries.get
(TimeOperator.PREVIOUS_ONLYを指定)
補間演算 線形補間 TIME_INTERPOLATED TimeSeries.interpolate
サンプリング TIME_SAMPLING TimeSeries.query
(InterpolationModeを指定)

以下では、TQL演算を用いたプログラミングの例で説明します。

3.3.1.1 集計演算

3.3.1.1.1 TIME_AVG 時刻の重み付き平均値

ロウの時間間隔で重みをつけて平均を計算します。時間間隔が長いほど重みが大きくなります。つまり、値が登録されていない期間の値は、その期間の前後の値が続いていたとみなして計算します。

TQL演算 内容 演算の引数 演算結果の型
TIME_AVG(column) 指定カラムについての、ロウの時刻に基づく重み付き平均 時系列コンテナの数値型のカラム DOUBLE型

[メモ]

3.3.1.2 選択演算

指定された時刻と直前/直後の選択条件に基づいて、時系列コンテナのロウキーの時刻が合致するロウを返します。

TQL選択演算 内容
TIME_NEXT(*, timestamp) 指定の時刻timestampの直後の時刻を持つロウを返す。
同一時刻のロウが存在した場合は、そのロウを返す。
TIME_NEXT_ONLY(*, timestamp) 指定の時刻timestampの直後の時刻を持つロウを返す。
TIME_PREV(*, timestamp) 指定の時刻timestampの直前の時刻を持つロウを返す。
同一時刻のロウが存在した場合は、そのロウを返す。
TIME_PREV_ONLY(*, timestamp) 指定の時刻timestampの直前の時刻を持つロウを返す。

[メモ]

3.3.1.3 補間演算

時系列データを補間します。

TQL補間演算 内容 演算の引数
TIME_INTERPOLATED(column, timestamp) 指定の時刻timestampのロウが存在しない場合、補間した値を返す column : 数値型のカラム
timestamp : 時刻
TIME_SAMPLING(*|column, timestamp_start, timestamp_end, interval, time_unit) 指定の期間において、ロウをサンプリングした結果を返す timestamp_start : 開始時刻
timestamp_end : 終了時刻
interval : サンプリング間隔
time_unit : サンプリング間隔の単位(DAY|HOUR|MINUTE|SECOND|MILLISECOND)

TIME_INTERPOLATED(column, timestamp) :値の補間

TIME_SAMPLING(*|column, timestamp_start, timestamp_end, interval, time_unit) :値のサンプリング

[メモ]

3.3.2 期限解放を設定する

期限解放の設定は、コンテナを作成する時に行います。コンテナ作成後には設定することができません。

時系列コンテナの情報を表すTimeSeriesPropertiesを用いて、期限解放の設定を行います。コンテナ情報ContainerInfoにTimeSeriesPropertiesをセットして、コンテナを作成します。

分類 メソッド
コンテナ情報に時系列コンテナ特有の情報をセット ContainerInfo.setTimeSeriesProperties(TimeSeriesProperties props)
ロウ期限解放の期間の設定 TimeSeriesProperties.setRowExpiration(int elapsedTime, TimeUnit timeUnit)
ロウ期限解放の分割数の設定 TimeSeriesProperties.setExpirationDivisionCount(int count)

期限解放を設定して時系列コンテナを作成するプログラムを示します。

// (1)コンテナ情報オブジェクトを生成
ContainerInfo containerInfo = new ContainerInfo();

// (2)カラムの名前やデータ型をカラム情報オブジェクトにセット
List<ColumnInfo> columnList = new ArrayList<ColumnInfo>();
columnList.add(new ColumnInfo("date", GSType.TIMESTAMP));
columnList.add(new ColumnInfo("value", GSType.DOUBLE));
containerInfo.setColumnInfoList(columnList);

// (3)ロウキーを設定
containerInfo.setRowKeyAssigned(true);

// (4)時系列コンテナの情報を生成して、ロウ期限解放を設定する
TimeSeriesProperties tsProp = new TimeSeriesProperties();
tsProp.setRowExpiration(100, TimeUnit.DAY);
tsProp.setExpirationDivisionCount(5);
containerInfo.setTimeSeriesProperties(tsProp);

// (5)時系列コンテナ作成
String containerName = "SampleJava_RowExpiration";
TimeSeries<Row> timeseries = store.putTimeSeries(containerName, containerInfo, false);

System.out.println("Create TimeSeries name="+containerName);

3.3.3 データを圧縮する

時系列コンテナでは、次の2種類の方式によってデータを圧縮できます。

圧縮方式の設定は、コンテナを作成する時に行います。コンテナ作成後には設定することができません。

圧縮の方式や誤差の範囲の設定は、以下のメソッドで行います。

分類 メソッド
圧縮方式の指定 TimeSeriesProperties.setCompressionMethod(CompressionMethod compressionMethod)
絶対誤差あり間引き圧縮のパラメータの設定
(圧縮方式がHIの場合)
TimeSeriesProperties.setAbsoluteHiCompression(java.lang.String column, double width)
相対誤差あり間引き圧縮のパラメータの設定
(圧縮方式がHIの場合)
TimeSeriesProperties.setRelativeHiCompression(java.lang.String column, double rate, double span)
連続して間引きされるロウの最大期間の設定 TimeSeriesProperties.setCompressionWindowSize(int compressionWindowSize, TimeUnit compressionWindowSizeUnit)

誤差あり間引き圧縮方式(HI)の時系列コンテナを作成するプログラムを以下に示します。

// (1)コンテナ情報オブジェクトを生成
ContainerInfo containerInfo = new ContainerInfo();

// (2)カラムの名前やデータ型をカラム情報オブジェクトにセット
List<ColumnInfo> columnList = new ArrayList<ColumnInfo>();
columnList.add(new ColumnInfo("date", GSType.TIMESTAMP));
columnList.add(new ColumnInfo("value", GSType.DOUBLE));
containerInfo.setColumnInfoList(columnList);

// (3)ロウキーを設定
containerInfo.setRowKeyAssigned(true);

// (4)時系列コンテナの情報を生成して、圧縮を設定する
TimeSeriesProperties tsProp = new TimeSeriesProperties();
tsProp.setCompressionMethod(CompressionMethod.HI);
tsProp.setAbsoluteHiCompression("value", 0.7);

containerInfo.setTimeSeriesProperties(tsProp);

// (5)時系列コンテナ作成
String containerName = "SampleJava_Compression";
TimeSeries<Row> timeseries = store.putTimeSeries(containerName, containerInfo, false);

System.out.println("Create TimeSeries name="+containerName);

3.3.4 配列型のデータを扱う

配列型のデータはJavaの配列にマッピングします。 Rowクラスには、配列型のデータのセットや取得を行うための配列型用のsetter/getterがあります。配列型のデータ型に合わせたsetter/getterを使用してロウを操作し、データの登録や取得を行います。

分類 メソッド
ブール型の配列 void Row.setBoolArray(int column, boolean[] fieldValue)
boolean[] Row.getBoolArray(int column)
STRING型の配列 void Row.setStringArray(int column, java.lang.String[] fieldValue)
java.lang.String[] Row.getStringArray(int column)
BYTE型の配列 void Row.setByteArray(int column, byte[] fieldValue)
byte[] Row.getByteArray(int column)
SHORT型の配列 void Row.setShortArray(int column, short[] fieldValue)
short[] Row.getShortArray(int column)
INTEGER型の配列 void Row.setIntegerArray(int column, int[] fieldValue)
int[] Row.getIntegerArray(int column)
LONG型の配列 void Row.setLongArray(int column, long[] fieldValue)
long[] Row.getLongArray(int column)
FLOAT型の配列 void Row.setFloatArray(int column, float[] fieldValue)
float[] Row.getFloatArray(int column)
DOUBLE型の配列 void Row.setDoubleArray(int column, double[] fieldValue)
double[] Row.getDoubleArray(int column)
TIMESTAMP型の配列 void Row.setTimestampArray(int column, java.util.Date[] fieldValue)
java.util.Date[] Row.getTimestampArray(int column)

配列型データを登録するプログラムを示します。

// (1)配列型のデータ
String[] stringArray = {"Sales", "Development", "Marketing", "Research"};
int[] integerArray = {39, 92, 18, 51 };

// (2)ロウに配列型のデータをセットする
Row row = container.createRow();
row.setInteger(0, 0);
row.setStringArray(1, stringArray);
row.setIntegerArray(2, integerArray);

// (3)ロウを登録する
container.put(row);

配列型データを取得するプログラムを示します。

// (1)ロウを取得
Row row = container.get(0);

// (2)ロウから配列型データを取得
String[] stringArray = row.getStringArray(1);
int[] integerArray = row.getIntegerArray(2);

[メモ]

3.3.5 空間型のデータを扱う

空間型のデータを登録、取得します。

空間型のデータを表すWKT(Well-Known Text)形式の値から、Geometryオブジェクトを生成して操作します。 WKT形式は、ISOで定められている標準的な書式で、空間型のデータをテキスト形式で表現できます。

Rowクラスには、空間型のデータのセットや取得を行うための空間型用のsetter/getterがあります。これらを用いて、空間型データの登録や取得を行います。

分類 メソッド
空間型データのセット void Row.setGeometry(int column, Geometry fieldValue)
空間型データの取り出し Geometry getGeometry(int column)

空間型データを登録するプログラムを示します。

import com.toshiba.mwcloud.gs.Geometry;
// (省略)

// (1)空間型のデータ
Geometry geometry = Geometry.valueOf("POINT(2 3)");

// (2)ロウに空間型のデータをセットする
Row row = container.createRow();
row.setInteger(0, 0);
row.setGeometry(1, geometry);

// (3)ロウを登録する
container.put(row);

空間型データを取得するプログラムを示します。

import com.toshiba.mwcloud.gs.Geometry;
// (省略)

// (1)ロウを取得
Row row = container.get(0);

// (2)ロウから配列型データを取得
Geometry geometry = row.getGeometry(1);

[メモ]

3.3.6 コンテナ情報を取得する

コンテナの情報を取得する操作を説明します。

3.3.6.1 コンテナ名の一覧を取得する

作成されているコンテナの名前の一覧を取得します。

コンテナ名の一覧取得は、パーティションの情報を取得するためのコントローラPartitionControllerインスタンスを用いて行います。

分類 メソッド
パーティションコントローラの取得 GridStore.getPartitionController()
パーティション数の取得 PartitionController.getPartitionCount()
コンテナ名の一覧取得 PartitionController.getContainerNames(int partitionIndex, long start, java.lang.Long limit)

パーティションコントローラを介して、パーティションごとにコンテナ名の一覧を取得します。コンテナ名一覧のプログラムを示します。

// (1)パーティションコントローラと、パーティション数を取得する
PartitionController partitionController = store.getPartitionController();
int partitionCount = partitionController.getPartitionCount();

// (2)パーティション数でループして、コンテナ名一覧を取得する
for (int i = 0; i < partitionCount; i++) {
    List<String> containerNames = partitionController.getContainerNames(i, 0, null);
    if ( containerNames.size() > 0 ){
        System.out.println(containerNames);
    }
}

(2)getContainerNamesメソッドで第2引数0, 第3引数NULLを指定すると、指定したパーティション上の全コンテナ名を取得します。取得するコンテナ名の数を制限する場合は、第3引数に制限する数を指定してください。

[メモ]

3.3.6.2 コンテナのスキーマ情報を取得する

コンテナに関する情報は、コンテナ情報ContainerInfoから取得します。

分類 メソッド
コンテナ情報の取得 GridStore.getContainerInfo(java.lang.String name)

ContainerInfoには、様々な情報を取得するsetterメソッドがあります。必要な情報を取得するメソッドを使用してください。メソッドの詳細は、『GridDB Java APIリファレンス』(GridDB_Java_API_Reference.html)をご参照ください。

コンテナのカラムや索引情報などを取得するプログラムを示します。

// (1)コンテナ情報の取得
ContainerInfo containerInfo = store.getContainerInfo(containerName);

// (2)名前とタイプの取得
String name = containerInfo.getName();
ContainerType type = containerInfo.getType();
System.out.println("name=" + name +", type="+type);

// (3)カラム情報の取得
for (int i = 0; i < containerInfo.getColumnCount(); i++){
  ColumnInfo info = containerInfo.getColumnInfo(i);
  // カラム名
  String columnName = info.getName();

  // カラムのデータ型
  GSType columnType = info.getType();

  // NotNull制約 (true=Not Null制約なし, false=Not Null制約あり)
  boolean columnNullable = info.getNullable();

  // 索引情報
  Set<IndexType> indexTypes = info.getIndexTypes();

  System.out.println("column name="+columnName+", type="+columnType+", nullable="+columnNullable);
  if ( indexTypes.size() > 0 ) System.out.println("       indexTypes="+indexTypes);
}

// (4)時系列コンテナ特有の情報の取得
TimeSeriesProperties tmProperties = containerInfo.getTimeSeriesProperties();
if ( tmProperties != null ){
  // 圧縮方式
  CompressionMethod method = tmProperties.getCompressionMethod();
  // ・・・TimeSeriesPropertiesから必要な情報を取得する
}

3.3.7 複合ロウキーを扱う

データの登録や検索の処理では、複合ロウキーを指定して操作を行うことができます。

複合ロウキーを設定したデータを登録するプログラムを示します。複合ロウキーとして1つ目のINTEGER型と2つ目のSTRING型を指定します。

// (1)コンテナ情報の作成
ContainerInfo containerInfo = new ContainerInfo();
containerInfo.setType(ContainerType.COLLECTION);
List<ColumnInfo> columnList = new ArrayList<ColumnInfo>();
columnList.add(new ColumnInfo("id", GSType.INTEGER));
columnList.add(new ColumnInfo("productName", GSType.STRING));
columnList.add(new ColumnInfo("count", GSType.INTEGER));
containerInfo.setColumnInfoList(columnList);

// (2)複合ロウキーを指定
containerInfo.setRowKeyColumnList(Arrays.asList(0, 1));

// (3)コンテナを作成
Container<?, Row> container = store.putContainer("SampleJava_CompositeKeyMultiGet1", containerInfo, false);

// (4)ロウを登録する
String[] nameList = {"notebook PC", "desktop PC", "keyboard", "mouse", "printer"};
int[] numberList = {108, 72, 25, 45, 62};
List<Row> rowList = new ArrayList<Row>();
for ( int i = 0; i < nameList.length; i++ ){
    Row row = container.createRow();
    row.setInteger(0, i);
    row.setString(1, nameList[i]);
    row.setInteger(2, numberList[i]);
    rowList.add(row);
}
container.put(rowList);

複数のコンテナから、複合ロウキーで指定した条件に当てはまるデータを取得するプログラムを示します。指定する条件は、個別条件指定を用い、1つ目のコンテナからはINTEGER型のロウキーの値が"0"、STRING型のロウキー値が"notebook PC"に合致するロウを、2つ目のコンテナからはINTEGER型のロウキーの値が"2"、STRING型のロウキー値が"keyboard"に合致するロウと、INTEGER型のロウキーの値が"4"、STRING型のロウキー値が"printer"に合致するロウを取得します。

// (1)取得条件を構築する
Map<String, RowKeyPredicate<Key>> predMap = new HashMap<String, RowKeyPredicate<Key>>();
{
    RowKeyPredicate<Key> predicate = RowKeyPredicate.create(containerInfo);
    Key rowKey = store.createRowKey(containerInfo);
    rowKey.setInteger(0,  0);
    rowKey.setString(1,  "notebook PC");
    predicate.add(rowKey);
    predMap.put("SampleJava_CompositeKeyMultiGet1", predicate);
}
{
    RowKeyPredicate<Key> predicate = RowKeyPredicate.create(containerInfo);

    Key rowKey = store.createRowKey(containerInfo);
    rowKey.setInteger(0,  2);
    rowKey.setString(1,  "keyboard");
    predicate.add(rowKey);
    rowKey.setInteger(0,  4);
    rowKey.setString(1,  "printer");
    predicate.add(rowKey);

    predMap.put("SampleJava_CompositeKeyMultiGet2", predicate);
}

// (2)複数コンテナからロウを取得する
Map<String, List<Row>> outMap = store.multiGet(predMap);
System.out.println("CompositeKeyMultiGet");

// (3)ロウの値を取得する
for (Map.Entry<String, List<Row>> entry : outMap.entrySet()) {
    System.out.println("containerName="+entry.getKey());

    for (Row row : entry.getValue()) {
        int id = row.getInteger(0);
        String name = row.getString(1);
        int count = row.getInteger(2);

        System.out.println("    id=" + id + " name=" + name +" count=" + count);
    }
}

[メモ]

4 C API (NoSQLインタフェース)

4.1 C APIを利用したアプリケーションの開発(Linux)

4.1.1 開発実行環境の構築

C APIのアプリケーションを開発するには、以下のパッケージをインストールする必要があります。

パッケージ名 ファイル名 内容
griddb-ee-c_lib griddb-ee-c_lib-X.X.X-linux.x86_64.rpm Cのヘッダファイルとライブラリが含まれます
(/usr/include/gridstore.h と /usr/lib64/libgridstore.so, libgridstore_advanced.so)

※: X.X.XはGridDBのバージョン

アプリケーションの開発や実行を行う際には、パス/usr/lib64をLD_LIBRARY_PATHに指定してください。

例)

$ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/lib64

4.1.2 プログラムのビルド方法

サンプルプログラムのコンパイルと実行方法を説明します。

コンパイル時にはライブラリ"gridstore"を-lオプションに指定してください。生成された実行ファイルを実行してください。

4.2 C APIを利用したアプリケーションの開発(Windows)

4.2.1 開発実行環境の構築

C APIのWindows用ライブラリは、インストールメディアの 「\Windows\C-API」ディレクトリに含まれています。(gridstore_c.lib、gridstore.h、gridstore_c.dll、msvcp140.dll、vcruntime140.dll、gridstore_advanced.dll、libssl-1_1-x64.dll、libcrypto-1_1-x64.dll)

ライブラリは64ビット用dllです。専用のインストーラはありませんので、WindowsクライアントPCにコピーが必要です。環境変数PATHに指定されているディレクトリにgridstore_c.dll、gridstore_advanced.dll、libssl-1_1-x64.dll、libcrypto-1_1-x64.dllをコピーしてください。gridstore_c.dll、gridstore_advanced.dllはVisual Studio 2019で作成しています。 Visual Studio 2019のランタイムライブラリがインストール済みでない場合は、msvcp140.dllとvcruntime140.dllをコピーしてください。 (Visual Studio 2019のランタイムライブラリ「Visual Studio 2019 の Microsoft Visual C++ 再頒布可能パッケージ」は、マイクロソフトの公式ページからもダウンロード可能です)

4.2.2 プログラムのビルド方法

プログラムのコンパイル方法を説明します。

<VisualStudioプロジェクトファイルの作成方法>以下は、VisualStudio2010の場合の手順です。

  1. x64のプロジェクトを作成
  1. Includeディレクトリの設定
  1. インポートライブラリ(gridstore_c.lib)の設定

 

サンプルプログラム一覧

分類 プログラム名 内容 作成するコンテナ名
クラスタに接続する Connect.c マルチキャスト方式でクラスタに接続して切断します。 -
コレクションを作成する(メソッド) CreateCollectionByMethod.c メソッドでスキーマを指定する方法を用いて、コレクションを作成します。 SampleC_collection1
コレクションを作成する(クラス定義) CreateCollectionByClass.c クラス定義でスキーマを指定する方法を用いて、コレクションを作成します。 SampleC_collection2
時系列コンテナを作成する(メソッド) CreateTimeSeriesByMethod.c メソッドでスキーマを指定する方法を用いて、時系列コンテナを作成します。 SampleC_timeseries1
ロウを登録する PutRow.c ひとつのコンテナにひとつのロウを登録します。 SampleC_PutRow
複数のロウを登録する PutRows.c ひとつのコンテナに複数のロウを登録します。 SampleC_PutRows
ロウを取得する GetRow.c ロウキーを指定してコンテナからロウを取得します。 SampleC_GetRow
TQLでロウを検索する TQLSelect.c TQLのSELECT文でロウを取得します。 SampleC_TQLSelect
TQLの集計関数を実行する TQLAggregation.c TQLのSELECT文で集計演算を実行します。 SampleC_TQLAggregation
複数コンテナにロウを登録する MultiPut.c 複数のコンテナにロウを一括で登録します。 SampleC_MultiPut1, SampleC_MultiPut2
複数コンテナからロウを取得する MultiGet.c 複数のコンテナからロウを一括で取得します。 SampleC_MultiGet1, SampleC_MultiGet2
複数コンテナにTQLを実行する FetchAll.c 複数のコンテナにTQLを一括で実行します。 SampleC_FetchAll1, SampleC_FetchAll2
バイナリデータを登録・検索する BlobData.c バイナリデータをコンテナに登録して、コンテナから取得します。 SampleC_BlobData
ロウを更新する UpdateRowByTQL.c TQLで取得したRowSetを用いて、ロウを更新します。 SampleC_UpdateRowByTQL
ロウを削除する(ロウキー) RemoveRowByRowkey.c ロウキーを指定してロウを削除します。 SampleC_RemoveRowByRowkey
ロウを削除する(TQL) RemoveRowByTQL.c TQLで検索したロウを削除します。 SampleC_RemoveRowByTQL
索引を作成する CreateIndex.c 索引を作成します。 SampleC_Index
時系列の演算を行う TQLTimeseries.c 時系列データに対して様々な演算を行います。 SampleC_TQLTimeseries
期限解放を設定する TimeSeriesRowExpiration.c 期限解放を設定します。 SampleC_RowExpiration
ロウの圧縮を設定する TimeSeriesCompression.c ロウの圧縮を設定します。 SampleC_Compression
配列型のデータを扱う ArrayData.c 配列型のデータの登録と検索を行います。 SampleC_ArrayData
空間型のデータを扱う GeometryData.c 空間型のデータの登録と検索を行います。 SampleC_GeometryData
コンテナ名一覧を取得する ContainerNames.c コンテナ名の一覧を取得します。
コンテナのスキーマ情報を取得する ContainerInformation.c コンテナのスキーマ情報を取得します。 SampleC_Info
複合ロウキーを使って複数コンテナからロウを取得する CompositeKeyMultiGet.c 複合ロウキーを使って複数のコンテナからロウを一括で取得します。 SampleC_CompositeKeyMultiGet1, SampleC_CompositeKeyMultiGet2

4.3 プログラミングの基礎

C APIを用いた基礎的なプログラミングを説明します。

4.3.1 クラスタに接続する

データの登録や検索などの操作を行うためには、クラスタに接続する必要があります。接続処理では以下のメソッドを用います。

分類 メソッド
GridStoreFactoryインスタンス取得 gsGetDefaultFactory()
GridStoreインスタンス取得 gsGetGridStore(GSGridStoreFactory *factory, const GSPropertyEntry *properties, size_t propertyCount, GSGridStore **store)
リソース解放 gsCloseGridStore(GSGridStore **store, GSBool allRelated)

クラスタへの接続を行うプログラムの例を以下に示します。

#include "gridstore.h"
#include <stdlib.h>
#include <stdio.h>

void main(int argc, char *argv[]){

    GSGridStore *store;
    GSContainer *container;
    GSResult ret;
    size_t stackSize;
    GSResult errorCode;
    GSChar errMsgBuf1[1024], errMsgBuf2[1024];  // エラーメッセージを格納するバッファ
    int i;

    //===============================================
    // クラスタに接続する
    //===============================================
    // (1)接続情報を指定する (マルチキャスト方式)
    const GSPropertyEntry props[] = {
        { "notificationAddress", "239.0.0.1" },
        { "notificationPort", "31999" },
        { "clusterName", "myCluster" },
        { "database", "public" },
        { "user", "admin" },
        { "password", "admin" },
        { "applicationName", "SampleC" }
    };

    const size_t propCount = sizeof(props) / sizeof(*props);


    // (2)GridStoreインスタンスを取得する
    ret = gsGetGridStore(gsGetDefaultFactory(), props, propCount, &store);
    if ( !GS_SUCCEEDED(ret) ){
        fprintf(stderr, "gsGetGridStore error\n");
        goto LABEL_ERROR;
    }

    // (3)コンテナ作成や取得などの操作を行うと、クラスタに接続される
    ret = gsGetContainerGeneral(store, "containerName", &container);
    if ( !GS_SUCCEEDED(ret) ){
        fprintf(stderr, "gsGetContainerGeneral error\n");
        goto LABEL_ERROR;
    }
    gsCloseContainer(&container, GS_TRUE);
    printf("Connect to Cluster\n");


    //===============================================
    // 終了処理
    //===============================================
    // (4)リソースを解放する
    gsCloseGridStore(&store, GS_TRUE);

    printf("success!\n");

    return;


LABEL_ERROR:
    //===============================================
    // エラー処理
    //===============================================
    // エラーコードとエラーメッセージを出力する
    stackSize = gsGetErrorStackSize(store);
    for ( i = 0; i < stackSize; i++ ){
        errorCode = gsGetErrorCode(store, i);
        gsFormatErrorMessage(store, i, errMsgBuf1, sizeof(errMsgBuf1));
        gsFormatErrorLocation(store, i, errMsgBuf2, sizeof(errMsgBuf2));
        fprintf(stderr, "[%d] %s (%s)\n", errorCode, errMsgBuf1, errMsgBuf2);
    }

    // リソースを解放する
    gsCloseGridStore(&store, GS_TRUE);
    return;
}

接続処理の部分を説明します。

(1)クラスタのアドレスやユーザ、パスワードなどの接続情報をGSPropertyEntryに指定します。 GSPropertyEntryは、プロパティのキーと値の組合せの配列です。指定したプロパティの数は、次のインスタンス取得処理で必要になるのでsizeofを用いて計算しておきます。

(2)接続情報のプロパティを基に、GridStoreインスタンスを取得します。

(3)GridStoreオブジェクトを用いてコンテナ作成や取得などの操作を行うと、GridDBクラスタへの接続処理が行われます。

(4)切断しリソースを解放します。第二引数は、GSGridStoreインスタンスで取得したすべてのリソースを解放するかどうかを指定します。GS_TRUEを指定するとすべてのリソースが解放されます。GS_FALSEを指定した場合は、別途個別にリソースを解放する必要があります。

エラー処理については、エラー処理を参照ください。

4.3.1.1 接続方式

クラスタには、マルチキャスト方式、固定リスト方式、プロバイダ方式の3種類の接続方式があります。

接続方式 内容
マルチキャスト方式 マルチキャスト通信を用いた方式
固定リスト方式 クラスタを構成する全ノードのアドレスを直接指定する方式
プロバイダ方式 クラスタを構成する全ノードのアドレスをプロバイダを用いて提供する方式

アプリケーションからクラスタに接続する際には、クラスタ定義ファイルgs_cluster.jsonで定義されている接続方式に合わせて、アプリケーション側の設定を行う必要があります。

まずはクラスタ定義ファイルgs_cluster.jsonを参照し、使用されている接続方式を確認してください。次に接続方式に基づいて、対応する値をPropertiesオブジェクトに設定してください。

接続方式 アプリケーションで指定するプロパティのキー 内容 指定する値
マルチキャスト方式 notificationAddress

notificationPort
マルチキャストのアドレス

マルチキャストのポート番号
/transaction/notificationAddressの値

/transaction/notificationPortの値
固定リスト方式 notificationMember クラスタを構成するノードのアドレスとポート番号のリスト /cluster/notificationMemberの/transaction/addressと/transaction/portをリスト形式にした値
プロバイダ方式 notificationProvider プロバイダのURL /cluster/notificationProvider/urlの値

3つの接続方式について、クラスタ定義ファイルgs_cluster.jsonの記述内容と対応する接続プログラムの例を示します。

マルチキャスト方式の例

固定リスト方式の例

プロバイダ方式の例

4.3.1.2 プロパティ

接続方式以外の主なプロパティは以下です。その他のプロパティの詳細は、『GridDB C APIリファレンス』(GridDB_C_API_Reference.html)の「gsGetGridStore」をご参照ください。

項目 プロパティのキー 必須 指定する値
クラスタ名 clusterName 必須 gs_cluster.jsonの/cluster/clusterNameに記載している値
データベース名 database publicデータベースに接続する場合は省略可
それ以外は必須
接続するデータベース名
ユーザ名 user 必須 接続するユーザ名(管理ユーザ・一般ユーザどちらも可)
パスワード password 必須 接続するユーザのパスワード
アプリケーション名 applicationName 省略可 アプリケーションを識別するための名前
(運用ツールgs_shでコネクション情報や実行中イベントを確認する時に表示されます)
タイムゾーン timeZone 省略可 時分で指定:±hh:mm または ±hhmm
タイムゾーンID:「Z」のみサポート
上位(JavaVM)の環境引継ぎ:auto
※省略時は「Z」相当
認証方式 authentication 省略可 認証方式として、INTERNAL(内部認証) / LDAP(LDAP認証)のいずれかを指定
SSL通信 sslMode 省略可 SSL通信として、PREFERRED(クラスタ設定に従う) / DISABLED(無効)のいずれかを指定
マルチキャストパケットを送出するインターフェースアドレス notificationInterfaceAddress 省略可 複数のネットワークインターフェースがあるときにクラスタのネットワーク構成をマルチキャスト方式にする場合は、マルチキャストパケットを送信するインターフェースのアドレスを指定

[メモ]

4.3.2 コンテナを作成する

コンテナを作成します。コンテナには、コレクションと時系列コンテナの2つの種類があります。コンテナ作成では、カラム名やデータ型などのスキーマを指定する必要があります。スキーマを指定する方法として、次の2つの方法があります。

それぞれの方法について説明します。

4.3.2.1 メソッドでスキーマを指定する方法

コンテナのスキーマはメソッドを使用して動的に指定します。スキーマを表すコンテナ情報クラスGSContainerInfoやカラム情報クラスGSColumnInfoを用います。これらを用いてコンテナを作成するメソッドは以下の通りです。

分類 メソッド
コレクション作成 gsPutCollectionGeneral(GSGridStore *store, const GSChar *name, const GSContainerInfo *info, GSBool modifiable, GSCollection **collection)
時系列コンテナ作成 gsPutTimeSeriesGeneral (GSGridStore *store, const GSChar *name, const GSContainerInfo *info, GSBool modifiable, GSTimeSeries **timeSeries)
コンテナ(コレクション、または時系列コンテナ)作成 gsPutContainerGeneral(GSGridStore *store, const GSChar *name, const GSContainerInfo *info, GSBool modifiable, GSContainer **container)

コンテナ作成のメソッドgsPutContainerGeneralは、コレクションと時系列コンテナのどちらの種類も作成できます。

4.3.2.1.1 コレクションの作成 gsPutCollectionGeneral

コレクション作成gsPutCollectionGeneralを用いて、コレクションを作成するプログラムの全体を以下に示します。

#include "gridstore.h"
#include <stdlib.h>
#include <stdio.h>

void main(int argc, char *argv[]){

    GSGridStore *store;
    GSContainer *container;
    GSCollection *collection;
    GSContainerInfo info = GS_CONTAINER_INFO_INITIALIZER;
    GSColumnInfo columnInfo = GS_COLUMN_INFO_INITIALIZER;
    GSColumnInfo columnInfoList[3];
    GSResult ret;
    size_t stackSize;
    GSResult errorCode;
    GSChar errMsgBuf1[1024], errMsgBuf2[1024];  // エラーメッセージを格納するバッファ
    int i;

    //===============================================
    // クラスタに接続する
    //===============================================
    // 接続情報を指定する (マルチキャスト方式)
    const GSPropertyEntry props[] = {
        { "notificationAddress", "239.0.0.1" },
        { "notificationPort", "31999" },
        { "clusterName", "myCluster" },
        { "database", "public" },
        { "user", "admin" },
        { "password", "admin" },
        { "applicationName", "SampleC" }
    };

    const size_t propCount = sizeof(props) / sizeof(*props);


    // GridStoreインスタンスを取得する
    ret = gsGetGridStore(gsGetDefaultFactory(), props, propCount, &store);
    if ( !GS_SUCCEEDED(ret) ){
        fprintf(stderr, "ERROR gsGetGridStore\n");
        goto LABEL_ERROR;
    }
    // コンテナ作成や取得などの操作を行うと、クラスタに接続される
    ret = gsGetContainerGeneral(store, "containerName", &container);
    if ( !GS_SUCCEEDED(ret) ){
        fprintf(stderr, "ERROR gsGetContainerGeneral\n");
        goto LABEL_ERROR;
    }
    gsCloseContainer(&container, GS_TRUE);
    printf("Connect to Cluster\n");


    //===============================================
    // コレクションを作成する
    //===============================================
    // (1)コンテナ種別を設定する
    info.type = GS_CONTAINER_COLLECTION;

    // (2)ロウキーありの場合は設定する
    info.rowKeyAssigned = GS_TRUE;

    // (3)カラム情報を定義する
    columnInfo.name = "id";
    columnInfo.type = GS_TYPE_INTEGER;
    columnInfoList[0] = columnInfo;

    columnInfo.name = "productName";
    columnInfo.type = GS_TYPE_STRING;
    columnInfoList[1] = columnInfo;

    columnInfo.name = "count";
    columnInfo.type = GS_TYPE_INTEGER;
    columnInfoList[2] = columnInfo;

    // (4)カラム情報をコンテナ情報オブジェクトに設定する
    info.columnCount = sizeof(columnInfoList) / sizeof(*columnInfoList);
    info.columnInfoList = columnInfoList;

    // (5)コレクションを作成する
    ret = gsPutCollectionGeneral(store, "SampleC_collection1", &info, GS_FALSE, &collection);
    if ( !GS_SUCCEEDED(ret) ){
        fprintf(stderr, "ERROR gsPutCollectionGeneral\n");
        goto LABEL_ERROR;
    }

    printf("Create Collection name=SampleC_collection1\n");

    //===============================================
    // 終了処理
    //===============================================
    // リソースを解放する
    gsCloseGridStore(&store, GS_TRUE);

    printf("success!\n");

    return;


LABEL_ERROR:
    //===============================================
    // エラー処理
    //===============================================
    // エラーコードとエラーメッセージを出力する
    stackSize = gsGetErrorStackSize(store);
    for ( i = 0; i < stackSize; i++ ){
        errorCode = gsGetErrorCode(store, i);
        gsFormatErrorMessage(store, i, errMsgBuf1, sizeof(errMsgBuf1));
        gsFormatErrorLocation(store, i, errMsgBuf2, sizeof(errMsgBuf2));
        fprintf(stderr, "[%d] %s (%s)\n", errorCode, errMsgBuf1, errMsgBuf2);
    }

    // リソースを解放する
    gsCloseGridStore(&store, GS_TRUE);
    return;

}

コレクションを作成する箇所を説明します。 (3)カラム名やデータ型は、カラム情報GSColumnInfoに指定します。複数のカラムがある場合は、GSColumnInfoを複数生成します。 (4)GSColumnInfoはコンテナ情報GSContainerInfoにセットします。 (5)この情報を用いて、putCollectionでコレクションを作成します。

[メモ]

4.3.2.1.2 時系列コンテナを作成する gsPutTimeSeriesGeneral

時系列コンテナ作成gsPutTimeSeriesGeneralを用いて、時系列コンテナを作成します。プログラム全体の流れはコレクションの作成と同様ですので、異なる部分のプログラムのみを示します。

//===============================================
// 時系列コンテナを作成する
//===============================================
// (1)コンテナ種別を設定する
info.type = GS_CONTAINER_TIME_SERIES;

// (2)ロウキーを設定する (時系列コンテナはロウキーの設定が必須)
info.rowKeyAssigned = GS_TRUE;

// (3)カラム情報を定義する
columnInfo.name = "date";
columnInfo.type = GS_TYPE_TIMESTAMP;
columnInfoList[0] = columnInfo;

columnInfo.name = "value";
columnInfo.type = GS_TYPE_DOUBLE;
columnInfoList[1] = columnInfo;

// (4)カラム情報をコンテナ情報オブジェクトに設定する
info.columnCount = sizeof(columnInfoList) / sizeof(*columnInfoList);
info.columnInfoList = columnInfoList;

// (5)時系列コンテナを作成する
ret = gsPutTimeSeriesGeneral(store, "SampleC_timeseries1", &info, GS_FALSE, &timeseries);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsPutTimeSeriesGeneral\n");
  goto LABEL_ERROR;
}

printf("Create TimeSeries name=SampleC_timeseries1\n");

[メモ]

4.3.2.1.3 コンテナを作成する gsPutContainerGeneral

コンテナ作成gsPutContainerGeneralメソッドは、コレクションと時系列コンテナのどちらでも作成することができます。コレクションと時系列コンテナの種別は、GSContainerInfo.typeで指定します。

4.3.2.2 構造体でスキーマを指定する方法

Cの構造体を用いて、コンテナのスキーマを定義します。メンバ変数が、GridDBのコンテナのカラムに対応付けされます。構造体を用いた方法では以下のメソッドを使用します。

分類 メソッド
コレクション作成 gsPutCollection(GSGridStore *store, const GSChar *name, const GSBinding *binding, const GSCollectionProperties *properties, GSBool modifiable, GSCollection **collection)
時系列コンテナ作成 gsPutTimeSeries(GSGridStore *store, const GSChar *name, const GSBinding *binding, const GSTimeSeriesProperties *properties, GSBool modifiable, GSTimeSeries **timeSeries)
コンテナ(コレクション、または時系列コンテナ)作成 gsPutContainer(GSGridStore *store, const GSChar *name, const GSBinding *binding, const GSContainerInfo *info, GSBool modifiable, GSContainer **container)

コンテナ作成のメソッドgsPutContainerは、コレクションと時系列コンテナのどちらの種類も作成できます。

コレクション作成gsPutCollectionを用いて、ロウキーありのコレクションを作成するプログラムを以下に示します。

時系列コンテナの作成gsPutTimeseriesとコンテナ作成gsPutContainerの場合も、プログラムの流れは同様です。

// (1)コレクションの構造体を定義する
typedef struct {
    int id;
    const GSChar *productName;
    uint64_t count;
} Product;

// (2)構造体とスキーマの対応関係を定義する
GS_STRUCT_BINDING(Product,
    GS_STRUCT_BINDING_KEY(id, GS_TYPE_INTEGER)
    GS_STRUCT_BINDING_ELEMENT(productName, GS_TYPE_STRING)
    GS_STRUCT_BINDING_ELEMENT(count, GS_TYPE_INTEGER)
);

void main(int argc, char *argv[]){
    // 省略

    //===============================================
    // コレクションを作成する
    //===============================================
  ret = gsPutCollection(store, "SampleC_collection2", GS_GET_STRUCT_BINDING(Product), NULL, GS_FALSE, &collection);
    if ( !GS_SUCCEEDED(ret) ){
        fprintf(stderr, "ERROR gsPutCollection\n");
        goto LABEL_ERROR;
    }

    fprintf(stdout, "Create Collection name=SampleC_collection2\n");

(1)コレクションをCの構造体で定義します。

(2)GS_STRUCT_BINDINGを用いて、構造体とコレクションのスキーマの対応関係を定義します。

分類 マクロ
構造体とスキーマの対応を取得 GS_GET_STRUCT_BINDING(type)
構造体とスキーマの対応を定義 GS_STRUCT_BINDING(type, entries)
構造体メンバとロウキーの対応を定義 GS_STRUCT_BINDING_KEY(member, memberType)
構造体メンバとカラム(基本型)の対応を定義 GS_STRUCT_BINDING_ELEMENT(member, memberType)
構造体メンバとカラム(配列型)の対応を定義 GS_STRUCT_BINDING_ARRAY(member, sizeMember, elementType)
構造体メンバとロウキーの対応を定義 (カラム名指定) GS_STRUCT_BINDING_NAMED_KEY(name, member, memberType)
構造体メンバとカラム(基本型)の対応を定義 (カラム名指定) GS_STRUCT_BINDING_NAMED_ELEMENT(name, member, memberType)
構造体メンバとカラム(配列型)の対応を定義 (カラム名指定) GS_STRUCT_BINDING_NAMED_ARRAY(name, member, sizeMember, elementType)

例)

// 構造体を定義する
typedef struct {
    int id;
    const int8_t *lob;
    size_t lobSize; // lobのサイズ
} Product;

// 構造体とコンテナスキーマの対応関係を定義する
GS_STRUCT_BINDING(Product,
    GS_STRUCT_BINDING_KEY(id, GS_TYPE_INTEGER)
        GS_STRUCT_BINDING_ARRAY(lob, lobSize, GS_TYPE_BYTE)
);

[メモ]

4.3.3 コンテナを取得する

コンテナの名前を指定して、コンテナを取得します。データの登録やTQLなどのロウ操作を行うためには、まずコンテナを取得する必要があります。

コンテナ取得には以下のメソッドがあります。ロウ操作する際のロウのタイプの違い(GSRowとユーザ定義の構造体)によって2種類に分けられます。

GSRow

ユーザ定義の構造体

例) コンテナ取得(GSRowでロウ操作を行う)

Row * row;

// (1)コレクション取得
gsGetCollectionGeneral(store, "collection1", &collection);

// (2)空のロウオブジェクトの作成
gsCreateRowByContainer(collection, &row);

// (3)ロウキーを指定してロウ(GSRow)取得
gsGetRowByInteger(container, 0, row, GS_FALSE, NULL);

// (4)ロウから値を取得
gsGetRowFieldAsInteger(row, 0, &id);
gsGetRowFieldAsString(row, 1, &productName);

例) コンテナ取得(ユーザ定義のクラスでロウ操作を行う)

typedef struct {
    int id;
    const GSChar *productName;
    uint64_t count;
} Product;
GS_STRUCT_BINDING(Product,
    GS_STRUCT_BINDING_KEY(id, GS_TYPE_INTEGER)
    GS_STRUCT_BINDING_ELEMENT(productName, GS_TYPE_STRING)
    GS_STRUCT_BINDING_ELEMENT(count, GS_TYPE_INTEGER)
);

void main(int argc, char *argv[]){
    Product product;
    // 省略

    // (1)コレクション取得
    gsGetCollection(store, "collection1", GS_GET_STRUCT_BINDING(Product), &collection);

    // (2)ロウキーを指定してロウ(Product)取得
    gsGetRowByInteger(collection, 0, &product, GS_FALSE, NULL);

    // (3)ロウから値を取得
    int id = product.id;

    // 省略

4.3.4 データを登録する

コンテナにロウを登録する場合は、以下のメソッドを使用します。

分類 メソッド
ロウオブジェクトの作成(コンテナ指定) gsCreateRowByContainer(GSContainer *container, GSRow **row)
ロウオブジェクトの作成(コンテナ情報指定) gsCreateRowByStore(GSGridStore *store, const GSContainerInfo *info, GSRow **row)
ロウオブジェクトに値を格納 gsSetRowFieldByXXXXX (※XXXXXはデータ型)
ロウ登録 gsPutRow(GSContainer *container, const void *key, const void *rowObj, GSBool *exists)

コンテナに対してロウをひとつ登録するプログラムを以下に示します。

//===============================================
// ロウを登録する
//===============================================
// (1)コンテナを取得する
ret = gsGetContainerGeneral(store, "SampleC_PutRow", &container);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetContainerGeneral\n");
  goto LABEL_ERROR;
}
if ( container == NULL ){
  fprintf(stderr, "ERROR Container not found. name=SampleC_PutRow\n");
  goto LABEL_ERROR;
}

// (2)空のロウオブジェクトの作成
ret = gsCreateRowByContainer(container, &row);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsCreateRowByContainer\n");
  goto LABEL_ERROR;
}

// (3)カラム値をセット
gsSetRowFieldByInteger(row, 0, 0);
gsSetRowFieldByString(row, 1, "display");
gsSetRowFieldByInteger(row, 2, 150);

// (4)ロウを登録する
ret = gsPutRow(container, NULL, row, NULL);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsPutRow\n");
  goto LABEL_ERROR;
}

ロウを登録する部分を説明します。 (1)ロウを登録するコンテナを取得します。 (2)コンテナオブジェクトから、空のロウオブジェクトを生成します。 (3)空のロウオブジェクトに、登録するデータをセットします。 (4)コンテナにロウを登録します。

GridDBのデータ型とCのデータ型の対応付けはデータ型の対応付けを参照ください。

[メモ]

ひとつのコンテナに複数のロウを登録

複数のロウを一度に登録することもできます。以下のメソッドを使用します。

分類 メソッド
ロウ登録 gsPutMultipleRows(GSContainer *container, const void *const *rowObjs, size_t rowCount, GSBool *exists)

gsPutMultipleRowsを用いて、ひとつのコンテナに複数のロウを登録するプログラムを示します。

GSRow *row;
const void * const * rowObj;
GSRow * rowList[5];
// 省略

//===============================================
// ロウを登録する
//===============================================
// (1)コンテナを取得する
ret = gsGetContainerGeneral(store, "SampleC_PutRows", &container);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetContainerGeneral\n");
  goto LABEL_ERROR;
}
if ( container == NULL ){
  fprintf(stderr, "ERROR Container not found. name=SampleC_PutRows\n");
  goto LABEL_ERROR;
}

// (2)複数のロウオブジェクトを作成
for ( i = 0; i < 5; i++ ){
  // 空のロウオブジェクトを生成
  gsCreateRowByContainer(container, &row);

  // ロウオブジェクトに値をセット
  gsSetRowFieldByInteger(row, 0, i);
  gsSetRowFieldByString(row, 1, "dvd");
  gsSetRowFieldByInteger(row, 2, 10*i);

  rowList[i] = row;
}
  rowObj = (void *)rowList;

// (3)複数のロウを登録する
ret = gsPutMultipleRows(container, rowObj, 5, NULL);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsPutMultipleRows\n");
  goto LABEL_ERROR;
}

複数のロウオブジェクトを作成してgsPutMultipleRowsを実行します。

[メモ]

4.3.5 データを取得する

コンテナからロウを取得します。

ロウキーが設定されているコンテナの場合、ロウキーの値を指定してロウを取得できます。ロウキーが設定されていない場合は、後述のTQLを利用してロウを取得します。

分類 メソッド
ロウ取得 gsGetRow(GSContainer *container, const void *key, void *rowObj, GSBool *exists)
ロウ取得 gsGetRowByXXXXX (※XXXXXはロウキーのデータ型)
ロウオブジェクトからカラム値の取得 gsGetRowFieldByXXXXX (※XXXXXはカラムのデータ型)

ロウキーありのコレクションから、ロウキーの値が"0"のロウを取得するプログラムを以下に示します。

//===============================================
// ロウを取得する
//===============================================
// (1)コンテナを取得する
ret = gsGetContainerGeneral(store, containerName, &container);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetContainerGeneral\n");
  goto LABEL_ERROR;
}
if ( container == NULL ){
  fprintf(stderr, "ERROR Container not found. name=%s\n", containerName);
  goto LABEL_ERROR;
}

// (2)空のロウオブジェクトの作成
gsCreateRowByContainer(container, &row);

// (3)ロウキーを指定してロウ取得
ret = gsGetRowByInteger(container, 0, row, GS_FALSE, NULL);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetRowByInteger\n");
  goto LABEL_ERROR;
}

// (4)ロウから値を取得
gsGetRowFieldAsInteger(row, 0, &id);
gsGetRowFieldAsString(row, 1, &productName);
gsGetRowFieldAsInteger(row, 2, &count);

printf("Get Row (id=%d, productName=%s, count=%d)\n", id, productName, count);

ロウを取得する処理の部分を説明します。 (2)空のロウオブジェクトを作成します。 (3)コンテナに対してロウキーを指定して、ロウを取得します。 (4)取得したロウは、カラムのデータ型に合わせてgetメソッドで値を取り出します。

4.3.6 TQLを実行する

TQLを実行します。

TQLの実行では、SELECTの選択式の種類によって、実行結果のクラスや処理方法が異なります。

SELECTの選択式の種類 内容 実行結果のクラス型
ロウ(*) コンテナに格納されているロウを取得します
例) SELECT * FROM container1
コンテナのロウオブジェクトの型
(Container<K,R>のRの型)
集計演算(MAX, MIN, COUNTなど) 集計演算の結果を取得します
例) SELECT COUNT(*) FROM container1
AggregationResult型

[メモ]

4.3.6.1 ロウを検索する

ロウの値を検索するTQLを実行する場合は、以下のメソッドを使用します。

分類 メソッド
クエリ生成 gsQuery(GSContainer *container, const GSChar *queryString, GSQuery **query)
クエリ実行 gsFetch(GSQuery *query, GSBool forUpdate, GSRowSet **rowSet)
結果セットにロウが存在するか gsHasNextRow (GSRowSet *rowSet)
結果セットからロウオブジェクト取得 gsGetNextRow(GSRowSet *rowSet, void *rowObj)

コレクションに対してカラムcountが50以上のロウを検索し、結果をidの昇順でソートして返すTQLのプログラムを示します。

//===============================================
// TQLで検索する
//===============================================
// (1)コンテナを取得する
ret = gsGetContainerGeneral(store, containerName, &container);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetContainerGeneral\n");
  goto LABEL_ERROR;
}
if ( container == NULL ){
  fprintf(stderr, "ERROR Container not found. name=%s\n", containerName);
  goto LABEL_ERROR;
}

// (2)TQLで検索実行
const GSChar * queryStr = "SELECT * WHERE count >= 50 ORDER BY id";
printf("TQL query : %s\n", queryStr);
ret = gsQuery(container, queryStr, &query);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsQuery\n");
  goto LABEL_ERROR;
}
ret = gsFetch(query, GS_FALSE, &rs);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsFetch\n");
  goto LABEL_ERROR;
}

// (3)空のロウを作成
gsCreateRowByContainer(container, &row);

// (4)結果を取得する
while (gsHasNextRow(rs)) {
  int id;
  const GSChar *productName;
  int count;


  // (5)ロウを取得する
  ret = gsGetNextRow(rs, row);
  if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsGetNextRow\n");
    goto LABEL_ERROR;
  }

  gsGetRowFieldAsInteger(row, 0, &id);
  gsGetRowFieldAsString(row, 1, &productName);
  gsGetRowFieldAsInteger(row, 2, &count);

  printf("TQL result: id=%d, productName=%s, count=%d\n", id, productName, count);
}

検索処理の部分を説明します。(2)実行するTQLでクエリオブジェクトを生成し、gsFetchで検索を実行します。 (3)結果を取得するための空のロウオブジェクトを作成します。 (4)検索結果を取得します。コンテナのカラムのデータ型に合わせて、getメソッドでロウの値を取得します。

4.3.6.2 集計演算を行う

集計演算のTQLを実行する場合は、以下のメソッドを使用します。

分類 メソッド
クエリ生成 gsQuery(GSContainer *container, const GSChar *queryString, GSQuery **query)
クエリ実行 gsFetch(GSQuery *query, GSBool forUpdate, GSRowSet **rowSet)
結果セットにロウが存在するか gsHasNextRow (GSRowSet *rowSet)
結果セットからGSAggregationResultを取得 gsGetNextAggregation (GSRowSet *rowSet, GSAggregationResult **aggregationResult)
GSAggregationResultから値を取得 gsGetAggregationValueAsXXXXX (※XXXXXはデータ型)

コレクションに対して、カラムcountの最大値を取得するプログラムを示します。

// (1)TQLで集計演算の実行
ret = gsQuery(container, "SELECT MAX(count)", &query);
if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsQuery\n");
    goto LABEL_ERROR;
}
ret = gsFetch(query, GS_FALSE, &rs);
if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsFetch\n");
    goto LABEL_ERROR;
}

// (2)結果を取得する
while (gsHasNextRow(rs)) {
    int64_t max;

    // (3)集計演算の結果を取得する
  ret = gsGetNextAggregation(rs, &aggregationResult);
    if ( !GS_SUCCEEDED(ret) ){
        fprintf(stderr, "ERROR gsGetNextRow\n");
        goto LABEL_ERROR;
    }

    // (4)値を取得する
  gsGetAggregationValueAsLong(aggregationResult, &max, NULL);

  printf("TQL result: max=%d\n", max);
}

(3)GSRowSetから値を取り出す時に、集計演算用のgsGetNextAggregationを使用します。 (4)実行した集計演算の種類によってGSAggregationResultオブジェクトの値のデータ型は異なります。データ型に合わせて値を取得します。

TQLの集計演算の一覧は、集計演算を行うを参照ください。

[メモ]

4.3.7 複数のコンテナに対して一括で操作を行う

データの登録や検索の処理では、複数のコンテナに対して一度に操作を行うことができます。複数コンテナ用のメソッドは以下の通りです。

分類 メソッド
複数コンテナのロウ登録 gsPutMultipleContainerRows(GSGridStore *store, const GSContainerRowEntry *entryList, size_t entryCount)
複数コンテナのロウ取得 gsGetMultipleContainerRows(GSGridStore *store, const GSRowKeyPredicateEntry *const *predicateList, size_t predicateCount, const GSContainerRowEntry **entryList, size_t *entryCount)
複数コンテナのTQL実行 gsFetchAll(GSGridStore *store, GSQuery *const *queryList, size_t queryCount)

ひとつのコンテナに対する操作と複数のコンテナに対する操作では、メソッドや取得条件などが異なりますので、用途に合わせて適切な方法をご利用ください。相違点を以下の表に示します。

それぞれの方法の説明は、「本書での参照先」の部分をご参照ください。

分類 処理対象のコンテナ メソッド 取得条件の指定 本書での参照先
ロウ登録 ひとつ gsPutRow
gsPutMultipleRows
データを登録する
複数 gsPutMultipleContainerRows 複数コンテナのロウ登録
ロウ取得
(ロウキー指定)
ひとつ gsGetRow ロウキー指定 データを取得する
複数 gsGetMultipleContainerRows GSRowKeyPredicateEntryクラスによるロウキー指定、または、ロウキー範囲指定 複数コンテナのロウ取得
ロウ取得
(TQL実行)
ひとつ gsQuery
gsFetch
TQLのクエリ TQLを実行する
複数 gsFetchAll TQLのクエリ 複数コンテナのTQL実行

4.3.7.1 複数コンテナのロウ登録

複数のコンテナに対して、複数のロウを登録します。コンテナ名と登録するロウのリストの組合せを作り、multiPutでロウを登録できます。

分類 メソッド
複数コンテナのロウ登録 gsPutMultipleContainerRows(GSGridStore *store, const GSContainerRowEntry *entryList, size_t entryCount)

2つのコレクションにそれぞれロウを2個ずつ登録するプログラムを以下に示します。

// コンテナ名
const GSChar *const containerNameList[2] = { "SampleC_MultiPut1", "SampleC_MultiPut2" };
const size_t containerCount = 2;

// 登録するロウデータ(各コンテナに5つのロウ)
const size_t rowCount = 5;
const GSChar * nameList[5] = { "notebook PC", "desktop PC", "keyboard", "mouse", "printer" };
const int numberList[2][5] = { { 108, 72, 25, 45, 62 }, { 50, 11, 208, 23, 153 } };

// 省略

//===============================================
// 複数コンテナにロウを一括登録する
//===============================================
for ( i = 0; i < containerCount; i++ ){
  // (1)コンテナ取得
  ret = gsGetContainerGeneral(store, containerNameList[i], &container);
  if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsGetContainerGeneral\n");
    return;
  }
  if ( container == NULL ){
    fprintf(stderr, "ERROR Container not found. name=%s\n", containerNameList[i]);
    goto LABEL_ERROR;
  }

  // (2)複数のロウを生成
  for ( j = 0; j < rowCount; j++ ){
    // 空のロウオブジェクト生成
    gsCreateRowByContainer(container, &row);

    // ロウオブジェクトに値をセット
    gsSetRowFieldByInteger(row, 0, j);
    gsSetRowFieldByString(row, 1, nameList[j]);
    gsSetRowFieldByInteger(row, 2, numberList[i][j]);
    allRowList[i][j] = row;
  }

  // (3)GSContainerRowEntryにコンテナ情報とロウをセット
  inEntry.containerName = containerNameList[i];
  inEntry.rowList = allRowList[i];
  inEntry.rowCount = rowCount;
  inEntryList[i] = inEntry;
}

// (4)複数コンテナにロウを一括登録
ret = gsPutMultipleContainerRows(store, inEntryList, containerCount);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsPutMultipleContainerRows\n");
  return;
}

ひとつのコンテナにロウを登録する時と同様に、コンテナオブジェクトから空のロウを作成して登録するロウを作ります。 GSContainerRowEntryにコンテナ情報とロウをセットし、まとめてgsPutMultipleContainerRowsで登録を行います。

[メモ]

4.3.7.2 複数コンテナのロウ取得

複数のコンテナから、指定した条件に当てはまるロウを取得します。

分類 メソッド
複数コンテナのロウ取得 gsGetMultipleContainerRows(GSGridStore *store, const GSRowKeyPredicateEntry *const *predicateList, size_t predicateCount, const GSContainerRowEntry **entryList, size_t *entryCount)

ロウキーの条件はコンテナごとに指定できます。条件には、特定の値を指定する個別条件と、値の範囲を指定する範囲条件の2種類があります。条件はGSRowKeyPredicateで指定します。

分類 メソッド
条件の生成 gsCreateRowKeyPredicate(GSGridStore *store, GSType keyType, GSRowKeyPredicate **predicate)
ロウキーの個別条件を設定 gsAddPredicateKeyXXXXX (※ XXXXXはデータ型)
ロウキーの範囲条件を設定 gsSetPredicateStartKeyXXXXX
gsSetPredicateFinishKeyXXXXX
(※ XXXXXはデータ型)

[メモ]

個別条件指定で、コレクションからロウを一括で取得するプログラムを以下に示します。

// コンテナ名
const GSChar *const containerNameList[2] = { "SampleC_MultiGet1", "SampleC_MultiGet2" };
const size_t containerCount = 2;

// 入力用の変数
GSRowKeyPredicate *predicate;
GSRowKeyPredicateEntry predEntryValueList[2];
const GSRowKeyPredicateEntry *predEntryList[2];

// 出力用の変数
const GSContainerRowEntry *outEntryList;
size_t outEntryCount;
GSContainerRowEntry outEntry = GS_CONTAINER_ROW_ENTRY_INITIALIZER;
int id;
GSChar const *productName;
int count;

// 省略

//===============================================
// 複数のコンテナから一括でロウを取得する
//===============================================
// (1)ロウ取得条件を構築する
for (i = 0; i < containerCount; i++) {

  // GSRowKeyPredicateを生成
  gsCreateRowKeyPredicate(store, GS_TYPE_INTEGER, &predicate);

  // 個別条件を設定 (ロウキーの値が0または2)
  gsAddPredicateKeyByInteger(predicate, 0);
  gsAddPredicateKeyByInteger(predicate, 2);

  // GSRowKeyPredicateEntryに条件を格納する
  predEntryValueList[i].containerName = containerNameList[i];
  predEntryValueList[i].predicate = predicate;

  predEntryList[i] = &predEntryValueList[i];
}

// (2)複数コンテナからロウを一括取得する
ret = gsGetMultipleContainerRows(store, predEntryList, containerCount, &outEntryList, &outEntryCount);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetMultipleContainerRows\n");
  goto LABEL_ERROR;
}

// (3)取得結果を出力する
for (i = 0; i < outEntryCount; i++) {
  outEntry = outEntryList[i];

  for (j = 0; j < outEntry.rowCount; j++) {
    row = (GSRow *)outEntry.rowList[j];

    gsGetRowFieldAsInteger(row, 0, &id);
    gsGetRowFieldAsString(row, 1, &productName);
    gsGetRowFieldAsInteger(row, 2, &count);

    printf("MultiGet: container=%s, id=%d, productName=%s, count=%d\n", outEntry.containerName, id, productName, count);
  }
}

(1)GSRowKeyPredicateを使って取得するロウの条件を生成し、コンテナ名とGSRowKeyPredicateの組合せをGSRowKeyPredicateEntryに格納します。 (2)gsGetMultipleContainerRowsを用いて検索を実行します。 (3)コンテナ名とロウのリストの組合せで結果が返ります。

4.3.7.3 複数コンテナのTQL実行

複数のコンテナに対して、TQLを実行します。TQLはコンテナごとに指定できます。

分類 メソッド
複数コンテナのTQL実行 gsFetchAll(GSGridStore *store, GSQuery *const *queryList, size_t queryCount)

2つのコレクションに対応するそれぞれのTQLをまとめて実行し、ロウを取得するプログラムを以下に示します。

// コンテナ名
const GSChar *const containerNameList[2] = { "SampleC_FetchAll1", "SampleC_FetchAll2" };
const size_t containerCount = 2;

// 各コンテナに対するTQL
const GSChar *const tqlList[2] = { "select * where count > 60",
                  "select * where count > 100" };

GSContainer * containerList[2];
GSQuery *queryList[2];
GSRowSet *rs;
int id;
GSChar const *productName;
int count;

// 省略

//===============================================
// 複数のコンテナにTQLを実行する
//===============================================
// (1)各コンテナのTQLクエリを生成する
for ( i = 0; i < containerCount; i++ ){
  ret = gsGetContainerGeneral(store, containerNameList[i], &containerList[i]);
  if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsGetContainerGeneral\n");
    goto LABEL_ERROR;
  }
  if ( containerList[i] == NULL ){
    fprintf(stderr, "ERROR Container not found. name=%s\n", containerNameList[i]);
    goto LABEL_ERROR;
  }

  printf("FetchAll query : container=%s, tql=%s\n", containerNameList[i], tqlList[i]);
  ret = gsQuery(containerList[i], tqlList[i], &queryList[i]);
  if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsQuery\n");
    goto LABEL_ERROR;
  }
}


// (2)複数コンテナにTQLを一括実行する
ret = gsFetchAll(store, queryList, containerCount);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsFetchAll\n");
  goto LABEL_ERROR;
}

// (3)結果を取得する
for (i = 0; i < containerCount; i++) {

  // 空のロウオブジェクトを生成
  gsCreateRowByContainer(containerList[i], &row);

  // RowSetを取得
  ret = gsGetRowSet(queryList[i], &rs);
  if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsGetRowSet\n");
    goto LABEL_ERROR;
  }

  // ロウを取得
  while (gsHasNextRow(rs)) {
    ret = gsGetNextRow(rs, row);
    if ( !GS_SUCCEEDED(ret) ){
      fprintf(stderr, "ERROR gsGetNextRow\n");
      goto LABEL_ERROR;
    }

    // 値を取得
    gsGetRowFieldAsInteger(row, 0, &id);
    gsGetRowFieldAsString(row, 1, &productName);
    gsGetRowFieldAsInteger(row, 2, &count);

    printf("FetchAll result: container=%s, row=(%d, \"%s\", %d)\n", containerNameList[i], id, productName, count);
  }

  gsCloseRow(&row);
  gsCloseRowSet(&rs);
  gsCloseQuery(&queryList[i]);
}

(1)コンテナオブジェクトからTQLのクエリを生成して、リストに格納します。 (2)TQL一括実行gsFetchAllを実行します。 (3)検索結果は、(2)で指定したクエリのリストに格納されます。

4.3.8 バイナリデータを扱う

バイナリデータを登録、取得します。バイナリのデータ型はBlob型です。他のデータ型と同様に操作することができます。

バイナリデータの登録

バイナリデータをファイルから読み込み、ロウを登録するプログラムを以下に示します。

// (1)バイナリファイルを読み込む
file = fopen("BlobData.c", "rb");
// (省略)

// (2)空のロウオブジェクトの作成
ret = gsCreateRowByContainer(collection, &row);
if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsCreateRowByContainer\n");
    goto LABEL_ERROR;
}

// (3)カラム値をセット
gsSetRowFieldByInteger(row, 0, 0);

blob.size = size;   // バイナリサイズ
blob.data = data;   // バイナリデータ
ret = gsSetRowFieldByBlob(row, 1, &blob);
if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsSetRowFieldByBlob\n");
    goto LABEL_ERROR;
}

// (4)ロウを登録する
ret = gsPutRow(collection, NULL, row, NULL);
if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsPutRow\n");
    goto LABEL_ERROR;
}

(1)バイナリデータをファイルから読み込みます。(2)(3)ロウオブジェクトにバイナリデータをセットして、(4)ロウを登録します。

バイナリデータの取得

getBlobでバイナリデータを取得します。

// (1)空のロウオブジェクトの作成
gsCreateRowByContainer(collection, &row);

// (2)ロウキーを指定してロウ取得
ret = gsGetRowByInteger(collection, 0, row, GS_FALSE, NULL);
if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsGetRowByInteger\n");
    goto LABEL_ERROR;
}

// (3)ロウからバイナリ型データを取得
GSBlob blob;
gsGetRowFieldAsBlob(row, 1, &blob);

4.3.9 データを更新する

ロウを更新します。ロウの更新には、ロウキーを指定して更新する方法と、TQLの実行結果から更新する方法の2種類があります。

分類 メソッド
ロウキーを指定してロウ更新 gsPutRow(GSContainer *container, const void *key, const void *rowObj, GSBool *exists)
gsPutMultipleRows(GSContainer *container, const void *const *rowObjs, size_t rowCount, GSBool *exists)
TQLの実行結果からロウ更新 gsUpdateCurrentRow (GSRowSet *rowSet, const void *rowObj)

ロウキーを指定してロウ更新する方法では、putで指定したロウのロウキーと合致するデータが既に存在していたら、そのデータを更新します。ロウキーのデータが存在しなかった場合、または、ロウキーが設定されていないコレクションの場合は、putは常にロウの新規登録になります。

TQLの実行結果からロウを更新するプログラムを示します。

//===============================================
// ロウを更新する
//===============================================
// (1)コンテナを取得する
ret = gsGetContainerGeneral(store, containerName, &container);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetContainerGeneral\n");
  goto LABEL_ERROR;
}
if ( container == NULL ){
  fprintf(stderr, "ERROR Container not found. name=%s\n", containerName);
  goto LABEL_ERROR;
}

// (2)手動コミットモードに設定する
gsSetAutoCommit(container, GS_FALSE);

// (3)TQLで検索実行
ret = gsQuery(container, "SELECT * WHERE id = 4", &query);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsQuery\n");
  goto LABEL_ERROR;
}
ret = gsFetch(query, GS_TRUE, &rs); // 更新するのでforUpdateにはtrueを指定する
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsFetch\n");
  goto LABEL_ERROR;
}

// (4)結果を取得する
while (gsHasNextRow(rs)) {
  int id;
  const GSChar *productName;
  int count;

  // 空のロウオブジェクトを生成
  gsCreateRowByContainer(container, &row);

  // ロウを取得する
  ret = gsGetNextRow(rs, row);
  if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsGetNextRow\n");
    goto LABEL_ERROR;
  }

  // 値を変更する
  gsSetRowFieldByInteger(row, 2, 325);

  // ロウを更新する
  ret = gsUpdateCurrentRow(rs, row);
  if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsUpdateCurrentRow\n");
    goto LABEL_ERROR;
  }
}

// (5)コミットする
ret = gsCommit(container);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsCommit\n");
  goto LABEL_ERROR;
}

printf("Update row id=4\n");

[メモ]

4.3.10 データを削除する

ロウを削除します。ロウの削除には、ロウキーを指定して削除する方法と、TQLの検索結果から削除する方法の2種類があります。

分類 メソッド
ロウキーを指定してロウ削除 gsDeleteRow(GSContainer *container, const void *key, GSBool *exists)
gsDeleteRowByXXXXX (※XXXXXはロウキーのデータ型)
TQLの検索結果からロウ削除 gsDeleteCurrentRow(GSRowSet *rowSet)

ロウキーを指定してロウを削除する方法を用いて、ロウキーの値"3"のロウを削除するプログラムを示します。

// (1) ロウキーを指定してロウを削除する
gsDeleteRowByInteger(container, 3, NULL);

TQLの検索結果からロウを削除する方法を用いて、カラムcountの値が50未満のロウを削除するプログラムを示します。

// コンテナを取得する
ret = gsGetContainerGeneral(store, containerName, &container);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetContainerGeneral\n");
  goto LABEL_ERROR;
}
if ( container == NULL ){
  fprintf(stderr, "ERROR Container not found. name=%s\n", containerName);
  goto LABEL_ERROR;
}

// (1)手動コミットモードに設定する
gsSetAutoCommit(container, GS_FALSE);

// (2)TQLで検索実行
printf("Delete query : %s\n", "SELECT * WHERE count < 50");
ret = gsQuery(container, "SELECT * WHERE count < 50", &query);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsQuery\n");
  goto LABEL_ERROR;
}
ret = gsFetch(query, GS_TRUE, &rs); // 更新するのでforUpdateにはtrueを指定する
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsFetch\n");
  goto LABEL_ERROR;
}

// (3)検索でヒットしたロウを削除する
while (gsHasNextRow(rs)) {
  // 空のロウオブジェクトを生成
  gsCreateRowByContainer(container, &row);

  // カーソルを移動する
  ret = gsGetNextRow(rs, row);
  if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsGetNextRow\n");
    goto LABEL_ERROR;
  }

  // ロウを削除する
  ret = gsDeleteCurrentRow(rs);
  if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsDeleteCurrentRow\n");
    goto LABEL_ERROR;
  }
}

// (4)コミットする
ret = gsCommit(container);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsCommit\n");
  goto LABEL_ERROR;
}

printf("Delete Row\n");

[メモ]

4.3.11 コンテナを削除する

コンテナ名を指定してコンテナを削除します。以下のメソッドで削除できます。

分類 メソッド
コレクション削除 gsDropCollection(GSGridStore *store, const GSChar *name)
時系列コンテナ削除 gsDropTimeSeries(GSGridStore *store, const GSChar *name)
コンテナ削除 gsDropContainer(GSGridStore *store, const GSChar *name)

[メモ]

コレクション"collection1"を削除するプログラムを以下に示します。

// コレクション"collection1"を削除する
gsDropCollection(store, "collection1");

4.3.12 索引を作成する

コンテナのカラムに索引を作成します。

索引種別には、ハッシュ索引、ツリー索引、空間索引の3種類があります。コンテナ種別やカラムのデータ型によって、指定できる索引種別が異なります。索引種別の詳細についてはJava APIの索引を作成するを参照ください。

索引作成は、索引種別やカラムを指定する方法の違いで以下の2種類のメソッドがあります。

分類 メソッド
索引作成(カラム名、番号、索引種別、索引名を指定) gsCreateIndexDetail(GSContainer *container, const GSIndexInfo *info)
索引作成(カラム名と索引種別を指定) gsCreateIndex(GSContainer *container, const GSChar *columnName, GSIndexTypeFlags flags)

[メモ]

索引作成gsCreateIndexDetailを使用して、コレクションのカラムcountにツリー索引を作成するプログラムを以下に示します。

// (コンテナオブジェクトの取得は省略)

// (1)索引情報を設定する
GSIndexInfo info;
info.name = "hash_index";
info.type = GS_INDEX_FLAG_HASH;
info.columnName = "count";
info.column = 2;

// (2)索引を作成する
ret = gsCreateIndexDetail(container, &info);
if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsCreateIndexDetail\n");
    goto LABEL_ERROR;
}

// (3)複合索引の索引情報を設定する
compositeInfo.name = "composite_index";
compositeInfo.type = GS_INDEX_FLAG_TREE;
compositeInfo.columnNameList = indexColumnNameList;
compositeInfo.columnNameCount = indexColumnNameCount;

// (4)複合索引を作成する
ret = gsCreateIndexDetail(container, &compositeInfo);
if (!GS_SUCCEEDED(ret)) {
    fprintf(stderr, "ERROR gsCreateIndexDetail\n");
    goto LABEL_ERROR;
}

(1)索引情報GSIndexInfoには、索引種別、索引名、作成対象のカラムを指定します。
(2)GSIndexInfoを引数として、gsCreateIndexDetailを実行します。
(3)複合索引の場合、索引情報GSIndexInfoに指定する作成対象のカラム(カラム番号またはカラム名)は配列形式で指定します。
(4)GSIndexInfoを引数として、gsCreateIndexDetailを実行します。

4.3.13 その他

4.3.13.1 データ型の対応付け

C APIにおいて、GridDBのデータ型とCのデータ型の対応付けは以下の通りです。ロウからの値取得や設定の際には、以下のデータ型を指定してください。

GridDBのデータ型 Cのデータ型 補足
BOOL型 GSBool 値はGS_TRUEまたはGS_FALSE
STRING型 GSChar GSCharはchar型
BYTE型 int8_t
SHORT型 int16_t
INTEGER型 int32_t
LONG型 int64_t
FLOAT型 float
DOUBLE型 double
TIMESTAMP型 GSTimestamp GSTimestampはint64_t型。値はミリ秒単位のUNIX時刻を表す。
GEOMETRY型 GSChar 値はWKT表記の文字列を表す
BLOB型 GSBlob GSBlobは、データサイズsizeとデータへのポインタdataをメンバに持つ構造体

4.3.13.2 エラー処理

C APIの多くのメソッドは、戻り値としてメソッドの成否を表す実行結果コードGSResultを返します。メソッドの成否は、マクロGS_SUCCEEDEDを用いて以下のようにチェックすることができます。

GSResult ret = gsGetContainerGeneral(store, "containerName", &container);
if ( !GS_SUCCEEDED(ret) ){
    // gsGetContainerGeneralでエラーが発生
}

エラーが発生した場合には以下のメソッドを用いてエラー情報を取得することができます。

分類 メソッド
エラー情報のスタックサイズの取得 gsGetErrorStackSize(void *gsResource)
エラーコードの取得 gsGetErrorCode(void *gsResource, size_t stackIndex)
エラーメッセージの取得 gsFormatErrorMessage(void *gsResource, size_t stackIndex, GSChar *strBuf, size_t bufSize)
内部のエラー発生位置情報の取得 gsFormatErrorLocation(void *gsResource, size_t stackIndex, GSChar *strBuf, size_t bufSize)
タイムアウトのエラーコードの判定 gsIsTimeoutError(GSResult result)

エラーが発生した時に、エラーコードやエラーメッセージを表示するプログラムの例を以下に示します。

size_t stackSize;
size_t s;
GSResult errorCode;
GSChar errMsgBuf1[1024], errMsgBuf2[1024];  // エラーメッセージを格納するバッファ

// エラーコードとエラーメッセージを出力する
stackSize = gsGetErrorStackSize(store);
for ( s = 0; s < stackSize; s++ ){
    errorCode = gsGetErrorCode(store, s);
    gsFormatErrorMessage(store, s, errMsgBuf1, sizeof(errMsgBuf1));
    gsFormatErrorLocation(store, s, errMsgBuf2, sizeof(errMsgBuf2));
    printf("[%d] %s (%s)\n", errorCode, errMsgBuf1, errMsgBuf2);
}

引数gsResourceには、エラーが発生した時の操作対象のオブジェクト、または、そのオブジェクトを生成した上位のオブジェクトを指定します。

例えば、コンテナへのロウ登録処理でエラーが発生した場合には、コンテナオブジェクト、または、コンテナオブジェクトを取得する際に使用したGSGridStoreのどちらでも、エラー情報は取得できます。

プログラムのエラー処理の方法に合わせて、メソッド単位でエラー処理をする場合には処理対象のオブジェクトを指定、複数の処理をまとめて大きな単位でエラー処理をする場合にはGSGridStoreオブジェクトを指定することもできます。

例) メソッド単位でエラー処理をする場合

// ロウを登録する
ret = gsPutRow(container, NULL, row, NULL);
if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsPutRow\n");
    // エラーコードとエラーメッセージを出力する(containerオブジェクトを指定)
    stackSize = gsGetErrorStackSize(container);
    for ( s = 0; s < stackSize; s++ ){
        errorCode = gsGetErrorCode(container, s);
        gsFormatErrorMessage(container, s, errMsgBuf1, sizeof(errMsgBuf1));
        gsFormatErrorLocation(container, s, errMsgBuf2, sizeof(errMsgBuf2));
        printf("[%d] %s (%s)\n", errorCode, errMsgBuf1, errMsgBuf2);
    }
    return;
}

4.3.13.3 TIMESTAMP型のユーティリティ機能

TIMESTAMP型のデータは、C APIではGSTimestamp型として扱います。 GSTimestamp型に対するユーティリティ機能として以下のメソッドがあります。

分類 メソッド
現在時刻の取得 gsCurrentTime()
時刻の加算 gsAddTime(GSTimestamp timestamp, int32_t amount, GSTimeUnit timeUnit)
GSTimestamp型を文字列表記に変換 gsFormatTime(GSTimestamp timestamp, GSChar *strBuf, size_t bufSize)
文字列表記をGSTimestamp型に変換 gsParseTime(const GSChar *str, GSTimestamp *timestamp)

ロウから取得したGSTimestamp型の値を文字列表記に変換する例を示します。

GSTimestamp date;
GSChar buf[GS_TIME_STRING_SIZE_MAX];

// ロウからGSTimestampの値を取得する
gsGetRowFieldAsTimestamp(row, 0, &date);

// GSTimestampを文字列に変換する
gsFormatTime(date, buf, GS_TIME_STRING_SIZE_MAX);

4.4 プログラミングの応用

4.4.1 時系列データを扱う

時系列コンテナに対して、時系列データ特有の演算を実行することができます。この節では、これらの時系列データ特有の演算について説明します。

演算は、TQLまたはメソッドで実行することができます。

種類 名称 TQL演算 メソッド
集計演算 重み付き平均値 TIME_AVG gsAggregateTimeSeries
(GS_AGGREGATION_WEIGHTED_AVERAGEを指定)
選択演算 直後の時刻 TIME_NEXT gsGetRowByBaseTime
(GS_TIME_OPERATOR_NEXTを指定)
直後の時刻 TIME_NEXT_ONLY gsGetRowByBaseTime
(GS_TIME_OPERATOR_NEXT_ONLYを指定)
直前の時刻 TIME_PREV gsGetRowByBaseTime
(GS_TIME_OPERATOR_PREVIOUSを指定)
直前の時刻 TIME_PREV_ONLY gsGetRowByBaseTime
(GS_TIME_OPERATOR_PREVIOUS_ONLYを指定)
補間演算 線形補間 TIME_INTERPOLATED gsInterpolateTimeSeriesRow
サンプリング TIME_SAMPLING gsQueryByTimeSeriesSampling

以下では、TQL演算を用いたプログラミングの例で説明します。

4.4.1.1 集計演算

4.4.1.1.1 TIME_AVG 時刻の重み付き平均値

演算の詳細については、Java APIのTIME_AVG 時刻の重み付き平均値を参照ください。

[メモ]

4.4.1.2 選択演算

指定された時刻と直前/直後の選択条件に基づいて、時系列コンテナのロウキーの時刻が合致するロウを返します。

演算の詳細については、Java APIの選択演算を参照ください。

[メモ]

4.4.1.3 補間演算

時系列データを補間します。

演算の詳細については、Java APIの補間演算を参照ください。

[メモ]

4.4.2 期限解放を設定する

期限解放の設定は、時系列コンテナを作成する時に行います。コンテナ作成後には設定することができません。

期限解放を設定して時系列コンテナを作成するメソッドは以下の通りです。

メソッド
gsPutTimeSeries(GSGridStore *store, const GSChar *name, const GSBinding *binding, const GSTimeSeriesProperties *properties, GSBool modifiable, GSTimeSeries **timeSeries)
gsPutTimeSeriesGeneral (GSGridStore *store, const GSChar *name, const GSContainerInfo *info, GSBool modifiable, GSTimeSeries **timeSeries)
gsPutContainer(GSGridStore *store, const GSChar *name, const GSBinding *binding, const GSContainerInfo *info, GSBool modifiable, GSContainer **container)
gsPutContainerGeneral(GSGridStore *store, const GSChar *name, const GSContainerInfo *info, GSBool modifiable, GSContainer **container)

時系列コンテナの情報GSTimeSeriesPropertiesに対して期限解放を設定し、これを時系列コンテナ作成メソッドに指定して作成します。 GSTimeSeriesPropertiesは、引数または、GSContainerInfoのメンバ変数として指定します。

分類 属性
コンテナ情報に時系列コンテナ特有の情報をセット GSContainerInfo.timeSeriesProperties
ロウ期限解放の期間の設定 GSTimeSeriesProperties.rowExpirationTime
ロウ期限解放の期間の単位の設定 GSTimeSeriesProperties.rowExpirationTimeUnit
ロウ期限解放の分割数の設定 GSTimeSeriesProperties.expirationDivisionCount

期限解放を設定して時系列コンテナを作成するプログラムを示します。

// (1)コンテナ種別を設定する
info.type = GS_CONTAINER_TIME_SERIES;

// (2)ロウキーを設定する
info.rowKeyAssigned = GS_TRUE;

// (3)ロウ期限解放を設定する
timeProp.rowExpirationTime = 100;
timeProp.rowExpirationTimeUnit = GS_TIME_UNIT_DAY;
timeProp.expirationDivisionCount = 5;
info.timeSeriesProperties = &timeProp;

// (4)カラム情報を定義する
columnInfo.name = "date";
columnInfo.type = GS_TYPE_TIMESTAMP;
columnInfoList[0] = columnInfo;

columnInfo.name = "value";
columnInfo.type = GS_TYPE_DOUBLE;
columnInfoList[1] = columnInfo;

info.columnCount = sizeof(columnInfoList) / sizeof(*columnInfoList);
info.columnInfoList = columnInfoList;

// (5)時系列コンテナを作成する
ret = gsPutTimeSeriesGeneral(store, "SampleC_RowExpiration", &info, GS_FALSE, &timeseries);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsPutTimeSeriesGeneral\n");
  goto LABEL_ERROR;
}

4.4.3 データを圧縮する

時系列コンテナでは、次の2種類の方式によってデータを圧縮できます。

圧縮方式の設定は、コンテナを作成する時に行います。コンテナ作成後には設定することができません。

圧縮の方式や誤差の範囲の設定は、以下のメソッドで行います。

分類 メンバ変数
圧縮方式の指定 GSTimeSeriesProperties.compressionMethod
圧縮設定のリスト GSTimeSeriesProperties.compressionList
圧縮設定の数 GSTimeSeriesProperties.compressionListSize
連続して間引きされるロウの最大期間の設定 GSTimeSeriesProperties.compressionWindowSize
連続して間引きされるロウの最大期間の単位の設定 GSTimeSeriesProperties.compressionWindowSizeUnit

誤差あり間引き圧縮方式(HI)の時系列コンテナを作成するプログラムを以下に示します。

GSContainerInfo info = GS_CONTAINER_INFO_INITIALIZER;
GSTimeSeriesProperties timeProp = GS_TIME_SERIES_PROPERTIES_INITIALIZER;
GSColumnCompression comp = GS_COLUMN_COMPRESSION_INITIALIZER;

// (1)コンテナ種別を設定する
info.type = GS_CONTAINER_TIME_SERIES;

// (2)ロウキーを設定する
info.rowKeyAssigned = GS_TRUE;

// (3)カラム圧縮を設定する
comp.columnName = "value";
comp.width = 0.7;

timeProp.compressionMethod = GS_COMPRESSION_HI;
timeProp.compressionList = &comp;
timeProp.compressionListSize = 1;

info.timeSeriesProperties = &timeProp;

// (4)カラム情報を定義する
columnInfo.name = "date";
columnInfo.type = GS_TYPE_TIMESTAMP;
columnInfoList[0] = columnInfo;

columnInfo.name = "value";
columnInfo.type = GS_TYPE_DOUBLE;
columnInfoList[1] = columnInfo;

info.columnCount = sizeof(columnInfoList) / sizeof(*columnInfoList);
info.columnInfoList = columnInfoList;

// (5)時系列コンテナを作成する
ret = gsPutTimeSeriesGeneral(store, "SampleC_Compression", &info, GS_FALSE, &timeseries);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsPutTimeSeriesGeneral\n");
  goto LABEL_ERROR;
}

4.4.4 配列型のデータを扱う

配列型のデータのセットや取得を行うための配列型用のsetter/getterがあります。配列型のデータ型に合わせたsetter/getterを使用してロウを操作し、データの登録や取得を行います。

分類 メソッド
ブール型の配列 gsSetRowFieldByBoolArray(GSRow *row, int32_t column, const GSBool *fieldValue, size_t size)
gsGetRowFieldAsBoolArray(GSRow *row, int32_t column, const GSBool **fieldValue, size_t *size)
STRING型の配列 gsSetRowFieldByStringArray(GSRow *row, int32_t column, const GSChar *const *fieldValue, size_t size)
gsGetRowFieldAsStringArray(GSRow *row, int32_t column, const GSChar *const **fieldValue, size_t *size)
BYTE型の配列 gsSetRowFieldByByteArray(GSRow *row, int32_t column, const int8_t *fieldValue, size_t size)
gsGetRowFieldAsByteArray(GSRow *row, int32_t column, const int8_t **fieldValue, size_t *size)
SHORT型の配列 gsSetRowFieldByShortArray(GSRow *row, int32_t column, const int16_t *fieldValue, size_t size)
gsGetRowFieldAsShortArray(GSRow *row, int32_t column, const int16_t **fieldValue, size_t *size)
INTEGER型の配列 gsSetRowFieldByIntegerArray(GSRow *row, int32_t column, const int32_t *fieldValue, size_t size)
gsGetRowFieldAsIntegerArray(GSRow *row, int32_t column, const int32_t **fieldValue, size_t *size)
LONG型の配列 gsSetRowFieldByLongArray(GSRow *row, int32_t column, const int64_t *fieldValue, size_t size)
gsGetRowFieldAsLongArray(GSRow *row, int32_t column, const int64_t **fieldValue, size_t *size)
FLOAT型の配列 gsSetRowFieldByFloatArray(GSRow *row, int32_t column, const float *fieldValue, size_t size)
gsGetRowFieldAsFloatArray(GSRow *row, int32_t column, const float **fieldValue, size_t *size)
DOUBLE型の配列 gsSetRowFieldByDoubleArray(GSRow *row, int32_t column, const double *fieldValue, size_t size)
gsGetRowFieldAsDoubleArray(GSRow *row, int32_t column, const double **fieldValue, size_t *size)
TIMESTAMP型の配列 gsSetRowFieldByTimestampArray(GSRow *row, int32_t column, const GSTimestamp *fieldValue, size_t size)
gsGetRowFieldAsTimestampArray(GSRow *row, int32_t column, const GSTimestamp **fieldValue, size_t *size)

配列型データを登録するプログラムを示します。

// (1)配列型のデータ
const GSChar *stringArray[4] = { "Sales", "Development", "Marketing", "Research" };
const int32_t integerArray[4] = { 39, 92, 18, 51 };


// (2)空のロウオブジェクトの作成
ret = gsCreateRowByContainer(collection, &row);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsCreateRowByContainer\n");
  goto LABEL_ERROR;
}

// (3)カラム値をセット
gsSetRowFieldByInteger(row, 0, 0);
gsSetRowFieldByStringArray(row, 1, stringArray, 4);
gsSetRowFieldByIntegerArray(row, 2, integerArray, 4);

// (4)ロウを登録する
ret = gsPutRow(collection, NULL, row, NULL);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsPutRow\n");
  goto LABEL_ERROR;
}

gsCloseRow(&row)

配列型データを取得するプログラムを示します。

int32_t id;
const GSChar * const * stringArray;
const int32_t * integerArray;
size_t stringCount;
size_t integerCount;

// (1)空のロウオブジェクトの作成
gsCreateRowByContainer(collection, &row);

// (2)ロウキーを指定してロウ取得
ret = gsGetRowByInteger(collection, 0, row, GS_FALSE, NULL);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetRowByInteger\n");
  goto LABEL_ERROR;
}

// (3)ロウから配列型データを取得
gsGetRowFieldAsInteger(row, 0, &id);
gsGetRowFieldAsStringArray(row, 1, &stringArray, &stringCount);
gsGetRowFieldAsIntegerArray(row, 2, &integerArray, &integerCount);

printf("Get Row (id=%d,", id);

printf("[");
for( i = 0; i < stringCount; i++ ){
  if ( i != 0 ) printf(", ");
  printf("%s", *stringArray);
  stringArray++;
}
printf("],[");

for( i = 0; i < integerCount; i++ ){
  if ( i != 0 ) printf(", ");
  printf("%d", *integerArray);
  integerArray++;
}
printf("])\n");

gsCloseRow(&row);

[メモ]

4.4.5 空間型のデータを扱う

空間型のデータを登録、取得します。

空間型のデータを表すWKT(Well-Known Text)形式の値で操作します。 WKT形式は、ISOで定められている標準的な書式で、空間型のデータをテキスト形式で表現できます。

空間型のデータのセットや取得を行うための空間型用のsetter/getterがあります。これらを用いて、空間型データの登録や取得を行います。

分類 メソッド
空間型データのセット gsSetRowFieldByGeometry(GSRow *row, int32_t column, const GSChar *fieldValue)
空間型データの取り出し gsGetRowFieldAsGeometry(GSRow *row, int32_t column, const GSChar **fieldValue)

空間型データを登録するプログラムを示します。

// (1)空のロウオブジェクトの作成
ret = gsCreateRowByContainer(collection, &row);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsCreateRowByContainer\n");
  goto LABEL_ERROR;
}

// (2)カラム値をセット
gsSetRowFieldByInteger(row, 0, 0);
gsSetRowFieldByGeometry(row, 1, "POINT(2 3)");

// (3)ロウを登録する
ret = gsPutRow(collection, NULL, row, NULL);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsPutRow\n");
  goto LABEL_ERROR;
}

printf("Put Row (Geometry)\n");

gsCloseRow(&row);

空間型データを取得するプログラムを示します。

int32_t id;
const GSChar * geometry;

// (1)空のロウオブジェクトの作成
gsCreateRowByContainer(collection, &row);

// (2)ロウキーを指定してロウ取得
ret = gsGetRowByInteger(collection, 0, row, GS_FALSE, NULL);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetRowByInteger\n");
  goto LABEL_ERROR;
}

// (3)ロウから配列型データを取得
gsGetRowFieldAsInteger(row, 0, &id);
gsGetRowFieldAsGeometry(row, 1, &geometry);

printf("Get Row (id=%d, geometry=%s)\n", id, geometry);

gsCloseRow(&row);

[メモ]

4.4.6 コンテナ情報を取得する

コンテナの情報を取得する操作を説明します。

4.4.6.1 コンテナ名の一覧を取得する

作成されているコンテナの名前の一覧を取得します。

コンテナ名の一覧取得は、パーティションの情報を取得するためのコントローラGSPartitionControllerインスタンスを用いて行います。

分類 メソッド
パーティションコントローラの取得 gsGetPartitionController(GSGridStore *store, GSPartitionController **partitionController)
パーティション数の取得 gsGetPartitionCount(GSPartitionController *controller, int32_t *partitionCount)
コンテナ名の一覧取得 gsGetPartitionContainerNames(GSPartitionController *controller, int32_t partitionIndex, int64_t start, const int64_t *limit, const GSChar *const **nameList, size_t *size)

パーティションコントローラを介して、パーティションごとにコンテナ名の一覧を取得します。コンテナ名一覧を取得するプログラムを示します。

GSPartitionController * pc;
int32_t pcCount;
const GSChar *const * nameList;
size_t nameCount;

// (1)パーティションコントローラと、パーティション数を取得する
ret = gsGetPartitionController(store, &pc);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetPartitionController\n");
  goto LABEL_ERROR;
}
gsGetPartitionCount(pc, &pcCount);


// (2)パーティション数でループして、コンテナ名一覧を取得する
for( i = 0; i < pcCount; i++) {
  ret = gsGetPartitionContainerNames(pc, i, 0, NULL, &nameList, &nameCount);
  if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsGetPartitionContainerNames\n");
    goto LABEL_ERROR;
  }

  for( j = 0; j < nameCount; j++ ){
    printf("%s\n", *nameList);
    nameList++;
  }
}

(2)gsGetPartitionContainerNamesメソッドで、第3引数startに0, 第4引数limitにNULLを指定すると、指定したパーティション上の全コンテナ名を取得します。取得するコンテナ名の数を制限する場合は、第4引数limitに制限する数を指定してください。

[メモ]

4.4.6.2 コンテナのスキーマ情報を取得する

コンテナに関する情報は、コンテナ情報ContainerInfoから取得します。

分類 メソッド
コンテナ情報の取得 gsGetContainerInfo(GSGridStore *store, const GSChar *name, GSContainerInfo *info, GSBool *exists)

ContainerInfoには、様々な情報を取得するsetterメソッドがあります。必要な情報を取得するメソッドを使用してください。メソッドの詳細は、『GridDB Java APIリファレンス』(GridDB_Java_API_Reference.html)をご参照ください。

コンテナのカラム情報を取得するプログラムを示します。

GSContainerInfo info = GS_CONTAINER_INFO_INITIALIZER;
GSBool exist;

// (1)コンテナ情報を取得する
ret = gsGetContainerInfo(store, "SampleC_Info", &info, &exist);
if ( !GS_SUCCEEDED(ret) ){
  fprintf(stderr, "ERROR gsGetContainerInfo\n");
  goto LABEL_ERROR;
}
if ( !exist ){
  printf("Container not found\n");
  goto LABEL_ERROR;
}

// (2)コンテナ情報を表示する
printf("Get ContainerInfo: \n    name=%s\n", info.name);
if ( info.type == GS_CONTAINER_COLLECTION ){
  printf("    type=Collection\n");
} else {
  printf("    type=TimeSeries\n");
}
printf("    rowKeyAssigned=%d\n", info.rowKeyAssigned);

printf("    columnCount=%d\n", info.columnCount);
for ( i = 0; i < info.columnCount; i++ ){
  printf("    column (%s, %d)\n", info.columnInfoList[i].name, info.columnInfoList[i].type);
}

4.4.7 複合ロウキーを扱う

データの登録や検索の処理では、複合ロウキーを指定して操作を行うことができます。

複合ロウキーを設定したデータを登録するプログラムを示します。複合ロウキーとして1つ目のINTEGER型と2つ目のSTRING型を指定します。

    //===============================================
    // クラスタに接続する
    //===============================================
    // 接続情報を指定する (マルチキャスト方式)
    const GSPropertyEntry props[] = {
        { "notificationAddress", "239.0.0.1" },
        { "notificationPort", "31999" },
        { "clusterName", "myCluster" },
        { "database", "public" },
        { "user", "admin" },
        { "password", "admin" },
        { "applicationName", "SampleC" }
    };
    
    const size_t propCount = sizeof(props) / sizeof(*props);

    // 複合ロウキー設定
    const int32_t rowKeyColumnList[] = { 0, 1 };
    const size_t rowKeyColumnCount = sizeof(rowKeyColumnList) / sizeof(*rowKeyColumnList);

    GSBool exists;

    // GridStoreインスタンスを取得する
    ret = gsGetGridStore(gsGetDefaultFactory(), props, propCount, &store);
    if ( !GS_SUCCEEDED(ret) ){
        fprintf(stderr, "ERROR gsGetGridStore\n");
        goto LABEL_ERROR;
    }
    // コンテナ作成や取得などの操作を行うと、クラスタに接続される
    ret = gsGetContainerGeneral(store, "SampleC_CompositKey", &collection);
    if ( !GS_SUCCEEDED(ret) ){
        fprintf(stderr, "ERROR gsGetContainerGeneral\n");
        goto LABEL_ERROR;
    }
    gsCloseContainer(&container, GS_TRUE);
    printf("Connect to Cluster\n");

    //===============================================
    // データ準備 (コンテナ作成&ロウ登録)
    //===============================================
    // コンテナ情報を設定する
    info0.type = GS_CONTAINER_COLLECTION;
    info0.rowKeyColumnList = rowKeyColumnList;
    info0.rowKeyColumnCount = rowKeyColumnCount;

    // カラム情報を定義する
    columnInfo.name = "id";
    columnInfo.type = GS_TYPE_INTEGER;
    columnInfoList[0] = columnInfo;

    columnInfo.name = "productName";
    columnInfo.type = GS_TYPE_STRING;
    columnInfoList[1] = columnInfo;

    columnInfo.name = "count";
    columnInfo.type = GS_TYPE_INTEGER;
    columnInfoList[2] = columnInfo;

    // カラム情報をコンテナ情報オブジェクトに設定する
    info.columnCount = sizeof(columnInfoList) / sizeof(*columnInfoList);
    info.columnInfoList = columnInfoList;

    for ( i = 0; i < containerCount; i++ ){
        // コレクションを作成する
        ret = gsPutContainerGeneral(store, containerNameList[i], &info0, GS_FALSE, &container);
        if ( !GS_SUCCEEDED(ret) ){
            fprintf(stderr, "ERROR gsPutCollectionGeneral\n");
            goto LABEL_ERROR;
        }
        printf("Sample data generation: Create Collection name=%s\n", containerNameList[i]);

        // 複数のロウを登録する
        for ( j = 0; j < rowCount; j++ ){
            gsCreateRowByContainer(container, &row);
            gsSetRowFieldByInteger(row, 0, j);
            gsSetRowFieldByString(row, 1, nameList[j]);
            gsSetRowFieldByInteger(row, 2, numberList[i][j]);

            rowList[j] = row;
        }
        rowObj = (void *)rowList;
        ret = gsPutMultipleRows(container, rowObj, rowCount, NULL);
        if ( !GS_SUCCEEDED(ret) ){
            fprintf(stderr, "ERROR gsPutMultipleRows\n");
            goto LABEL_ERROR;
        }
        printf("Sample data generation: Put Rows count=%d\n", rowCount);
        
        gsCloseContainer(&container, GS_TRUE);
    }

複数のコンテナから、複合ロウキーで指定した条件に当てはまるデータを取得するプログラムを示します。指定する条件は、個別条件指定を用い、1つ目のコンテナからはINTEGER型のロウキーの値が"0"、STRING型のロウキー値が"notebook PC"に合致するロウを、2つ目のコンテナからも1つ目と同様にINTEGER型のロウキーの値が"0"、STRING型のロウキー値が"notebook PC"に合致するロウを取得します。

//===============================================
// 複数のコンテナから一括でロウを取得する
//===============================================

// (1)ロウ取得条件を構築する
for (i = 0; i < containerCount; i++) {
    ret = gsCreateRowKeyByStore(store, &info0, &rowKey);
    if (!GS_SUCCEEDED(ret)) {
        fprintf(stderr, "ERROR gsCreateRowKeyByStore\n");
        goto LABEL_ERROR;
    }

    ret = gsSetRowFieldByInteger(rowKey, 0, 0);
    if (!GS_SUCCEEDED(ret)) {
        fprintf(stderr, "ERROR gsSetRowFieldByInteger\n");
        goto LABEL_ERROR;
    }

    ret = gsSetRowFieldByString(rowKey, 1, "notebook PC");
    if (!GS_SUCCEEDED(ret)) {
        fprintf(stderr, "ERROR gsSetRowFieldByInteger\n");
        goto LABEL_ERROR;
    }

    ret = gsCreateRowKeyPredicateGeneral(store, &info0, &predicate);
    if (!GS_SUCCEEDED(ret)) {
        fprintf(stderr, "ERROR gsCreateRowKeyPredicateGeneral\n");
        goto LABEL_ERROR;
    }

    ret = gsAddPredicateGeneralKey(predicate, rowKey);
    if (!GS_SUCCEEDED(ret)) {
        fprintf(stderr, "ERROR gsAddPredicateGeneralKey\n");
        goto LABEL_ERROR;
    }

    // GSRowKeyPredicateEntryに条件を格納する
    predEntryValueList[i].containerName = containerNameList[i];
    predEntryValueList[i].predicate = predicate;

    predEntryList[i] = &predEntryValueList[i];
}

// (2)複数コンテナからロウを一括取得する
ret = gsGetMultipleContainerRows(store, predEntryList, containerCount, &outEntryList, &outEntryCount);
if ( !GS_SUCCEEDED(ret) ){
    fprintf(stderr, "ERROR gsGetMultipleContainerRows\n");
    goto LABEL_ERROR;
}

// (3)取得結果をコピーする
// ※gsGetRowFieldAsStringなど、結果を取得する関数は、
//   値の書き換えが行われうる仕様
//   関数呼び出し前に結果はコピーしておく
for (i = 0; i < outEntryCount; i++) {
    outEntry = outEntryList[i];
    for (j = 0; j < outEntry.rowCount; j++) {
        allRowList[i][j] = (GSRow*)outEntry.rowList[j];
    }
}

// (4)取得結果を出力する
for (i = 0; i < outEntryCount; i++) {
    for (j = 0; j < outEntryList[i].rowCount; j++) {
        row = allRowList[i][j];

        gsGetRowFieldAsInteger(row, 0, &id);
        gsGetRowFieldAsString(row, 1, &productName);
        gsGetRowFieldAsInteger(row, 2, &count);

        printf("MultiGet: container=%s, id=%d, productName=%s, count=%d\n", outEntryList[i].containerName, id, productName, count);
    }
}

[メモ]

5 JDBC (NewSQLインタフェース)

5.1 JDBCを利用したアプリケーションの開発

5.1.1 開発実行環境の構築

JDBCのアプリケーションを開発するには、以下のパッケージをインストールする必要があります。

パッケージ名 ファイル名 内容
griddb-ee-java_lib griddb-ee-java_lib-X.X.X-linux.x86_64.rpm Java APIのライブラリ(gridstore.jar, gridstore-conf.jar, gridstore-advanced.jar, gridstore-jdbc.jar)が含まれます

※: X.X.XはGridDBのバージョン

アプリケーションの開発や実行を行う際には、以下のライブラリをクラスパスに指定してください。

また、SSL機能を利用してGridDBクラスタとクライアントの通信を保護する場合には、以下のライブラリも追加でクラスパスに指定してください。

5.1.2 ログ機能

GridDBのJDBCはメソッドの呼び出しごとにログ出力を行う機能があります。このログにJDBCにてどのような操作が行われたのかが出力されるため、アプリケーションに問題が発生した際に、原因解析の情報として用いることができます。ログ機能を有効とすることを推奨します。

JDBCのログ機能を有効にするためには、以下のライブラリをクラスパスに指定してください。

ログ機能はSLF4Jを使うため、SLF4Jのライブラリをクラスパスに指定してください。

また、ロギングライブラリをクラスパスに指定してください。ここではロギングライブラリにLogbackを使用するものとして例を示します。

さらに、Logbackの設定ファイル(logback.xml)をクラスパスに含まれるディレクトリに配置してください。

Logbackの設定ファイルに定義する内容については後述します。

5.1.2.1 ログ出力内容

JDBCのログ出力内容は以下です。

ログ出力を行う対象は以下です。

5.1.2.2 Logbackの設定ファイル

JDBCのログはロガー名「com.toshiba.mwcloud.gs.sql.Logger」で始まります。 Logbackの設定ファイルには、このロガーの出力方法を定義します。設定ファイルのサンプルを以下に示します。

<configuration scan="true" scanPeriod="10 minutes">

    <property name="logPath" value="/var/lib/gridstore/log" />

    <appender name="FILEJDBCLOG"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logPath}/gridstore-jdbc-%d{yyyyMMdd}-%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>

        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%-5p] %m%n</pattern>
        </encoder>
    </appender>

    <logger name="com.toshiba.mwcloud.gs.sql.Logger" level="TRACE" additivity="false">
        <appender-ref ref="FILEJDBCLOG" />
    </logger>

    <root level="info">
    </root>
</configuration>

このサンプルはJDBCのログを下記ファイル名のログファイルに出力するものです。

ログ出力内容の例を以下に示します。

2019-03-08 11:32:13.008 [main] [TRACE] [Trace Start] pid=16112 SQLConnection::prepareStatement()
2019-03-08 11:32:13.011 [main] [TRACE]   [argument]  pid=16112 String=select * from Collection_NoPart_0001 where id = ? and integercol = ?
2019-03-08 11:32:13.049 [main] [TRACE]   [return]    pid=16112 $Proxy3=com.toshiba.mwcloud.gs.sql.internal.SQLPreparedStatement@37b79249
2019-03-08 11:32:13.049 [main] [TRACE] [Trace End]   pid=16112 SQLConnection::prepareStatement()
2019-03-08 11:32:13.049 [main] [TRACE] [Trace Start] pid=16112 SQLPreparedStatement::setString()
2019-03-08 11:32:13.049 [main] [TRACE]   [argument]  pid=16112 Integer=1
2019-03-08 11:32:13.049 [main] [TRACE]   [argument]  pid=16112 String=ID0005
2019-03-08 11:32:13.049 [main] [TRACE] [Trace End]   pid=16112 SQLPreparedStatement::setString()
2019-03-08 11:32:13.050 [main] [TRACE] [Trace Start] pid=16112 SQLPreparedStatement::setInt()
2019-03-08 11:32:13.050 [main] [TRACE]   [argument]  pid=16112 Integer=2
2019-03-08 11:32:13.050 [main] [TRACE]   [argument]  pid=16112 Integer=10006
2019-03-08 11:32:13.050 [main] [TRACE] [Trace End]   pid=16112 SQLPreparedStatement::setInt()
2019-03-08 11:32:13.050 [main] [TRACE] [Trace Start] pid=16112 SQLPreparedStatement::executeQuery()
2019-03-08 11:32:13.060 [main] [TRACE]   [return]    pid=16112 SQLResultSet=com.toshiba.mwcloud.gs.sql.internal.SQLResultSet@52e53663
2019-03-08 11:32:13.060 [main] [TRACE] [Trace End]   pid=16112 SQLPreparedStatement::executeQuery()
2019-03-08 11:32:13.061 [main] [TRACE] [Trace Start] pid=16112 SQLConnection::close()
2019-03-08 11:32:13.062 [main] [TRACE] [Trace End]   pid=16112 SQLConnection::close()

5.1.3 サンプルプログラムの実行

サンプルプログラムのコンパイルと実行方法を説明します。

コンパイルと実行の際には、クラスパスにライブラリgridstore-jdbc.jarを設定します。

サンプルプログラム一覧

分類 プログラム名 内容 作成するコンテナ名
クラスタに接続する JDBCConnect.java マルチキャスト方式でクラスタに接続して切断します。 -
SQLを実行する(コンテナ作成とロウ登録) JDBCCreateTableInsert.java SQLでコンテナを作成してロウを登録します。 SampleJDBC_Create
SQLを実行する(検索) JDBCSelect.java SQLでロウを検索します。 SampleJDBC_Select
プリペアードステートメントを実行する JDBCPreparedStatement.java メソッドでスキーマを指定する方法を用いて、時系列コンテナを作成します。 SampleJDBC_Prepared
バイナリデータを扱う JDBCBlobData.java バイナリデータを扱います。 SampleJDBC_BlobData
メタデータを取得する JDBCMetaData.java メタデータを取得します。 -

5.2 プログラミングの基礎

GridDBで提供しているJDBCは、JDBC標準に準拠していますが、一部未サポートのものや相違点があります。詳細は『GridDB JDBCドライバ説明書』(GridDB_JDBC_Driver_UserGuide.html)をご参照ください。

5.2.1 クラスタに接続する

JDBCのDriverManagerインタフェースを用いて、クラスタに接続します。

接続する際には以下のいずれかのメソッドを使用します。

分類 メソッド ユーザとパスワードの指定
接続 DriverManager.getConnection(String url) ユーザとパスワードはURLで指定します
URL書式: http://・・・&user=(ユーザ名)&password=(パスワード)
接続 DriverManager.getConnection(String url, String user, String password) ユーザとパスワードは引数で指定します
接続 DriverManager.getConnection(String url, Properties info)
または
Connection Driver.connect(String url, Properties info)
ユーザとパスワード、アプリケーション名などはPropertiesで指定します。
プロパティキー
user:ユーザ名(必須)
password:パスワード(必須)
applicationName:アプリケーション名(省略可)
loginTimeout:ログインタイムアウト(省略可)

ユーザとパスワードをPropertiesで指定するDriverManager.getConnectionを用いた接続のプログラムを以下に示します。

import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

public class JDBCConnect {

    public static void main(String[] args){
        try {
            //===============================================
            // クラスタに接続する
            //===============================================
            // JDBCの接続情報
            String jdbcAddress = "239.0.0.1";
            String jdbcPort = "41999";
            String clusterName = "myCluster";
            String databaseName = "public";
            String username = "admin";
            String password = "admin";
            String applicationName = "SampleJDBC";

            // (1)クラスタ名とデータベース名はエンコードする
            String encodeClusterName = URLEncoder.encode(clusterName, "UTF-8");
            String encodeDatabaseName = URLEncoder.encode(databaseName, "UTF-8");

            // (2)URLを組み立てる (マルチキャスト方式)
            String jdbcUrl = "jdbc:gs://"+jdbcAddress+":"+jdbcPort+"/"+encodeClusterName+"/"+encodeDatabaseName;

            Properties prop = new Properties();
            prop.setProperty("user", username);
            prop.setProperty("password", password);
            prop.setProperty("applicationName", applicationName);

            // (3)接続する
            Connection con = DriverManager.getConnection(jdbcUrl, prop);

            System.out.println("Connect to cluster");

            //===============================================
            // 終了処理
            //===============================================
            // (4)接続をクローズする
            con.close();
            System.out.println("success!");

        } catch ( Exception e ){
            e.printStackTrace();
        }
    }
}

5.2.1.1 接続のURL形式

接続時に指定するURL形式を説明します。URL形式は、クラスタの接続方式によって異なります。クラスタの接続先アドレスやクラスタ名、データベース名などをURLに指定します。クラスタ名とデータベース名はURLエンコードが必要です。

マルチキャスト方式

固定リスト方式

プロバイダ方式

5.2.1.2 ログインタイムアウトの設定

接続時のタイムアウトを設定します。設定方法は、ドライバ全体へ設定を行う方法と、コネクション取得時に設定を行う方法の2つがあります。コネクション取得時に設定を行う方法の場合は、その時に取得したコネクションにしかログインタイムアウトの情報は反映されません。

分類 メソッド
ドライバ全体への設定 void DriverManager.setLoginTimeout(int seconds)
コネクションへの設定 Connection DriverManager.getConnection(String url, Properties info)
Connection Driver.connect(String url, Properties info)

5.2.2 トランザクション制御

JDBCでは、トランザクション制御をサポートしていません。データの登録INSERTなどの操作は、SQL文を実行した時点で自動的にロウがコミットされます。

例)

Statement stmt = con.createStatement();
stmt.executeUpdate("CREATE TABLE sqlCollection ( id integer, value string )");
// →実行時点でコミットされる

int ret0 = stmt.executeUpdate("INSERT INTO sqlCollection values (0, 'test0')");
// →実行時点でコミットされる

int ret1 = stmt.executeUpdate("INSERT INTO sqlCollection values "+
                            "(1, 'test1'),(2, 'test2'),(3, 'test3'),(4, 'test4')");
// →実行時点でコミットされる(ロウ単位でコミット)

con.commit();
// →コミット要求は無視される(エラーにはならない)

[メモ]

5.2.3 SQLを実行する(コンテナ作成とロウ登録)

コンテナ作成とロウ登録を行うSQLを実行するプログラムを示します。

import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Properties;

public class JDBCCreateTableInsert {

    public static void main(String[] args){
        try {
            //===============================================
            // クラスタに接続する
            //===============================================
            // JDBCの接続情報
            String jdbcAddress = "239.0.0.1";
            String jdbcPort = "41999";
            String clusterName = "myCluster";
            String databaseName = "public";
            String username = "admin";
            String password = "admin";
            String applicationName = "SampleJDBC";

            // クラスタ名とデータベース名はエンコードする
            String encodeClusterName = URLEncoder.encode(clusterName, "UTF-8");
            String encodeDatabaseName = URLEncoder.encode(databaseName, "UTF-8");

            // URLを組み立てる (マルチキャスト方式)
            String jdbcUrl = "jdbc:gs://"+jdbcAddress+":"+jdbcPort+"/"+encodeClusterName+"/"+encodeDatabaseName;

            Properties prop = new Properties();
            prop.setProperty("user", username);
            prop.setProperty("password", password);
            prop.setProperty("applicationName", applicationName);

            // 接続する
            Connection con = DriverManager.getConnection(jdbcUrl, prop);


            //===============================================
            // コンテナ作成とデータ登録
            //===============================================
            // (1)ステートメント作成
            Statement stmt = con.createStatement();

            // (存在した場合は削除する)
            stmt.executeUpdate("DROP TABLE IF EXISTS SampleJDBC_Create");

            // (2)コンテナ作成のSQL実行
            stmt.executeUpdate("CREATE TABLE SampleJDBC_Create ( id integer PRIMARY KEY, value string )");
            System.out.println("SQL Create Table name=SampleJDBC_Create");

            // (3)ロウ登録のSQL実行
            int ret0 = stmt.executeUpdate("INSERT INTO SampleJDBC_Create values (0, 'test0')");
            System.out.println("SQL Insert count=" + ret0);

            int ret1 = stmt.executeUpdate("INSERT INTO SampleJDBC_Create values "+
                                        "(1, 'test1'),(2, 'test2'),(3, 'test3'),(4, 'test4')");
            System.out.println("SQL Insert count=" + ret1);


            //===============================================
            // 終了処理
            //===============================================
            stmt.close();
            con.close();
            System.out.println("success!");

        } catch ( Exception e ){
            e.printStackTrace();
        }
    }
}

(1)ステートメントを作成し、(2)(3)executeUpdateでコンテナを作成するSQL、ロウを登録するSQLを実行します。戻り値は、コンテナ作成のSQLの場合は成功したら0、ロウ登録のSQLの場合は、登録したロウ数になります。

5.2.4 SQLを実行する(検索)

SQLで検索を行います。Statement.executeQueryメソッドを使用します。

// (1)ステートメント作成
Statement stmt = con.createStatement();

// (2)SQL実行
ResultSet rs = stmt.executeQuery("SELECT * from SampleJDBC_Select where ID > 2");

// (3)結果の取得
while( rs.next() ){
  int id = rs.getInt(1);
  String value = rs.getString(2);
  System.out.println("SQL row(id=" + id + ", value=" + value + ")");
}

executeQueryで検索を実行し、検索結果のロウをResultSet.nextで取り出します。ロウの値は、データ型に対応するgetterを用いて取得します。

取得するロウ数のヒントをJDBCドライバに与える場合は、Statement.setFetchSizeまたはResultSet.setFetchSizeを使用します。

// (2)SQL実行
ResultSet rs = stmt.executeQuery("SELECT * from SampleJDBC_Select where ID > 2");
stmt.setFetchSize(1000);

[メモ]

5.2.5 プリペアードステートメントを実行する

プリペアードステートメントを用いて検索を行うプログラムを示します。

// (1)プリペアードステートメント作成
PreparedStatement pstmt = con.prepareStatement("SELECT * from SampleJDBC_Prepared where ID > ?");

// (2)値を設定する
pstmt.setInt(1, 3);

// (3)SQL実行
ResultSet rs = pstmt.executeQuery();

// (4)結果の取得
while( rs.next() ){
  int id = rs.getInt(1);
  String value = rs.getString(2);
  System.out.println("SQL row(id=" + id + ", value=" + value + ")");
}

5.2.6 バイナリデータを扱う

5.2.6.1 バイナリデータを登録する

バイナリデータの登録では、PreparedStatementインタフェースを使用します。

ロウを登録するINSERT文でPreparedStatementを作成し、setBlob(int parameterIndex, Blob x)でバイナリデータをセットして登録します。 PreparedStatementインタフェースにはバイナリデータをセットするメソッドが様々ありますが、GridDBのJDBCではsetBlob(int parameterIndex, Blob x)のみをサポートしています。

Blobオブジェクトは、SerialBlobなどのBlobを実装したクラスを使用します。Blobオブジェクトを生成するConnectionインタフェースのcreateBlob()は未サポートです。

// バイナリデータを格納するコンテナを作成する
stmt.executeUpdate("CREATE TABLE SampleJDBC_BlobData ( id integer PRIMARY KEY, data blob )");
stmt.close();

// ファイルからバイナリデータを読み込み登録する
// (1)プリペアードステートメントを作成する
PreparedStatement pstmt = con.prepareStatement("INSERT INTO SampleJDBC_BlobData(id, data) VALUES(?, ?)");

// (2)ファイルからバイナリファイルを読み込む
File file = new File("JDBCBlobData.class");
FileInputStream fis = new FileInputStream(file);
  byte[] b = new byte[1];
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  while (fis.read(b) > 0) {
      baos.write(b);
  }
  baos.close();
  fis.close();
  b = baos.toByteArray();

  // (3)BLOBをセットする
SerialBlob serialBlob = new SerialBlob(b);
pstmt.setBlob(2,  serialBlob);
pstmt.setInt(1, 0);

// (4)ロウを登録する
pstmt.executeUpdate();
pstmt.close();

[メモ]

5.2.6.2 バイナリデータを取得する

バイナリデータはResultSetのgetBinaryStreamやgetBlobなどを用いて取得します。

// (1)検索を実行する
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM SampleJDBC_BlobData WHERE id = 0");

while( rs.next() ){
  // (2)バイナリデータを取得してファイルに保存する
  InputStream input = rs.getBinaryStream(2);
  FileOutputStream output = new FileOutputStream("jdbc_output");
  int c;
  while((c=input.read())!=-1){
    output.write(c);
  }
  input.close();
  output.close();
}

5.2.7 メタデータを取得する

メタデータを取得するDatabaseMetaDataインタフェースやResultSetMetaDataインタフェースを用いて、コンテナ名一覧、コンテナのスキーマ情報や索引情報、検索結果のカラム情報などを取得できます。メソッドの詳細は『GridDB JDBCドライバ説明書』(GridDB_JDBC_Driver_UserGuide.html)をご参照ください。

5.2.7.1 コンテナ名一覧を取得する

DatabaseMetaData.getTablesで、コンテナ名一覧を取得します。コンテナ名に対してワイルドカードを使った絞込み条件を指定することができます。

DatabaseMetaData meta = con.getMetaData();

// コンテナ一覧を取得する
System.out.println("DatabaseMetadata.getTables  null");

ResultSet rs = meta.getTables(null, null, null, null);
while( rs.next() ){
  String name = rs.getString("TABLE_NAME");
  String type = rs.getString("TABLE_TYPE");
  System.out.println("  (name=" + name + ", type=" + type +")");
}
rs.close();

// コンテナ名が「SampleJDBC_」で始まるコンテナ一覧を取得する
System.out.println("DatabaseMetadata.getTables SampleJDBC\\_%");

rs = meta.getTables(null, null, "SampleJDBC\\_%", null);
while( rs.next() ){
  String name = rs.getString("TABLE_NAME");
  String type = rs.getString("TABLE_TYPE");
  System.out.println("  (name=" + name + ", type=" + type +")");
}
rs.close();

5.2.7.2 コンテナのスキーマ情報を取得する

DatabaseMetadata.getColumnsで、コンテナのスキーマ情報を取得します。カラム名やデータ型、NOT NULL制約などの情報が取得できます。

DatabaseMetaData meta = con.getMetaData();

// コンテナ"SampleJDBC_Meta1"のカラム情報を取得する
System.out.println("DatabaseMetadata.getColumns  SampleJDBC_Meta1");

rs = meta.getColumns(null, null, "SampleJDBC_Meta1", null);
while( rs.next() ){
    String name = rs.getString("TABLE_NAME");
    String columnName = rs.getString("COLUMN_NAME");
    int columnDataType = rs.getInt("DATA_TYPE");
    String columnTypeName = rs.getString("TYPE_NAME");
    int nullable = rs.getInt("NULLABLE");
    String isNullable = rs.getString("IS_NULLABLE");
    System.out.println("  (name=" + name + ", columnName=" + columnName
            + ", dataType=" + columnDataType + ", typeName=" + columnTypeName
            + ", nullable="+nullable+", isNullable="+isNullable+")");
}
rs.close();

5.2.7.3 検索結果のメタデータを取得する

SQLの検索結果ResultSetのメタデータを、ResultSetMetaDataインタフェースを用いて取得します。カラムの名前やデータ型などを取得できます。

// (1)SQL実行
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * from sqlCollection where ID > 2");

// (2)メタデータ取得
ResultSetMetaData rsMeta = rs.getMetaData();

// (3)メタデータの値を取得
for ( int i = 1; i <= rsMeta.getColumnCount(); i++ ){
    String columnName = rsMeta.getColumnName(i);
    String columnLabelName = rsMeta.getColumnLabel(i);
    String columnTypeClassName = rsMeta.getColumnClassName(i);
    int columnType = rsMeta.getColumnType(i);
    String columnTypeName = rsMeta.getColumnTypeName(i);
    System.out.println("columnName="+columnName+", columnLabelName="+columnLabelName
            + ", columnTypeClassName="+columnTypeClassName+", columnType="+columnType
            + ", columnTypeName="+columnTypeName);
}

5.2.8 JDBCではサポートしていないデータ型を持つコンテナを扱う

JDBCでは、GridDBのデータ型の中で空間型(Geometry型)と配列型をサポートしていません。これらのデータ型のカラムを持つコンテナに対して、JDBCでアクセスした時のアプリケーションの動作を説明します。

[メモ]

5.2.8.1 SQLを実行する(ロウ登録)

空間型と配列型のカラムを持つコンテナに対しては、ロウを登録することはできません。ロウ登録のINSERT文において、サポート範囲のデータ型のカラムの値だけ指定しても、ロウを登録することはできません。

次のカラムを持つコンテナに対して、カラムidとdoubleだけを指定したINSERT文を実行するプログラムを示します。このプログラムはエラーになります。

Statement stmt = con.createStatement();
stmt.executeUpdate("INSERT INTO collection_type (id, double) VALUES (1, 192.3)");
// →SQLExceptionが発生します。

5.2.8.2 SQLを実行する(検索)

空間型と配列型のカラムを持つコンテナを検索した場合、それらのカラムの値を取得した結果は常にNULLです。 ResultSetインタフェースではこれらのデータ型専用のgetterがないため、getObjectで値を取得できます。

次のカラムを持つコンテナに対して、検索を行うプログラムを示します。

Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM collection_type");

while( rs.next() ){
    int id = rs.getInt(1);
    Object geometry = rs.getObject(2);  // NULLが返る
    Object string_array = rs.getObject(3);  // NULLが返る
}

Geometry型と、String型の配列型のカラムの値は、NULLが返ります。

5.2.8.3 メタデータを取得する

DatabaseMetadataインタフェースでカラム情報を取得した時、サポートしていない空間型、配列型のカラムについては、データ型の名前はUNKNOWN、データ型の値はTypes.OTHERが返ります。

6 付録

6.1 APIのサポート範囲の機能詳細

6.1.1 接続機能

GridDBの機能 Java API C API JDBC
マルチキャスト方式の接続
固定リスト方式の接続
プロバイダ方式の接続
接続時のオプション設定(データベース)
接続時のオプション設定(ログインタイムアウト) × ×
接続時のオプション設定(トランザクションタイムアウト) ×
接続時のオプション設定(フェイルオーバタイムアウト) ×
接続時のオプション設定(クエリタイムアウト) × ×
接続時のオプション設定(データ一貫性) ×
接続時のオプション設定(コンテナキャッシュ) ×
接続時のオプション設定(データアフィニティのパターン定義) × ×
接続時のオプション設定(認証方式)
接続時のオプション設定(SSL通信)
接続時のオプション設定(マルチキャストパケットを送出するインターフェースアドレス)
クライアント設定ファイル読み込み × ×

6.1.2 コンテナの機能

コンテナ(パーティショニングコンテナではないコンテナ)の機能について、サポート範囲を以下に示します。

GridDBの機能 Java API C API JDBC
コンテナ作成(メソッドによるスキーマ定義) ○ GridStore.putContainer ○ gsPutContainerGeneral ○(SQL) CREATE TABLE
コンテナ作成(クラスによるスキーマ定義) ○ GridStore.putContainer ○ gsPutContainer ×
コンテナ削除 ○ GridStore.dropContainer ○ gsDropContainer ○(SQL) DROP TABLE
カラム追加 ○ GridStore.putContainer ○ gsPutContainer
gsPutContainerGeneral
○(SQL) ALTER TABLE
カラム削除 ○ GridStore.putContainer ○ gsPutContainer
gsPutContainerGeneral
×
索引(名前なし)作成 ○ Container.createIndex ○ gsCreateIndex ×
索引(名前あり)作成 ○ Container.createIndex ○ gsCreateIndexDetail ○(SQL) CREATE INDEX
索引削除 ○ Container.dropIndex ○ gsDropIndex
gsDropIndexDetail
○(SQL) DROP INDEX
トリガ設定 ○ Container.createTrigger ○ gsCreateTrigger ×
トリガ削除 ○ Container.dropTrigger ○ gsDropTrigger ×
--------------------------- ---------------------------- ----------------------------- ----------------
コンテナ作成のオプション設定(データアフィニティ) ○ ContainerInfo.setDataAffinity
GSContainerInfo.dataAffinity
○(SQL) CREATE TABLE
コンテナ作成のオプション設定(ノードアフィニティ) ○ コンテナ名で指定 ○ コンテナ名で指定 ○(SQL) コンテナ名で指定
コンテナ作成のオプション設定(NOT NULL制約) ○ ColumnInfo ○ GSColumnInfo.options ○(SQL)
時系列コンテナ作成のオプション設定(ロウ期限解放) ○ TimeSeriesProperties ○ GSTimeSeriesProperties ○(SQL)
時系列コンテナ作成のオプション設定(カラム圧縮) ○ TimeSeriesProperties ○ GSTimeSeriesProperties ×
--------------------------- ---------------------------- ----------------------------- ----------------
コンテナオブジェクト取得 ○ GridStore.getContainer ○ gsGetContainerGeneral ×
コンテナのカラム情報取得 ○ Container.getContainerInfo ○ gsGetContainerInfo
コンテナの索引情報取得 ○ Container.getIndexInfo ○ gsGetContainerInfo
--------------------------- ---------------------------- ----------------------------- ----------------
ロウ取得(ロウキー指定) ○ Container.get(K key) ○ gsGetRow ○(SQL)
ロウ取得(参照ロック) ○ Container.get(K key, boolean forUpdate) ○ gsGetRowForUpdate ×
ロウ登録 ○ Container.put(R row) ○ gsPutRow ○(SQL)
ロウ登録(ロウキー指定) ○ Container.put(K key, R row) ○ gsPutRowGeneral ○(SQL)
複数ロウ登録 ○ Container.put(Collection rowCollection) ○ gsPutMultipleRows ○(SQL)
ロウ削除 ○ Container.remove ○ gsDeleteRow ○(SQL)
--------------------------- ---------------------------- ----------------------------- ----------------
ロウオブジェクト生成 ○ Container.createRow ○ gsCreateRowByContainer
gsCreateRowByStore
×
ロウオブジェクトの初期値(NULL使用有無)設定 ○ ColumnInfo(..,boolean defaultValueNull,..) ×
ロウオブジェクトのNULL参照・設定 ○ Row.setNull
Row.isNull
×
--------------------------- ---------------------------- ----------------------------- ----------------
TQLクエリ生成 ○ Container.query ○ gsQuery ×
TQLフェッチ(ロックなし) ○ Query.fetch ○ gsFetch ×
TQLフェッチ(ロックあり) ○ Query.fetch ○ gsFetch ×
TQL結果件数取得 ○ RowSet.size ○ gsGetRowSetSize ×
TQLカーソル確認 ○ RowSet.hasNext ○ gsHasNextRow ×
TQLカーソル移動 ○ RowSet.next ○ gsGetNextRow ×
TQLカーソル位置のロウ更新 ○ RowSet.update ○ gsUpdateCurrentRow ×
TQLカーソル位置のロウ削除 ○ RowSet.remove ○ gsDeleteCurrentRow ×
--------------------------- ---------------------------- ----------------------------- ----------------
SQL実行 × ×
--------------------------- ---------------------------- ----------------------------- ----------------
コミットモード設定 ○ Container.setAutoCommit ○ gsSetAutoCommit ×
コミット ○ Container.commit ○ gsCommit ×
アボート ○ Container.abort ○ gsAbort ×
データフラッシュ ○ Container.flush ○ gsFlush ×
--------------------------- ---------------------------- ----------------------------- ----------------
複数コンテナのロウ登録 ○ GridStore.multiPut ○ gsPutMultipleContainerRows ×
複数コンテナのロウ取得 ○ GridStore.multiGet ○ gsGetMultipleContainerRows ×
複数コンテナのTQL実行 ○ GridStore.fetchAll ○ gsFetchAll ×

時系列コンテナ特有の機能

GridDBの機能 Java API C API JDBC
ロウ取得(時刻の隣接指定) ○ TimeSeries.get ○ gsGetRowByBaseTime ×
ロウ取得(集計演算) ○ TimeSeries.aggregate ○ gsAggregateTimeSeries ×
ロウ取得(補間演算) ○ TimeSeries.interpolate ○ gsInterpolateTimeSeriesRow ×
サンプリングクエリ生成 ○ TimeSeries.query ○ gsQueryByTimeSeriesSampling ×
ロウ登録(現時刻をもつ新規ロウ追加) ○ TimeSeries.append ○ gsAppendTimeSeriesRow ×

コレクション特有の機能

GridDBの機能 Java API C API JDBC
空間型の検索条件のクエリ生成 ○ Collection.query(java.lang.String column, Geometry geometry, GeometryOperator geometryOp) ○ gsQueryByGeometry ×
空間型の検索条件のクエリ生成(除外範囲付き) ○ Collection.query(java.lang.String column, Geometry geometryIntersection, Geometry geometryDisjoint) ○ gsQueryByGeometryWithDisjointCondition ×

6.1.3 パーティショニングコンテナの機能

パーティショニングコンテナの機能について、サポート範囲を以下に示します。

GridDBの機能 Java API C API JDBC
コンテナ作成(ハッシュパーティショニング) × × ○(SQL)
コンテナ作成(インターバルパーティショニング) × × ○(SQL)
コンテナ作成(インターバルハッシュパーティショニング) × × ○(SQL)
コンテナ削除 × × ○(SQL)
カラム追加 × × ○(SQL)
カラム削除 × × ×
索引(名前なし)作成・削除 × × ×
索引(名前あり)作成・削除 × × ○(SQL)
トリガ設定・削除 × × ×
-------------------------------------- ---------------------- ------------ -----------
コンテナ作成のオプション設定(データアフィニティ) × × ○(SQL)
コンテナ作成のオプション設定(ノードアフィニティ) × × ×
コンテナ作成のオプション設定(NOT NULL制約) × × ○(SQL)
コンテナ作成のオプション設定(パーティション期限解放) × × ○(SQL)
コンテナ作成のオプション設定(ロウ期限解放) × × ○(SQL)
時系列コンテナ作成のオプション設定(カラム圧縮) × × ×
-------------------------------------- ---------------------- ------------ -----------
コンテナオブジェクト取得 ○ GridStore.getContainer × ×
コンテナのカラム情報取得 ○ Container.getContainerInfo ×
コンテナの索引情報取得 ○ Container.getIndexInfo ×
-------------------------------------- ---------------------- ------------ -----------
ロウ取得(ロウキー指定) ○ Container.get(K key) × ○(SQL)
ロウ取得(参照ロック) × × ×
ロウ登録 ○ Container.put(R row) × ○(SQL)
ロウ登録(ロウキー指定) × × ×
複数ロウ登録 ○ Container.put(Collection rowCollection) × ○(SQL)
ロウ削除 ○ Container.remove(K key) × ○(SQL)
-------------------------------------- ---------------------- ------------ -----------
ロウオブジェクト生成 ○ Container.createRow × ×
ロウオブジェクトの初期値(NULL使用有無)設定 ○ ColumnInfo(..,boolean defaultValueNull,..) × ×
ロウオブジェクトのNULL参照・設定 ○ Row.setNull
Row.isNull
× ×
-------------------------------------- ---------------------- ------------ -----------
TQLクエリ生成 ○ Container.query × ×
TQLフェッチ(ロックなし) ○ Query.fetch × ×
TQLフェッチ(ロックあり) × × ×
TQL結果件数取得 ○ RowSet.size × ×
TQLカーソル確認 ○ RowSet.hasNext × ×
TQLカーソル移動 ○ RowSet.next × ×
TQLカーソル位置のロウ更新 × × ×
TQLカーソル位置のロウ削除 × × ×
-------------------------------------- ---------------------- ------------ -----------
SQL実行 × ×
-------------------------------------- ---------------------- ------------ -----------
コミットモード設定 × × ×
コミット × × ×
アボート × × ×
データフラッシュ ○ Container.flush × ×
-------------------------------------- ---------------------- ------------ -----------
複数コンテナのロウ登録 ○ GridStore.multiPut × ×
複数コンテナのロウ取得 ○ GridStore.multiGet × ×
複数コンテナのTQL実行 ○ GridStore.fetchAll × ×

時系列コンテナ特有の機能

GridDBの機能 Java API C API JDBC
ロウ取得(時刻の隣接指定) × × ×
ロウ取得(集計演算) × × ×
ロウ取得(補間演算) × × ×
サンプリングクエリ生成 × × ×
ロウ登録(現時刻をもつ新規ロウ追加) × × ×

コレクション特有の機能

GridDBの機能 Java API C API JDBC
空間型の検索条件のクエリ生成 × × ×
空間型の検索条件のクエリ生成(除外範囲付き) × × ×

6.1.4 その他の機能

GridDBの機能 Java API C API JDBC
パーティションコントローラ取得 ○ GridStore.getPartitionController ○ gsGetPartitionController ×
パーティション数取得 ○ PartitionController. getPartitionCount ○ gsGetPartitionCount ×
パーティション単位のコンテナ数取得 ○ PartitionController. getContainerCount ○ gsGetPartitionContainerCount ×
パーティション単位のコンテナ名取得 ○ PartitionController. getContainerNames ○ gsGetPartitionContainerNames ×
ノードアドレス一覧取得 ○ PartitionController. getHosts ○ gsGetPartitionHosts ×
オーナアドレス取得 ○ PartitionController. getOwnerHost ○ gsGetPartitionOwnerHost ×
-------------------------------- -------------------------- --------------------------- --------
現在時刻取得 ○ TimestampUtils.current ○ gsCurrentTime ×
時刻加算 ○ TimestampUtils.add ○ gsAddTime ×
文字列からTimestamp型への変換 ○ TimestampUtils.parse ○ gsParseTime ×
Timestamp型から文字列への変換 ○ TimestampUtils.format ○ gsFormatTime ×
-------------------------------- -------------------------- --------------------------- --------
複数コンテナのロウ取得の個別条件設定 ○ RowKeyPredicate.add ○ gsAddPredicateKeyXXXXX ×
複数コンテナのロウ取得の範囲条件設定 ○ RowKeyPredicate.setStart
RowKeyPredicate.setFinish
○ gsSetPredicateStartKeyXXXXX
gsSetPredicateFinishKeyXXXXX
×

6.2 Java APIのプロパティの外部ファイル指定方法

Java APIで、クラスタ接続のプロパティを外部ファイルで指定する方法は、次の2種類があります。

外部ファイルで指定すると、アプリケーションのソースを修正せずに接続先などのプロパティを変更することができます。

6.2.1 JavaのPropertiesのファイル読み込みを使用する

Propertiesオブジェクトで、プロパティファイルを読み込みます。

Properties prop = new Properties();
prop.load(new FileInputStream("connect.properties"));
GridStore store = GridStoreFactory.getInstance().getGridStore(prop);

プロパティファイルには、プロパティを記載します。

notificationAddress=239.0.0.1
notificationPort=31999
clusterName=myCluster
database=public
user=admin
password=admin

6.2.2 Java APIの「クライアント設定ファイル読み込み機能」を使用する

Java APIには、接続のプロパティを記載したファイル「クライアント設定ファイル」を自動的に読み込む機能があります。

この機能を用いて接続する場合には、以下のライブラリを使用します。

[メモ]

6.3 NoSQLインタフェースを利用する際のヒント

6.3.1 既に存在するコンテナと同じ名前でコンテナを作成した場合はどうなるのか?

同じ名前でコンテナ作成(putContainer)すると、カラムやロウキーなどのスキーマ情報が、既に存在するコンテナと作成するコンテナで同じ内容だった場合にはコンテナ取得(getContainer)と同じ動作になります。スキーマ情報が異なる場合には、コンテナ作成エラーになります。

 

6.3.2 既に存在するロウのロウキーと同じ値でロウ登録した場合はどうなるのか?

ロウキーありのコンテナに対して、既に存在するロウキーと同じ値のロウキーを持つロウを登録(put)すると、既存のロウを更新します。

ロウキーなしのコンテナに対するロウ登録(put)は、常にロウの新規登録になります。

 

6.3.3 登録先のコンテナの定義と異なるロウを登録した場合はどうなるのか?

ロウ登録(put)がエラーになります。

 

6.3.4 複数ロウの登録中に異常が発生した場合はどうなるのか?

自動コミットモードの場合、複数ロウの登録(put(Collection rowCollection), multiPut)の途中で異常が発生すると、一部のロウのみが登録された状態になる場合があります。

 

6.3.5 時系列コンテナ作成時の注意点

時系列コンテナには、TIMESTAMP型のロウキーを設定する必要があります。

そのため、第一カラムのデータ型をTIMESTAMP型にして、かつ、ロウキーの設定を有効にしてください。

これらに反する場合は、コンテナ作成時にエラーが発生します。

 

6.3.6 時系列データの最新または最古のロウ1件を取得する方法

時系列コンテナで最新または最古のロウ1件を取得する場合は、選択演算を用いてください。

この方法を用いると、時系列コンテナのロウキー索引を使用してロウの絞込を行うため、アクセスするロウが最小限になり高速に取得できます。

TQLのORDER BYを用いた方法「SELECT * ORDER BY 時系列カラム DESC LIMIT 1」では、絞込がないため全ロウデータの読出しが発生して、性能が低下します。

6.4 日付時刻機能を利用する上でのアプリ向けの推奨事項