GridDB’s C/Python/Ruby APIsを使ってみよう

最近のデータベースは、そのほとんどが複数のフレームワークとプログラミング言語をサポートしています。 一般的にサポートされている言語の中には、Java、C、Ruby、Pythonなどがあります。 GridDBも同様です。 GridDBは、C、Python、およびRubyプログラミング言語用のAPIを使用して、開発者にツールキットを提供するようになりました。

Setting Up the C API

C lang

GridDBのCクライアントAPIは、 CentOS 6.7 および CentOS 7.3 をサポートしています。 クライアントは互換性があり gcc version-4.8.5 で、コミュニティ版またはスタンダード版で使用できます。 CクライアントのStandard Editionのバージョンでは、ジオメトリの列や操作などをサポートするJava対応のすべての機能がサポートされています。Community Edition用のCクライアントをセットアップするためのファイルと説明は、 GridDB Githubページにあります。

何らかの理由で configure スクリプトまたは bootstrap.sh スクリプトのいずれかでエラーが発生した場合は、これらのコマンドを使用して次のライブラリをインストールします。

$ sudo yum groupinstall ‘Development Tools’
$ sudo yum makecache fast

make コマンドを実行しているときに、 **recursive errorというエラーがスローされた場合は、上記のライブラリがインストールされていることを確認してください。 その後、Github Cリポジトリから新しいものを取得してクローニングして、 c_client ディレクトリを削除します。

そこから、クライアントとGridDB接続をテストするために、c_clientリポジトリに用意されているいくつかのサンプルプログラムを実行して、クライアントをテストできます。

CクライアントファイルをGridDBにコンパイルしてリンクする際に注意すべき点がいくつかあります。 gcc でコンパイルする場合、インクルード(-I)フラグは gridstore.h を含む include >ディレクトリを指します。ライブラリ、または(-L)フラグは、.so ファイルとシンボリックリンクを持つc-clientディレクトリの中にある bin ディレクトリを常に指します。

$ ls c_client/bin
libgridstore.so
libgridstore.so.0
libgridstore.so.0.0.0

ファイルを正常にコンパイルするには、 -lgridstore オプションも使用する必要があります。

また、コンパイルされた実行ファイルが正常に実行されるためには、 LD_LIBRARY_PATH という環境変数を設定する必要があります。 この変数は、GridDB Cクライアントディレクトリの bin ディレクトリを指す必要があります。

Cソースコードファイルのコンパイル例

$ export LD_LIBRARY_PATH=/path/to/c_client/bin
$ gcc -o cSample cSample.c -I./include -L./bin -lgridstore
$ ./cSample 239.0.0.1 31999 defaultCluster admin admin

C APIリファレンスの詳細については、こちらを参照してください。

Python/Ruby API Setup

GridDBは、Python 2.6、2.7、そしてPython 3.6をサポートします。

Pythonライブラリをうまく構築するために重要なことの1つは、Cクライアントを正常に構築する必要があることです。 PythonとRuby用の開発キットも必要です。

$ sudo yum install ruby-devel
$ sudo yum install python-devel

SWIGとpcreライブラリも必要です。 インストール手順とサンプルプログラムについては、 griddb_client ページを参照してください。

PythonやRubyライブラリを使うことについて知っておくべき重要なことは、クライアントの Makefile の変数がc_clientライブラリを指しているため、Cクライアントをインストールしてセットアップする必要があることです。

Cクライアントを設定している場合は、環境変数 LD_LIBRARY_PATH を設定する必要があります。 RubyとPythonの両方のクライアントライブラリファイルを正常に構築するには、この変数の値が必要です。

Makefile でこの行を編集してください。

LDFLAGS = -L/path/c_client/library/bin -lpthread -lrt -lgridstore

Makefileでは、使用されるPythonのデフォルトバージョンはPython 2.6です。 2.7またはPython 3.6を使用する場合は、 Makefile の11行目を編集して make コマンドを正常に実行できるようにします。

MakefileのPythonバージョンを2.6から2.7に変更する例:
Line 11 of Makefile:

INCLUDES_PYTHON = $(INCLUDES) -I/usr/include/python2.6 ## Before Makefile used (Python 2.6)
## Change it to
INCLUDES_PYTHON = $(INCLUDES) -I/usr/include/python2.7 ## After, now uses (Python 2.7)

