REST APIを使ってVantageにクエリーを送ってみた

Author: Sudha Vedula
Last updated: October 27th, 2022

:::note warn
警告
本記事はTeradata Corporationのサイト[Getting Started](https://quickstarts.teradata.com/index.html#getting-access-to-vantage)に掲載された内容を抄訳したものです。掲載内容の正確性・完全性・信頼性・最新性を保証するものではございません。正確な内容については、原本をご参照下さい。
また、修正が必要な箇所や、ご要望についてはコメントをよろしくお願いします。
:::

# 概要

Teradata Query Service は、Vantage 用の REST API で、これを使用すると、クライアント側のドライバを管理せずに標準的な SQL 文を実行できます。REST API を使用して Analytics データベースにクエリおよびアクセスする場合は、Query Service を使用します。

このハウツーでは、Query Service を使い始めるのに役立つ、一般的な使用例を紹介します。

# 前提条件

開始する前に、確認すること：

・Query Service がプロビジョニングされている VantageCloud システム、または Query Service が有効な接続を持つ VantageCore にアクセスできること。管理者でQuery Serviceをインストールする必要がある場合は、[『Query Service Installation, Configuration, and Usage Guide』](https://docs.teradata.com/r/Teradata-Query-Service-Installation-Configuration-and-Usage-Guide-for-Customers/April-2022)を参照してください。

・クエリサービスのホスト名とシステム名

・データベースに接続するための認証情報

前提条件に問題がありますか？セットアップ情報については、Teradataにお問い合わせください。


# クエリサービスAPIの例

例題を使用する際は、その点に留意してください：

・この文書ではPythonを使用していますが、これを利用してお好きな言語でサンプルを作成することができます。

・ここで提供されるサンプルは完全なものであり、すぐに使用できますが、ほとんどの場合、多少のカスタマイズが必要です。

　○このドキュメントの例では、URL [https://<QS_HOSTNAME>:1443/](https://%3Cqs_hostname%3E:1443/)を使用しています。

　○以下の変数を自分の好きな値に置き換えてください。

　　■ <QS_HOSTNAME>：クエリサービスがインストールされているサーバ

　　■ <SYSTEM_NAME>：システムの事前設定されたエイリアス

## Query Serviceインスタンスに接続します

HTTP Basic認証またはJWT認証を使用して、対象のAnalytics Databaseにアクセスするための有効な認証情報を提供します。

データベースのユーザー名とパスワードは文字列（"username : password"）に結合され、Base64でエンコードされます。APIレスポンスには、認証方法とエンコードされた認証情報が含まれます。

```:RequestScript
import requests
import json
import base64
requests.packages.urllib3.disable_warnings()

# run it from local.

db_user, db_password = 'dbc','dbc'
auth_encoded = db_user + ':' + db_password
auth_encoded = base64.b64encode(bytes(auth_encoded, 'utf-8'))
auth_str = 'Basic ' + auth_encoded.decode('utf-8')

print(auth_str)

headers = {
  'Content-Type': 'application/json',
  'Authorization': auth_str # base 64 encoded username:password
}

print(headers)
```

```:Response
Basic ZGJjOmRiYw==
{
  'Content-Type': 'application/json',
  'Authorization': 'Basic ZGJjOmRiYw=='
}
```

## 基本的なオプションで簡単なAPIリクエストを行う

以下の例では、リクエストの内容は以下の通りです：

・SELECT * FROM DBC.DBCInfo: エイリアス <SYSTEM_NAME> を持つシステムに対するクエリです。

・'format': 'OBJECT'。応答の形式。対応するフォーマットは以下の通り。JSONオブジェクト、JSON配列、およびCSV。


::: note info
メモ
JSONオブジェクト形式は、1行につき1つのJSONオブジェクトを作成し、列名はフィールド名、列値はフィールド値とする。
:::


・'includeColumns': true: カラム名や型などのカラムメタデータをレスポンスに含めるかどうかのリクエスト。

・'rowLimit': 4: クエリから返される行の数。

```:RequestScript
url = 'https://<QS_HOSTNAME>:1443/systems/<SYSTEM_NAME>/queries'

payload = {
  'query': example_query, # 'SELECT * FROM DBC.DBCInfo;',
  'format': 'OBJECT',
  'includeColumns': True,
  'rowLimit': 4
}

payload_json = json.dumps(payload)

response = requests.request('POST', url, headers=headers, data=payload_json, verify=False)

num_rows = response.json().get('results')[0].get('rowCount')
print('NUMBER of ROWS', num_rows)
print('==========================================================')

print(response.json())
```

```:Response
NUMBER of ROWS 4
==========================================================
{
  "queueDuration":7,
  "queryDuration":227,
  "results":[
    {
      "resultSet":True,
      "columns":[
        {
          "name":"DatabaseName",
          "type":"CHAR"
        },
        {
          "name":"USEDSPACE_IN_GB",
          "type":"FLOAT"
        },
        {
          "name":"MAXSPACE_IN_GB",
          "type":"FLOAT"
        },
        {
          "name":"Percentage_Used",
          "type":"FLOAT"
        },
        {
          "name":"REMAININGSPACE_IN_GB",
          "type":"FLOAT"
        }
      ],
      "data":[
        {
          "DatabaseName":"DBC",
          "USEDSPACE_IN_GB":317.76382541656494,
          "MAXSPACE_IN_GB":1510.521079641879,
          "Percentage_Used":21.03670247964377,
          "REMAININGSPACE_IN_GB":1192.757254225314
        },
        {
          "DatabaseName":"EM",
          "USEDSPACE_IN_GB":0.0007491111755371094,
          "MAXSPACE_IN_GB":11.546071618795395,
          "Percentage_Used":0.006488017745513208,
          "REMAININGSPACE_IN_GB":11.545322507619858
        },
        {
          "DatabaseName":"user10",
          "USEDSPACE_IN_GB":0.019153594970703125,
          "MAXSPACE_IN_GB":9.313225746154785,
          "Percentage_Used":0.20566016,
          "REMAININGSPACE_IN_GB":9.294072151184082
        },
        {
          "DatabaseName":"EMEM",
          "USEDSPACE_IN_GB":0.006140708923339844,
          "MAXSPACE_IN_GB":4.656612873077393,
          "Percentage_Used":0.13187072,
          "REMAININGSPACE_IN_GB":4.650472164154053
        },
        {
          "DatabaseName":"EMWork",
          "USEDSPACE_IN_GB":0.0,
          "MAXSPACE_IN_GB":4.656612873077393,
          "Percentage_Used":0.0,
          "REMAININGSPACE_IN_GB":4.656612873077393
        }
      ],
      "rowCount":4,
      "rowLimitExceeded":True
    }
  ]
}
```

応答パラメータについては、[『Query Service Installation, Configuration, and Usage Guide』](https://docs.teradata.com/r/Teradata-Query-Service-Installation-Configuration-and-Usage-Guide-for-Customers/April-2022/Using-the-Query-Service-APIs/Submitting-SQL-Statement/Request-Body)を参照してください。

## CSV形式での応答要求

APIレスポンスをCSV形式で返すには、リクエストの**format**フィールドに**CSV**という値を設定します。

CSV 形式はクエリーの結果のみを含み、レスポンスのメタデータは含みません。レスポンスには各行が含まれ、各行にはカンマで区切られた行のカラムが含まれます。次の例は、データをカンマ区切りの値として返します。

```:RequestScript
# CSV with all rows included

url = 'https://<QS_HOSTNAME>:1443/systems/<SYSTEM_NAME>/queries'

payload = {
  'query': example_query, # 'SELECT * FROM DBC.DBCInfo;',
  'format': 'CSV',
  'includeColumns': True
}

payload_json = json.dumps(payload)

response = requests.request('POST', url, headers=headers, data=payload_json, verify=False)

print(response.text)
```

レスポンス
|DatabaseName|USEDSPACE_IN_GB|MAXSPACE_IN_GB|Percentage_Used|REMAININGSPACE_IN_GB|
|:------------|---------------:|--------------:|---------------:|--------------------:|
|DBC|317.7634754180908|1510.521079641879|21.036679308932754|1192.7576042237881|
|EM|7.491111755371094E-4|11.546071618795395|0.006488017745513208|11.545322507619858|
|user10|0.019153594970703125|9.313225746154785|0.20566016|9.294072151184082|
|EMEM|0.006140708923339844|4.656612873077393|0.13187072|4.650472164154053|
|EMWork|0.0|4.656612873077393|0.0|4.656612873077393|
|EMJI|0.0|2.3283064365386963|0.0|2.3283064365386963|
|USER_NAME|0.0|2.0|0.0|2.0|
|readonly|0.0|0.9313225746154785|0.0|0.9313225746154785|
|aug12_db|7.200241088867188E-5|0.9313225746154785|0.0077312|0.9312505722045898|
|SystemFe|1.8024444580078125E-4|0.7450580596923828|0.024192|0.744877815246582|
|dbcmngr|3.814697265625E-6|0.09313225746154785|0.004096|0.09312844276428223|
|EMViews|0.027594566345214844|0.09313225746154785|29.62944|0.06553769111633301|
|tdwm|6.732940673828125E-4|0.09313225746154785|0.722944|0.09245896339416504|
|Crashdumps|0.0|0.06984921544790268|0.0|0.06984921544790268|
|SYSLIB|0.006252288818359375|0.03725290298461914|16.78336|0.031000614166259766|
|SYSBAR|4.76837158203125E-6|0.03725290298461914|0.0128|0.03724813461303711|
|SYSUDTLIB|3.5381317138671875E-4|0.029802322387695312|1.1872|0.029448509216308594|
|External_AP|0.0|0.01862645149230957|0.0|0.01862645149230957|
|SysAdmin|0.002307891845703125|0.01862645149230957|12.3904|0.016318559646606445|
|KZXaDtQp|0.0|0.009313225746154785|0.0|0.009313225746154785|
|s476QJ6O|0.0|0.009313225746154785|0.0|0.009313225746154785|
|hTzz03i7|0.0|0.009313225746154785|0.0|0.009313225746154785|
|Y5WYUUXj|0.0|0.009313225746154785|0.0|0.009313225746154785|



## 明示的なセッションを使用してクエリーを送信する

トランザクションが複数のリクエストにまたがる必要がある場合や、揮発性のテーブルを使用する場合は、明示的なセッションを使用します。これらのセッションは、クエリリクエストでセッションを参照する場合にのみ再利用されます。リクエストがすでに使用されている明示的セッションを参照する場合、リクエストはキューに入れられます。

１．セッションを作成する

system/<SYSTEM_NAME>/sessions エンドポイントに POST リクエストを送信します。このリクエストは、新しいデータベースセッションを作成し、セッションの詳細をレスポンスとして返します。

次の例では、リクエストに 'auto_commit': True - 完了時にクエリをコミットする要求が含まれています。

```:RequestScript
# first create a session
url = 'https://<QS_HOSTNAME>:1443/systems/<SYSTEM_NAME>/sessions'

payload = {
  'auto_commit': True
}

payload_json = json.dumps(payload)

response = requests.request('POST', url, headers=headers, data=payload_json, verify=False)

print(response.text)
```


```:Response
{
  'sessionId': 1366010,
  'system': 'testsystem',
  'user': 'dbc',
  'tdSessionNo': 1626922,
  'createMode': 'EXPLICIT',
  'state': 'LOGGINGON',
  'autoCommit': true
}
```

２．手順1で作成したセッションを使用して、クエリーを送信します。

system/<SYSTEM_NAME>/queries エンドポイントに POST リクエストを送信します。

このリクエストでは、対象システムに対してクエリーを送信し、対象システムのリリース番号とバージョン番号を返します。

以下の例では、リクエストの内容は以下の通りです：

　○　SELECT * FROM DBC.DBCInfo: エイリアス <SYSTEM_NAME> を持つシステムに対するクエリです。

　○　'format': 'OBJECT'。応答のフォーマットです。

　○　'Session'(セッション): <Session ID>: 明示的なセッションを作成するためにステップ1で返されたセッションIDです。


```:Request
# use this session to submit queries afterwards

url = 'https://<QS_HOSTNAME>:1443/systems/<SYSTEM_NAME>/queries'

payload = {
  'query': 'SELECT * FROM DBC.DBCInfo;',
  'format': 'OBJECT',
  'session': 1366010 # <-- sessionId
}
payload_json = json.dumps(payload)

response = requests.request('POST', url, headers=headers, data=payload_json, verify=False)

print(response.text)
```

```:Response
{
  "queueDuration":6,
  "queryDuration":41,
  "results":[
    {
      "resultSet":true,
      "data":[
        {
          "InfoKey":"LANGUAGE SUPPORT MODE",
          "InfoData":"Standard"
        },
        {
          "InfoKey":"RELEASE",
          "InfoData":"15.10.07.02"
        },
        {
          "InfoKey":"VERSION",
          "InfoData":"15.10.07.02"
        }
      ],
      "rowCount":3,
      "rowLimitExceeded":false
    }
  ]
}
```

## 非同期クエリを使用する
非同期クエリーは、大量のデータや長時間実行するクエリーによってシステムやネットワークのパフォーマンスに影響を与える場合に使用します。

１．ターゲットシステムに非同期クエリを送信し、クエリIDを取得する

system/<SYSTEM_NAME>/queries のエンドポイントに POST リクエストを送信します。

次の例では、リクエストの内容は次のとおりです：

　○　SELECT * FROM DBC.DBCInfo: エイリアス <SYSTEM_NAME> を持つシステムに対するクエリです。

　○　'format': 'OBJECT'。応答のフォーマットです。

　○　'spooled_result_set': True: リクエストが非同期であることを示す。

```:Request
## Run async query .

url = 'https://<QS_HOSTNAME>:1443/systems/<SYSTEM_NAME>/queries'

payload = {
  'query': 'SELECT * FROM DBC.DBCInfo;',
  'format': 'OBJECT',
  'spooled_result_set': True
}

payload_json = json.dumps(payload)
response = requests.request('POST', url, headers=headers, data=payload_json, verify=False)

print(response.text)
```


```:Response
{"id":1366025}
```

２．Step1で取得したIDを使用して、クエリの詳細を取得する。

system/<SYSTEM_NAME>/queries/<queryID>エンドポイントにGETリクエストを送信します。<queryID>は手順1で取得したIDに置き換えてください。

このリクエストでは、**queryState、queueOrder、queueDuration** など、特定のクエリの詳細が返されます。応答フィールドの完全なリストとその説明については、[『Query Service Installation, Configuration, and Usage Guide（クエリ・サービスのインストール、設定、および使用ガイド）』](https://docs.teradata.com/r/Teradata-Query-Service-Installation-Configuration-and-Usage-Guide-for-Customers/April-2022/Using-the-Query-Service-APIs/Submitting-SQL-Statement/Request-Body)を参照してください。

```:Response
## response for async query .

url = 'https://<QS_HOSTNAME>:1443/systems/<SYSTEM_NAME>/queries/1366025'

payload_json = json.dumps(payload)
response = requests.request('GET', url, headers=headers, verify=False)

print(response.text)
```

```:Response
{
  "queryId":1366025,
  "query":"SELECT * FROM DBC.DBCInfo;",
  "batch":false,
  "system":"testsystem",
  "user":"dbc",
  "session":1366015,
  "queryState":"RESULT_SET_READY",
  "queueOrder":0,
  "queueDuration":6,
  "queryDuration":9,
  "statusCode":200,
  "resultSets":{

  },
  "counts":{

  },
  "exceptions":{

  },
  "outParams":{

  }
}
```

３．非同期クエリの結果セットを表示する

システム/<SYSTEM_NAME>/queries/<queryID>/resultsエンドポイントにGETリクエストを送信します。<queryID>を手順1で取得したIDに置き換えます。このリクエストは、送信されたクエリによって生成された結果セットと更新回数のアレイを返します。

```:Request
url = 'https://<QS_HOSTNAME>:1443/systems/<SYSTEM_NAME>/queries/1366025/results'

payload_json = json.dumps(payload)
response = requests.request('GET', url, headers=headers, verify=False)

print(response.text)
```

```:Response
{
  "queueDuration":6,
  "queryDuration":9,
  "results":[
    {
      "resultSet":true,
      "data":[
        {
          "InfoKey":"LANGUAGE SUPPORT MODE",
          "InfoData":"Standard"
        },
        {
          "InfoKey":"RELEASE",
          "InfoData":"15.10.07.02"
        },
        {
          "InfoKey":"VERSION",
          "InfoData":"15.10.07.02"
        }
      ],
      "rowCount":3,
      "rowLimitExceeded":false
    }
  ]
}
```

## アクティブまたはキューイングされたクエリのリストを取得する

system/<SYSTEM_NAME>/queries エンドポイントに GET リクエストを送信します。このリクエストは、アクティブなクエリのIDを返します。

```:Request
url = 'https://<QS_HOSTNAME>:1443/systems/<SYSTEM_NAME>/queries'

payload={}

response = requests.request('GET', url, headers=headers, data=payload, verify=False)

print(response.json())
```

```:Response
[
  {
    "queryId": 12516087,
    "query": "SELECt * from dbcmgr.AlertRequest;",
    "batch": false,
    "system": "BasicTestSys",
    "user": "dbc",
    "session": 12516011,
    "queryState": "REST_SET_READY",
    "queueOrder": 0,
    "queueDurayion": 3,
    "queryDuration": 3,
    "statusCode": 200,
    "resultSets": {},
    "counts": {},
    "exceptions": {},
    "outparams": {}
  },
  {
    "queryId": 12516088,
    "query": "SELECt * from dbc.DBQLAmpDataTbl;",
    "batch": false,
    "system": "BasicTestSys",
    "user": "dbc",
    "session": 12516011,
    "queryState": "REST_SET_READY",
    "queueOrder": 0,
    "queueDurayion": 3,
    "queryDuration": 3,
    "statusCode": 200,
    "resultSets": {},
    "counts": {},
    "exceptions": {},
    "outparams": {}
  }
]
```

## 参考となるリンク

・機能、実行例、コマンド使用法など: [Query Service Installation, Configuration, and Usage Guide](https://docs.teradata.com/r/Teradata-Query-Service-Installation-Configuration-and-Usage-Guide-for-Customers/April-2022)

・Teradata Query Serviceのダウンロード: [Query Service API OpenAPI Specification](https://downloads.teradata.com/api/teradata_query_service)

#### Teradata Vantageへのお問合せ
[Teradata Vantage へのお問合せ](https://www.teradata.jp/About-Us/Contact)