GridDB Cloud v2.0が正式リリースされ、無料の新しいティアが追加され、世界中で正式に利用可能になりました。
このクイックスタートガイドでは、IoTデータをGridDB Cloudに挿入する方法、接続の有効性をテストする方法、および基本的なCRUDコマンド(Create、Read、Update、Delete)を学習します。
Contents
準備
GridDB Cloudの使い方を説明する前に、いくつかの基本的な準備について確認しておきましょう。
GridDB Cloud無料プランに申し込む
GridDB Cloud Freeインスタンスの登録をご希望の場合は、以下のリンクから登録いただけます。https://form.ict-toshiba.jp/download_form_griddb_cloud_freeplan_e.
GitHub リポジトリのクローン
これらのサンプルコードを実行するには、GitHub リポジトリをクローンしてください。
$ git clone https://github.com/griddbnet/Blogs.git --branch cloud-quick-start-worldwide
ソースコードの概要
GridDB Cloud への導入をスムーズに進めるための基本的な HTTP リクエストを用意しています。これらのリクエストは、CLI スクリプト(bash/
ディレクトリ内の bash とも呼ばれる)、node.js、python の 3 つの異なるプログラミングインターフェースで共有されています。
例えば、最初のコマンドは、お客様のマシンとクラウド間の接続が確立できることを確認するためのものです。これを行うには、bash(cURLを使用)を使用して特定のエンドポイントへのHTTPリクエストを実行し、その後、node.js/pythonスクリプトを使用します。
サンプルコードの実行設定
HTTPリクエストに適切な接続情報を設定するには、env.exampleファイル(上記のセクションで共有したGitHubリポジトリから)をコピーし、.env
に名前を変更します。 個人用の変数(GridDB Cloud Web APIエンドポイントや、ユーザー名/パスワードの組み合わせをbase64でエンコードしたものなど)を入力する必要があります。
適切な認証情報を取得するには、ユーザー名とパスワードの組み合わせをコロンで区切ってベース64エンコードする必要があります。例えば、admin:adminはYWRtaW46YWRtaW4=
となります。これらの値は、次のウェブサイトを使用してエンコードできます。https://www.base64encode.org/
WEBAPIのURLは、GridDBダッシュボードのメインページでご確認いただけます。
.env
ファイルの例を以下に示します。
export GRIDDB_WEBAPI_URL="https://cloud51e32re97.griddb.com:443/griddb/v2/gs_clustermfcloud5314927/dbs/ZV8YUerterlQ8"
export USER_PASS="TTAxZ2FYMFrewwerZrRy1pc3JrerehZWw6avdfcvxXNyYWVs"
次に、$ source .env
を実行してこれらの値を環境に読み込み、CLIからこれらのスクリプトを実行できるようにします。
GridDB Cloudの最初のステップ
GridDB CloudインスタンスはHTTPリクエストで通信できます。GridDBとやりとりするために必要なすべてのアクションは、異なるURL、パラメータ、メソッド、ペイロードボディを持つHTTPリクエストを生成し、発行する必要があります。
1. IPアドレスのホワイトリスト化
まだ行っていない場合は、GridDB Cloud Managementダッシュボードのネットワーク設定で、お客様のパブリックIPアドレスをホワイトリストに登録してください。お客様のIPアドレスは、Google検索で「What is my IP Address?」と検索すると確認できます。
または、こちらにアクセスすることもできます。https://whatismyipaddress.com/
ネットワークタブに移動し、お客様のIPアドレスを追加します。
注:CIDR範囲は互換性があるので、ご存知の場合はご自由に追加してください。
2. GridDBユーザーの追加とデータベースへのアクセス権付与
次に、新しいGridDBユーザーを作成します。サイドパネルからGridDBユーザーというアイコンをクリックします。このページから、「CREATE DATABASE USER」をクリックします。このユーザー名とパスワードは、Web APIを使用する際に、すべてのHTTPリクエストにBasic認証ヘッダーとして付加されます。
新しいユーザーを作成したら、データベースへのアクセス権限も付与する必要があります。GridDB Usersページのユーザー一覧からユーザーをクリックし、このページからデータベースへのアクセス権限(READまたはALL)を付与します。これで、実際のHTTPリクエストの作成に進むことができます。
3. GridDB 接続の確認
まずは、GridDB Cloud インスタンスに接続できるか確認します。.
env ファイルが作成され、準備ができている場合、次のコマンドを使用して、環境に変数が読み込まれていることを確認できます。 $ source .env
。
次に、bash スクリプトを実行します。
ステータスコードが200であれば、接続は成功しています。ステータスコードが403 Forbiddenの場合、おそらくネットワークタブでマシンのIPアドレスがホワイトリスト化されていないことが原因です。同様に、401 Unauthorizedというコードが返された場合、おそらく認証情報が間違っていることが原因です。base64にエンコードされた「user:pass」を使用していることを確認してください。
接続URLの確認 エンドポイント
Web APIでは、base url
を使用します。このURLを使用して、リクエストを構築していきます。base urlは次のようになります。 f
https://cloud<number>.griddb.com/griddb/v2/<clusterName>/dbs/<database name>
接続が存在することを確認するには、ベース URL に /checkConnection
を追加します。 サーバーにデータを送信しないため、HTTP メソッドとして GET
を使用します。
最後に、HTTP リクエストのヘッダーに basic authentication
を追加する必要があります。 これには、base64 にエンコードしたユーザー名とパスワードを含める必要があります。 以上の手順を踏まえて、最終的な結果は以下のようになります。
https://cloud51ergege97.griddb.com/griddb/v2/gs_clustermfcloud51fgerge97/dbs/B2vderewDSJy/checkConnection
この URL を任意の数のプログラミング言語で使用して、データベースと通信することができます。
また、注として、この記事の例には URL や認証情報がハードコードされていますが、ソースコード(上記リンク)では環境変数を使用しています。
cURL リクエスト
cURL との接続を確認するには、以下のコマンド(check_connection.sh
)を使用します。
curl -i --location 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/checkConnection' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
これは GET
リクエストなので、比較的単純であり、認証ヘッダーを追加するだけで済みます。これを実行すると、HTTPレスポンスコード200が返されるはずです。
Python リクエスト
以下は、同じリクエストをPythonで記述したものです。
# check_connection.py
import requests
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/checkConnection"
payload = {}
headers = {
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.status_code)
node.js リクエスト
//checkConnection.js
const request = require('request');
const options = {
'method': 'GET',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/checkConnection',
'headers': {
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log("Response Status Code: ", response.statusCode);
});
4. 最初のタイムシリーズとコレクションコンテナの作成
接続が確立されたので、最初のコンテナ(コレクションと時系列の両方)を作成することができます。これらはリレーショナル・テーブルに似ています。 これについての詳細は、こちらを参照してください:GridDBデータモデル。
URLの接尾辞は次のようになります。 /containers
。 このリクエストは、大量のデータが必要になる場合があり、また範囲も広くなる可能性があるため、HTTPメソッドとしてPOST
が必要です。
リクエストのボディには、コンテナ名、コンテナタイプ、rowkeyの有無(ブール値)、スキーマが必要です。 まず、HTTPリクエストのコンテキスト外の構造を見てから、リクエストボディ内に送信します。 また、以下のように、JSON形式のデータペイロードを送信していることを示すヘッダーを含める必要があります。 'Content-Type: application/json'
タイムシリーズコンテナ
まず、タイムシリーズコンテナを作成します。ここでは、コンテナタイプをTIME_SERIESとして選択し、最初の列はタイムスタンプ型であることがわかります。行キーのセクションもありますが、タイムシリーズコンテナでは行キーは常にデフォルトでタイムスタンプであるため、これはオプションです。
{
"container_name": "device1",
"container_type": "TIME_SERIES",
"rowkey": true,
"columns": [
{
"name": "ts",
"type": "TIMESTAMP"
},
{
"name": "co",
"type": "DOUBLE"
},
{
"name": "humidity",
"type": "DOUBLE"
},
{
"name": "light",
"type": "BOOL"
},
{
"name": "lpg",
"type": "DOUBLE"
},
{
"name": "motion",
"type": "BOOL"
},
{
"name": "smoke",
"type": "DOUBLE"
},
{
"name": "temp",
"type": "DOUBLE"
}
]
}
これで、リクエストを行う際にこれをボディに追加するだけで、新しいコンテナが作成されるはずです。成功すれば、ステータスコードとして 201 (Created)
が返されるはずです。
#create_container.sh
curl -i -X POST --location 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '{
"container_name": "device1",
"container_type": "TIME_SERIES",
"rowkey": true,
"columns": [
{
"name": "ts",
"type": "TIMESTAMP"
},
{
"name": "co",
"type": "DOUBLE"
},
{
"name": "humidity",
"type": "DOUBLE"
},
{
"name": "light",
"type": "BOOL"
},
{
"name": "lpg",
"type": "DOUBLE"
},
{
"name": "motion",
"type": "BOOL"
},
{
"name": "smoke",
"type": "DOUBLE"
},
{
"name": "temp",
"type": "DOUBLE"
}
]
}'
Python
#create_container.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers"
payload = json.dumps({
"container_name": "device1",
"container_type": "TIME_SERIES",
"rowkey": True,
"columns": [
{
"name": "ts",
"type": "TIMESTAMP"
},
{
"name": "co",
"type": "DOUBLE"
},
{
"name": "humidity",
"type": "DOUBLE"
},
{
"name": "light",
"type": "BOOL"
},
{
"name": "lpg",
"type": "DOUBLE"
},
{
"name": "motion",
"type": "BOOL"
},
{
"name": "smoke",
"type": "DOUBLE"
},
{
"name": "temp",
"type": "DOUBLE"
}
]
})
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.status_code)
node.js
//createContainer.js
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify({
"container_name": "device1",
"container_type": "TIME_SERIES",
"rowkey": true,
"columns": [
{
"name": "ts",
"type": "TIMESTAMP"
},
{
"name": "co",
"type": "DOUBLE"
},
{
"name": "humidity",
"type": "DOUBLE"
},
{
"name": "light",
"type": "BOOL"
},
{
"name": "lpg",
"type": "DOUBLE"
},
{
"name": "motion",
"type": "BOOL"
},
{
"name": "smoke",
"type": "DOUBLE"
},
{
"name": "temp",
"type": "DOUBLE"
}
]
})
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log("Response Status Code: ", response.statusCode);
});
Collection Container
それではコレクションコンテナを作成してみましょう。これらのコンテナは時系列カラムを必要としませんが(使用することはできます)、rowkeyをtrueに設定する必要もありません。以下に例を示します。
cURL
#create_collection.sh
curl -i -X POST --location 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '{
"container_name": "deviceMaster",
"container_type": "COLLECTION",
"rowkey": true,
"columns": [
{
"name": "equipment",
"type": "STRING"
},
{
"name": "equipmentID",
"type": "STRING"
},
{
"name": "location",
"type": "STRING"
},
{
"name": "serialNumber",
"type": "STRING"
},
{
"name": "lastInspection",
"type": "TIMESTAMP"
},
{
"name": "information",
"type": "STRING"
}
]
}'
Python
#create_collection.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers"
payload = json.dumps({
"container_name": "deviceMaster",
"container_type": "COLLECTION",
"rowkey": True,
"columns": [
{
"name": "equipment",
"type": "STRING"
},
{
"name": "equipmentID",
"type": "STRING"
},
{
"name": "location",
"type": "STRING"
},
{
"name": "serialNumber",
"type": "STRING"
},
{
"name": "lastInspection",
"type": "TIMESTAMP"
},
{
"name": "information",
"type": "STRING"
}
]
})
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.status_code)
node.js
//createCollection.js
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify({
"container_name": "deviceMaster",
"container_type": "COLLECTION",
"rowkey": true,
"columns": [
{
"name": "equipment",
"type": "STRING"
},
{
"name": "equipmentID",
"type": "STRING"
},
{
"name": "location",
"type": "STRING"
},
{
"name": "serialNumber",
"type": "STRING"
},
{
"name": "lastInspection",
"type": "TIMESTAMP"
},
{
"name": "information",
"type": "STRING"
}
]
})
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.statusCode);
});
5. CRUD with GridDB Cloud (Create, Read, Update, Delete)
5. CRUD with GridDB Cloud (Create, Read, Update, Delete)
次に、Create、Read、Update、Deleteのコマンドについて確認します。
データの行の追加(作成
これまでにいくつかのコンテナを作成してきましたが、さらに、コンテナに追加するデータの行を作成します。データの行はコンテナ内に直接追加することができます。URLのサフィックス:/containers/:container/rows
[
["2024-01-09T10:00:01.234Z", 0.003551, 50.0, false, 0.00754352, false, 0.0232432, 21.6],
["2024-01-09T11:00:01.234Z", 0.303551, 60.0, false, 0.00754352, true, 0.1232432, 25.3],
["2024-01-09T12:00:01.234Z", 0.603411, 70.0, true, 0.00754352, true, 0.4232432, 41.5]
]
もちろん、行のスキーマがコンテナのスキーマと一致していることも確認する必要があります。一致していない場合は、エラーメッセージとステータスコード 400 (Bad Request)
が表示されます。
cURL
https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers
#add_rows.sh
curl --location --request PUT 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/device1/rows' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '[
["2024-01-09T10:00:01.234Z", 0.003551, 50.0, false, 0.00754352, false, 0.0232432, 21.6],
["2024-01-09T11:00:01.234Z", 0.303551, 60.0, false, 0.00754352, true, 0.1232432, 25.3],
["2024-01-09T12:00:01.234Z", 0.603411, 70.0, true, 0.00754352, true, 0.4232432, 41.5]
]'
Python
#add_rows.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/device1/rows"
payload = json.dumps([
[
"2024-01-09T10:00:01.234Z",
0.003551,
50,
False,
0.00754352,
False,
0.0232432,
21.6
],
[
"2024-01-09T11:00:01.234Z",
0.303551,
60,
False,
0.00754352,
True,
0.1232432,
25.3
],
[
"2024-01-09T12:00:01.234Z",
0.603411,
70,
True,
0.00754352,
True,
0.4232432,
41.5
]
])
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("PUT", url, headers=headers, data=payload)
print(response.text)
node.js
//addRows.js
var request = require('request');
var options = {
'method': 'PUT',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/device1/rows',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify([
[
"2024-01-09T10:00:01.234Z",
0.003551,
50,
false,
0.00754352,
false,
0.0232432,
21.6
],
[
"2024-01-09T11:00:01.234Z",
0.303551,
60,
false,
0.00754352,
true,
0.1232432,
25.3
],
[
"2024-01-09T12:00:01.234Z",
0.603411,
70,
true,
0.00754352,
true,
0.4232432,
41.5
]
])
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
コンテナの問い合わせ(読み取り)
コンテナに書き込みを行った後、コンテナから読み込みを行う必要があります。URLの接尾辞はこれまでとまったく同じです。ただし、今回は POST
メソッドのリクエストを使用します。これらのリクエストでサーバーが期待するデータは、返される行データです。例えば、行の制限、オフセット、任意の条件、ソート方法などを選択できます。以下がそのボディの例です。
{
"offset" : 0,
"limit" : 100,
"condition" : "temp >= 30",
"sort" : "temp desc"
}
このリクエストを行う際の注意点は、POST
リクエストであるため、リクエストのボディに何らかのデータを送信する必要があるということです。上記のパラメータのいずれでもかまいませんが、リミットを含めるのが最も簡単なオプションであり、サーバーの負荷を軽減できるという利点もあります。
成功した場合、ステータスコードが 200 (OK)
で、リクエストしたデータを含むボディが返されます。
#query_container.sh
{
"columns": [
{
"name": "ts",
"type": "TIMESTAMP",
"timePrecision": "MILLISECOND"
},
{
"name": "co",
"type": "DOUBLE"
},
{
"name": "humidity",
"type": "DOUBLE"
},
{
"name": "light",
"type": "BOOL"
},
{
"name": "lpg",
"type": "DOUBLE"
},
{
"name": "motion",
"type": "BOOL"
},
{
"name": "smoke",
"type": "DOUBLE"
},
{
"name": "temp",
"type": "DOUBLE"
}
],
"rows": [
[
"2024-01-09T12:00:01.234Z",
0.603411,
70.0,
true,
0.00754352,
true,
0.4232432,
41.5
]
],
"offset": 0,
"limit": 100,
"total": 1
}
cURL
curl -i -X POST --location 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/device1/rows' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '{
"offset" : 0,
"limit" : 100,
"condition" : "temp >= 30",
"sort" : "temp desc"
}'
Python
#query_container.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/device1/rows"
payload = json.dumps({
"offset": 0,
"limit": 100,
"condition": "temp >= 30",
"sort": "temp desc"
})
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
nodejs
//queryContainer.js
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/device1/rows',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify({
"offset": 0,
"limit": 100,
"condition": "temp >= 30",
"sort": "temp desc"
})
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
行の更新(更新
更新に対応するためには、データの行を追加することも更新とみなすことができますが、行を直接更新することもできます(コンテナにrowkeyがある場合)。動作としては、rowkeyがtrueに設定されたコンテナにデータの行をプッシュし、コンテナにすでに存在するrowkeyを持つデータの行を送信すると、プッシュされた新しい情報でその行が更新されます。
deviceMaster
コレクションコンテナに一度データをプッシュしてデータを追加し、その後もう一度プッシュして行を更新してみましょう。
データの行を作成してみましょう。
[
["device1", "01", "CA", "23412", "2023-12-15T10:45:00.032Z", "working"]
]
それでは、HTTPリクエストを作成しましょう。
cURL
#update_collection.sh
curl -i --location --request PUT 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/deviceMaster/rows' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '[
["device1", "01", "CA", "23412", "2023-12-15T10:45:00.032Z", "working"]
]'
Python
#update_collection.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/deviceMaster/rows"
payload = json.dumps([
[
"device1",
"01",
"CA",
"23412",
"2023-12-15T10:45:00.032Z",
"working"
]
])
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("PUT", url, headers=headers, data=payload)
print(response.text)
node.js
//updateCollection.js
var request = require('request');
var options = {
'method': 'PUT',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/deviceMaster/rows',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify([
[
"device1",
"01",
"CA",
"23412",
"2023-12-15T10:45:00.032Z",
"working"
]
])
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
1行の更新
データが入力された状態で、最初の値(rowkey、デバイス名)以外の値を変更すると、コンテナ内の行はそのまま維持され、そのデバイスのメタデータが更新されます。
curl -i --location --request PUT 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/deviceMaster/rows' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '[
["device1", "01", "NY", "23412", "2023-12-20T10:45:00.032Z", "working"]
]'
ここでは、場所と最後の検査時刻を変更しています。ダッシュボードを見ると、値が更新されていることが確認できます。
行の削除(削除)
適切な HTTP メソッド(削除)を使用し、有効な行キーとコンテナをサーバーに送信するだけで、行を削除することができます。deviceMasterの唯一の行を削除してみましょう。
リクエストのボディは以下のようになります。この中に複数の行キーを追加して、複数の行を一度に削除することもできます。
[
"device1"
]
cURL
#delete_row.sh
curl -v --location --request DELETE 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/deviceMaster/rows' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '[
"device1"
]'
Python
#delete_row.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/deviceMaster/rows"
payload = json.dumps([
"device1"
])
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("DELETE", url, headers=headers, data=payload)
print(response.status_code)
node.js
//deleteRow.js
var request = require('request');
var options = {
'method': 'DELETE',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/deviceMaster/rows',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify([
"device1"
])
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.statusCode);
});
時系列コンテナの行の削除
時系列コンテナの行を削除することもできます。前述の通り、タイムスタンプは常に時系列コンテナの行キーとなりますので、ここではタイムスタンプを追加するだけで、それらの行が削除されます。
#delete_container.sh
curl --location --request DELETE 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers/device1/rows' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '[
"2024-01-09T10:00:01.234Z",
"2024-01-09T12:00:01.234Z"
]'
TQL
次に、TQLクエリを実行してみましょう。TQLはGridDBの特別なクエリ言語です。
簡単なクエリを実行してみましょう。まず、URLは次のようになります。
ベースURL + /tql
リクエストの本文には、コンテナ名とクエリ文を続けます。複数のコンテナを一度にクエリすることもできます。
[
{"name" : "deviceMaster", "stmt" : "select * limit 100", "columns" : null},
{"name" : "device1", "stmt" : "select * where temp>=24", "columns" : ["temp", "co"]},
]
And this is the response of the above query:
[
{
"columns": [
{
"name": "equipment",
"type": "STRING"
},
{
"name": "equipmentID",
"type": "STRING"
},
{
"name": "location",
"type": "STRING"
},
{
"name": "serialNumber",
"type": "STRING"
},
{
"name": "lastInspection",
"type": "TIMESTAMP",
"timePrecision": "MILLISECOND"
},
{
"name": "information",
"type": "STRING"
}
],
"results": [
[
"device1",
"01",
"NY",
"23412",
"2023-12-20T10:45:00.032Z",
"working"
]
],
"offset": 0,
"limit": 100,
"total": 1,
"responseSizeByte": 31
},
{
"columns": [
{
"name": "temp",
"type": "DOUBLE"
},
{
"name": "co",
"type": "DOUBLE"
}
],
"results": [
[
25.3,
0.303551
],
[
41.5,
0.603411
]
],
"offset": 0,
"limit": 1000000,
"total": 2,
"responseSizeByte": 32
}
]
cURL
#tql.sh
curl -i -X POST --location 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/tql' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '
[
{"name" : "deviceMaster", "stmt" : "select * limit 100", "columns" : null},
{"name" : "device1", "stmt" : "select * where temp>=24", "columns" : ["temp", "co"]}
]
'
Python
#tql.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/tql"
payload = json.dumps([
{
"name": "deviceMaster",
"stmt": "select * limit 100",
"columns": None
},
{
"name": "device1",
"stmt": "select * where temp>=24",
"columns": [
"temp",
"co"
]
}
])
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
node.js
//tql.js
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/tql',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify([
{
"name": "deviceMaster",
"stmt": "select * limit 100",
"columns": null
},
{
"name": "device1",
"stmt": "select * where temp>=24",
"columns": [
"temp",
"co"
]
}
])
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
SQL
TQLに加えて、GridDBとGridDB CloudにはSQL機能もあります。ただし、GridDB CloudのSQL機能は、結果の読み取り(SELECT)と一部の行の更新(UPDATE)のみに限定されています。
SQL SELECT
base url + /sql
[
{"type" : "sql-select", "stmt" : "SELECT * FROM deviceMaster"},
{"type" : "sql-select", "stmt" : "SELECT temp, co FROM device1 WHERE temp>=24"}
]
TQLと非常に似ていますが、クエリ自体からコンテナ名を呼び出す点が「通常の」SQLステートメントと異なります。
以下がレスポンスボディです:
[
{
"columns": [
{
"name": "equipment",
"type": "STRING"
},
{
"name": "equipmentID",
"type": "STRING"
},
{
"name": "location",
"type": "STRING"
},
{
"name": "serialNumber",
"type": "STRING"
},
{
"name": "lastInspection",
"type": "TIMESTAMP",
"timePrecision": "MILLISECOND"
},
{
"name": "information",
"type": "STRING"
}
],
"results": [
[
"device1",
"01",
"CA",
"23412",
"2023-12-15T10:45:00.032Z",
"working"
]
],
"responseSizeByte": 47
},
{
"columns": [
{
"name": "temp",
"type": "DOUBLE"
},
{
"name": "co",
"type": "DOUBLE"
}
],
"results": [
[
25.3,
0.303551
],
[
41.5,
0.603411
]
],
"responseSizeByte": 32
}
]
cURL
#sql_select.sh
curl -i -X POST --location 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '[
{"type" : "sql-select", "stmt" : "SELECT * FROM deviceMaster"},
{"type" : "sql-select", "stmt" : "SELECT temp, co FROM device1 WHERE temp>=24"}
]
'
Python
#sql_select.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql"
payload = json.dumps([
{
"type": "sql-select",
"stmt": "SELECT * FROM deviceMaster"
},
{
"type": "sql-select",
"stmt": "SELECT temp, co FROM device1 WHERE temp>=24"
}
])
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
node.js
//sqlSelect.js
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify([
{
"type": "sql-select",
"stmt": "SELECT * FROM deviceMaster"
},
{
"type": "sql-select",
"stmt": "SELECT temp, co FROM device1 WHERE temp>=24"
}
])
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
SQL SELECT GROUP BY RANGE
SQL Selectを使用しているため、GridDBのGroup By Rangeも使用できます。詳しくは、こちらを参照してください:GridDBのGroup By Range機能の紹介。
クエリを作成し、時間単位でグループ化します。
[
{"type" : "sql-select", "stmt" : "SELECT temp, co FROM device1 WHERE ts > TO_TIMESTAMP_MS(1594515625984) AND ts < TO_TIMESTAMP_MS(1595040779336) GROUP BY RANGE (ts) EVERY (1, HOUR)"}
]
cURL
#sql_select_groupby.sh
curl -i --location 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '[
{"type" : "sql-select", "stmt" : "SELECT temp, co FROM device1 WHERE ts > TO_TIMESTAMP_MS(1594515625984) AND ts < TO_TIMESTAMP_MS(1595040779336) GROUP BY RANGE (ts) EVERY (1, HOUR)"}
]
'
Python
# sql_select_groupby.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql"
payload = json.dumps([
{
"type": "sql-select",
"stmt": "SELECT temp, co FROM device1 WHERE ts > TO_TIMESTAMP_MS(1594515625984) AND ts < TO_TIMESTAMP_MS(1595040779336) GROUP BY RANGE (ts) EVERY (1, HOUR)"
}
])
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
SQL 挿入
ベース URL は SELECT と同じですが、’update’ を追加する必要があります
ベース URL + /:cluster/dbs/:database/sql/update
[
{"stmt" : "insert into deviceMaster(equipment, equipmentID, location, serialNumber, lastInspection, information) values('device2', '02', 'MA', '34412', TIMESTAMP('2023-12-21T10:45:00.032Z'), 'working')"}
]
cURL
#sql_insert.sh
curl -i -X POST --location 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql/update' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '[
{"stmt" : "insert into deviceMaster(equipment, equipmentID, location, serialNumber, lastInspection, information) values('\''device2'\'', '\''02'\'', '\''MA'\'', '\''34412'\'', TIMESTAMP('\''2023-12-21T10:45:00.032Z'\''), '\''working'\'')"}
]'
Python
#sql_insert.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql/update"
payload = json.dumps([
{
"stmt": "insert into deviceMaster(equipment, equipmentID, location, serialNumber, lastInspection, information) values('device2', '02', 'MA', '34412', TIMESTAMP('2023-12-21T10:45:00.032Z'), 'working')"
}
])
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
node.js
//sqlInsert.js
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql/update',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify([
{
"stmt": "insert into deviceMaster(equipment, equipmentID, location, serialNumber, lastInspection, information) values('device2', '02', 'MA', '34412', TIMESTAMP('2023-12-21T10:45:00.032Z'), 'working')"
}
])
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
SQL 更新
ベースURLは上記と同じですが、’update’を追加する必要があります。 base url + /sql/update
[
{"stmt" : "update deviceMaster set location = 'LA' where equipmentID = '01'"}
]
This command allows you to Update, similar to the NoSQL method described above. We can both update existing rows, or update containers to add new rows.
cURL
#sql_update.sh
curl -i -X POST --location 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql/update' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '[
{"stmt" : "update deviceMaster set location = '\''LA'\'' where equipmentID = '\''01'\''"}
]'
Python
#sql_update.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql/update"
payload = json.dumps([
{
"stmt": "update deviceMaster set location = 'LA' where equipmentID = '01'"
}
])
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
node.js
//sqlUpdate.js
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/sql/update',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify([
{
"stmt": "update deviceMaster set location = 'LA' where equipmentID = '01'"
}
])
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
コンテナのドロップ
コンテナのドロップも可能です。
ベースURL + /containers
リクエストのボディには、1つまたは複数のコンテナ名を含めることができます。リクエストを送信すると、コンテナがドロップされます。
[
"deviceMaster"
]
成功した場合、ステータスコードとして「204 (No Content)」が返されます。
cURL
#delete_container.sh
curl -i --location --request DELETE 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs' \
--data '[
"deviceMaster"
]'
Python
#delete_container.py
import requests
import json
url = "https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers"
payload = json.dumps([
"deviceMaster"
])
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
'User-Agent': 'PostmanRuntime/7.29.0'
}
response = requests.request("DELETE", url, headers=headers, data=payload)
print(response.status_code)
node.js
//deleteContainer.js
var request = require('request');
var options = {
'method': 'DELETE',
'url': 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/containers',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs'
},
body: JSON.stringify([
"deviceMaster"
])
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.statusCode);
});
6. サンプルIoTデータの取り込み
次に、CSVデータの取り込みを見てみましょう。KaggleからIoTデータを取得します。生のファイルは、こちらのウェブサイトからダウンロードできます:https://www.kaggle.com/datasets/garystafford/environmental-sensor-data-132k。
以下は、データを当社の device2
コンテナに取り込むために使用できるPythonスクリプトです。
すでに device1
コンテナを作成済みですが、同じスキーマを使用して、新たに device2
というコンテナを作成します。
#data_ingest.py
import pandas as pd
import numpy as np
import json
import requests
from datetime import datetime as dt, timezone
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
"User-Agent":"PostmanRuntime/7.29.0"
}
base_url = 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/'
data_obj = {
"container_name": "device1",
"container_type": "TIME_SERIES",
"rowkey": True,
"columns": []
}
input_variables = [
"ts","co","humidity","light","lpg","motion","smoke","temp"
]
data_types = [
"TIMESTAMP", "DOUBLE", "DOUBLE", "BOOL", "DOUBLE", "BOOL", "DOUBLE","DOUBLE"
]
for variable, data_type in zip(input_variables, data_types):
column = {
"name": variable,
"type": data_type
}
data_obj["columns"].append(column)
#Create Container
url = base_url + 'containers'
r = requests.post(url, json = data_obj, headers = headers)
これらはすべて非常に単純明快です。
次に、実際にデータをインポートしてみましょう。そのためには、pandas Pythonライブラリを使用して、インポート対象のCSVファイルを読み込みます。このライブラリを使用すると、CSVデータの特定の列を簡単にターゲットとして指定し、変換してインポートすることが可能になります。
最後に、CSVファイルは8メガバイトを超えるため、データをいくつかの部分に分割してクラウドに送信します。データのダウンロードはこちらから: https://www.kaggle.com/datasets/garystafford/environmental-sensor-data-132k
以下が残りのコードです。
iot_data = pd.read_csv('iot_telemetry_data.csv')
#2023-12-15T10:25:00.253Z
iot_data['ts'] = pd.to_datetime(iot_data['ts'], unit='s').dt.strftime("%Y-%m-%dT%I:%M:%S.%fZ")
print(iot_data["ts"])
iot_data = iot_data.drop('device', axis=1)
#print(iot_data.dtypes)
iot_subsets = np.array_split(iot_data, 20)
#Ingest Data
url = base_url + 'containers/device1/rows'
for subset in iot_subsets:
#Convert the data in the dataframe to the JSON format
iot_subsets_json = subset.to_json(orient='values')
request_body_subset = iot_subsets_json
r = requests.put(url, data=request_body_subset, headers=headers)
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
print('_______________',r.text,'___________')
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
if r.status_code > 299:
print(r.status_code)
break
else:
print('Success for chunk')
スクリプトを実行すると、アップロードされた各チャンクについて、更新が成功した行数とともに、成功した旨のメッセージが表示されるはずです。完了したら、HTTPリクエストクエリまたはポータルを使用して、device1
を確認できます。
7. データ分析の実行
最後に、簡単なPython分析を行ってみましょう。IoTデータにクエリを実行し、そのデータを使用して、データの簡単な分析とチャート化を行います。
#data_analysis.py
import pandas as pd
import numpy as np
import requests
import plotly.express as px
from IPython.display import Image
# ts object
# co float64
# humidity float64
# light bool
# lpg float64
# motion bool
# smoke float64
# temp float64
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic TTAxMU1sd0MxYS1pc3ewrwqJhZWw6aXNyYWVs',
"User-Agent":"PostmanRuntime/7.29.0"
}
base_url = 'https://cloud5197422.griddb.com/griddb/v2/gs_clustermfcloud5197422/dbs/B2vdfewfwDSJy/'
sql_query1 = (f"""SELECT * from device1 WHERE co < 0.0019050147565559603 """)
url = base_url + 'sql'
request_body = '[{"type":"sql-select", "stmt":"'+sql_query1+'"}]'
data_req1 = requests.post(url, data=request_body, headers=headers)
myJson = data_req1.json()
dataset = pd.DataFrame(myJson[0]["results"],columns=[myJson[0]["columns"][0]["name"],myJson[0]["columns"][1]["name"],myJson[0]["columns"][2]["name"],
myJson[0]["columns"][3]["name"],myJson[0]["columns"][4]["name"],myJson[0]["columns"][5]["name"],myJson[0]["columns"][6]["name"],myJson[0]["columns"][7]["name"]])
print(dataset)
lowest_col = dataset.sort_values('co', ascending=False).head(20000)
scatter_plot = px.scatter(lowest_col, x='ts', y='co', size='co', color='co',
color_continuous_scale='plasma', hover_name='co')
# Customize the plot
scatter_plot.update_layout(
title='Data Analysis',
xaxis_title='CO2 Emissions',
yaxis_title='Time'
)
scatter_plot.update_layout(template='plotly_dark')
# Show the plot
scatter_plot.show()
まとめ
以上で、GridDB Cloudとの連携方法と、データベース関連のさまざまな機能をご紹介しました。
ブログの内容について疑問や質問がある場合は Q&A サイトである Stack Overflow に質問を投稿しましょう。 GridDB 開発者やエンジニアから速やかな回答が得られるようにするためにも "griddb" タグをつけることをお忘れなく。 https://stackoverflow.com/questions/ask?tags=griddb