ソースコードでは、 griddb_python_client ファイルをインポートして、グリッドストア機能にアクセスしてください。

PythonのAPIのリファレンスは、こちらにあります。

Ruby API Features

GridDB Pythonクライアント用のリポジトリをクローンすると、Rubyクライアントのビルドと実行に必要なすべてのファイルも取得されます。 GridDBはRubyバージョン1.8とバージョン2.4をサポートします。 Rubyクライアントをビルドして実行する方法の詳細については、 griddb_clientページを参照してください。

PythonクライアントとしてRubyクライアントにも同様のルールが適用されます。 一つの違いは、Rubyクライアントライブラリを含む griddb_ruby_client.so ファイルを参照する 'griddb_ruby_client' をソースコードで単純に require

Ruby APIのリファレンスは、こちらにあります。

Connecting to your GridDB Cluster

ほとんどの場合、C/Python/Ruby APIのGridDBクラスタへの接続は、Java APIのGridDBへの接続に似ています。 Properties オブジェクトまたは同様のデータ構造を作成し、接続先のデータベースのホスト、ポート、および構成設定を入力します。 GridDBへの接続を表す Gridstore インスタンスを取得するために、これらのプロパティとの接続をフェッチするために StoreFactory オブジェクトを使用します。

C

#include "gridstore.h"
// (snip)
GSGridStore* gridstore;
const GSPropertyEntry properties[] = {
	{"notificationAddress",host},
	{"notificationPort",port},
	{"clusterName",clusterName},
	{"user",username},
	{"password",password}
};
size_t propertyCount = sizeof(properties) / sizeof(*properties);
gsGetGridStore(gsGetDefaultFactory(),properties,propertyCount,&gridstore);

Python

#!/usr/bin/python
import sys
import griddb_python_client
# (snip)
griddb = griddb_python_client
factory = griddb.StoreFactory.get_default()
try:
     gridstore = factory.get_store({
	"notificationAddress":host,
	"notificationPort": port,
	"clusterName":cluster,
	"user":user,
	"password":password
	})

Ruby

#!/usr/bin/ruby
$:.unshift File.dirname(__FILE__)
require 'griddb_ruby_client'
Griddb = Griddb_ruby_client
factory = Griddb::StoreFactory.get_default()
gridstore = factory.get_store({
                        "notificationAddress"=> ARGV[0],
                        "notificationPort"=> ARGV[1],
                        "clusterName"=> ARGV[2],
                        "user"=> ARGV[3],
                        "password"=> ARGV[4]
                      }) 

TQLクエリの発行

GridDBのC APIには、コンテナ内の行を照会および集約するためのさまざまな組み込み関数があります。ほとんどの場合、コンテナにクエリを作成して発行する最も簡単で簡単な方法は、TQL文字列を使用することです。 TQL は、GridDBのSQLクエリの簡略化された形式です。

クエリはTQL文字列として開始されます。 そこから、そのTQLをコンテナに発行することによってクエリオブジェクトが形成されます。このTQLを取得して結果の行セットを取得できます。 その結果得られる行セットを反復して、個々の行と列の値を取得できます。 集計結果も行セットから取得されます。 このフローは、C、Python、RubyのAPIとほぼ同じです。

TQL Query in C

他の多くのクエリ言語と同様に、GridDBのTQL を用いて、文字列の長さチェック、部分文字列スライシング、文字列認識のような
文字列操作が可能です。

Device nextDevice;
GSQuery* generalQuery;
GSRowSet* generalRowSet;

gsQuery(collection, \ 
"select * where (SUBSTRING(name,8,3)='r12' OR name LIKE '%LUE%R55_') and CHAR_LENGTH(name) > 4", \ &generalQuery);

gsFetch(generalQuery,GS_FALSE,&generalRowSet);
printf("Performing a String Operation on Collection ampCollection151 in TQL\n\n");
while(gsHasNextRow(generalRowSet)){
	GSChar timeString[GS_TIME_STRING_SIZE_MAX];
	gsGetNextRow(generalRowSet,&nextDevice); // Obtain  row object
	gsFormatTime(nextDevice.timestamp,timeString,sizeof(timeString)); // Format timestamp number

	printf("Row in collection ampMeter151: Name=%s",nextDevice.name);
	printf(" Amperage = %.2lf",nextDevice.amperage);
	printf(" Count = %d",nextDevice.count);
	printf(" Timestamp = %s\n",timeString);

アウトプット

TQLのコレクションampCollection151で文字列操作を実行する
Row in collection ampMeter151: Name=ampMeter12 Amperage = 1.45 \ 
Count = 3 Timestamp = 2017-09-15T18:13:52.710Z
Row in collection ampMeter151: Name=BLUESEAMETER555 Amperage = 2.43 \ 
Count = 5 Timestamp = 2017-09-15T18:13:52.710Z

Python

ジオメトリ固有のクエリと関数を除いて、TQLはPythonとRuby APIの両方でクエリを作成するために使用できます。 たとえば、PythonでTimeseries集計を実行する組み込み関数はありませんが、TQLで発行できます。 これには、タイムサンプリング、時間平均、および補間のような時間依存のクエリおよび関数が含まれます。

PythonでのTQL時間クエリ

query = timeseries.query(“select * where timestamp > TIMESTAMPADD(HOUR,NOW(),-12)”)
rowSet = query.fetch(False)
while rowSet.has_next():
	rowSet.get_next(row)
	time = row.get_field_as_timestamp(0)
	voltage = row.get_field_as_double(2)
	print(“Voltage at timestamp: {0} is {1} volts in Timeseries voltmeter2.”.format(time,voltage)

Output

Voltage at timestamp: 1505398224644 is 12.34 volts in Timeseries voltmeter2

Ruby

特定の集約関数をTQLの時間特有の関数と組み合わせることもできます。

Rubyでの集計TQLクエリ

update = false
timestamp = Griddb::Timestamp.current()
aggCommand = "select AVG(voltage) from voltmeter502 where timestamp > TIMESTAMPADD(MINUTE, \
TO_TIMESTAMP_MS(#{timestamp}), -10) AND timestamp < TIMESTAMPADD(MINUTE, \ 
TO_TIMESTAMP_MS(#{timestamp}), 10)"
aggQuery = timeseries.query(aggCommand) 
aggRowSet = aggQuery.fetch(update)
while aggRowSet.has_next()
      aggResult = aggRowSet.get_next_aggregation()
      print "Aggregation Result from voltmeter502: Average voltage = #{aggResult.get_double()}\n"
end

Output

Aggregation result from voltmeter502: Average voltage = 10.5

Inserting Collection into GridDB with C API

Cでは、静的スキーマまたは動的スキーマのいずれかを使用して、コンテナのスキーマを作成してGridDBに更新できます。 静的スキーマは、構造体バインディングの形式で提供されます。 動的スキーマは、コンテナを更新または挿入するために使用できる columnInfo および containerInfo オブジェクトの形式で提供されます。

C-Structを使用した静的スキーマの作成

typedef struct {
	const GSChar* name;
	double amperage;
	int count;
	GSTimestamp timestamp;
} Device; // Static Column Schema in GridDB C API

構造体をGridDB内のコンテナのスキーマとして使用するには、行キーを定義し、各フィールドに型を明示的に割り当てるための構造体バインディングを作成する必要があります 構造体。

Creating a Column Schema from a Struct

GS_STRUCT_BINDING(Device,
	GS_STRUCT_BINDING_KEY(name,GS_TYPE_STRING)
	GS_STRUCT_BINDING_ELEMENT(amperage,GS_TYPE_DOUBLE)
	GS_STRUCT_BINDING_ELEMENT(count,GS_TYPE_INTEGER)
	GS_STRUCT_BINDING_ELEMENT(timestamp,GS_TYPE_TIMESTAMP));

そこから構造体がバインドされ、行スキーマになったら、コンテナで使用することができます。

コンテナへの構造体バインディングスキーマの挿入

GSCollection* collection;
gsPutCollection(gridstore,"ampCollection151",GS_GET_STRUCT_BINDING(Device),NULL,GS_FALSE,&collection);

そこから Device 構造体をオブジェクトとして使用して行をフェッチして挿入できます。

Inserting a Struct as a GSRow

Device insertionDevice;
insertionDevice.name = "ampMeter12";
insertionDevice.amperage = 1.45;
insertionDevice.count = 3;
insertionDevice.timestamp = gsCurrentTime();

Having a Struct Represent a Row Schema

Device device;
while(gsHasNextRow(rowSet)){
	gsGetNextRow(rowSet,&device);
	GSChar timeStr[GS_TIME_STRING_SIZE_MAX];
	gsFormatTime(device.timestamp,timeStr,sizeof(timeStr));
	printf("Device in ampCollection151: ");
	printf("name=%s",device.name);
	printf(" amperage=%.2lf",device.amperage);
	printf(" count=%d",device.count);
	printf(" timestamp=%s\n",timeStr);

アウトプット

Device in ampCollection151: name=ampMeter12 amperage=1.45 count=3 \ 
timestamp=2017-09-14T20:05:06.285Z

Python

PythonとRubyの両方で、スキーマを作成してコンテナを挿入するアプローチは、C APIで示した動的アプローチに似ています。 列とコンテナに名前を付け、列の種類を定義するだけです。 それらがTimeSeriesかコレクションであるかどうか、およびそれらが持つべき索引を決定します。 使用可能な列の種類は、GridDBドキュメント および APIリファレンスを参照してください。

Pythonで時系列を挿入する

timeseries = gridstore.put_container("voltmeter2",[
		("timestamp",griddb.GS_TYPE_TIMESTAMP),
		("active",griddb.GS_TYPE_BOOL),
		("voltage",griddb.GS_TYPE_DOUBLE)
		],griddb.GS_CONTAINER_TIME_SERIES)

Pythonでは、変数の型を明示的に記述する必要がないためです。 行フィールドは、より流動的に挿入して取り込むことができます。 知る必要があるのは、列のタイプとインデックスのみです。 作成された行オブジェクトは、それが基になっているコンテナによって設定された行スキーマを持ちます。 行を挿入するには以下のようにします。

Pythonで行を挿入する

## Create rows and set all Row Fields
insertionRow = timeseries.create_row()
insertionRow.set_field_by_timestamp(0,griddb.Timestamp_add_time(griddb.Timestamp_current(),-6, \ 
 griddb.GS_TIME_UNIT_HOUR))

insertionRow.set_field_by_bool(1,True)
insertionRow.set_field_by_double(2, 12.34)

## Insert Row into Timeseries
timeseries.put_row(insertionRow)

Ruby

同じプロセスを使用して、Rubyで Python でスキーマやコンテナを作成します。 単に列に名前を付けて型を設定し、コンテナ、コレクション、またはtimeseriesのタイプを設定します。

Rubyにコレクションを挿入する

Collection = gridstore.put_container(“collection121”,[
{“name”=>Grid db::GS_TYPE_STRING},
{“status”=>Grid db::GS_TYPE_BOOL},
{“count”=>Grid db::GS_TYPE_LONG},
{“lob”=>Grid db::GS_TYPE_BLOB }
],CONTAINER_TYPE_COLLECTION)

そこから行は、Pythonと同じ方法でフェッチ、挿入、更新できます。

Rubyでの行の取得と更新

rowSet.get_next(row)
name = row.get_field_as_string(0)
status = row.get_field_as_bool(1)
count = row.get_field_as_long(2) + 1
lob = row.get_field_as_blob(3)
print "Row in Collection: collection121, Person: name=#{name} status=#{status} count=#{count} lob="
p lob.unpack("U*")
row.set_field_as_long(2,count)
rowSet.update_current(row)

アウトプット

Row in Collection: collection121, Person: name=secondRow status=false \
 count=6 lob=[65, 66, 67, 68, 69, 70, 71, 72, 73, 74]

上記の例からわかるように、GridDBとのやりとりは多くの言語で理解され使用されています。 これは、GridDBがどのように使いやすいAPIを介して幅広いサポートを提供するかを示しています。さまざまなアプリケーションを作成するベースとして使用できます。

Source Code

ここに表示されているすべてのコードスニペットは、サンプルプログラムから入手でき、以下のリンクからダウンロードして実行できます。 Ruby、Python、C のサンプルコードがそれぞれ一つづつあります。
api_samples.tar.gz

ブログの内容について疑問や質問がある場合は Q&A サイトである Stack Overflow に質問を投稿しましょう。 GridDB 開発者やエンジニアから速やかな回答が得られるようにするためにも "griddb" タグをつけることをお忘れなく。 https://stackoverflow.com/questions/ask?tags=griddb

2 Comments

  1. […] システムにGo clientを構築するには、 GridDB C clientを構築し、 インストールする必要があります。 C clientの設定とテストの方法については、このブログ記事を参照してください。 […]

Leave a Reply

Your email address will not be published. Required fields are marked *