🎏

Amazon CodeWhisperer(プレビュー)でTimestreamのクエリを教えてもらう

2022/09/22に公開

動機

  • CodeWhispererのプレビューを使ってみました
  • ちょうどTimestreamのPython実装を試していたのでクエリを提案してもらおうかと思いました

先に感想

  • スニペット教えてもらえるけど、使えるかどうかを判断するのが難しいのでは
  • あくまでヒントや事例を教えてもらえる、という使い方になりそう

CodeWhispererとは

一言で書くと、コメント文や関数名からコードを提案してくれる機械学習サービスです。(2022年7月からプレビュー開始)

プレビューの申込みや、CodeWhispererの最初の使い方はこちらが詳しかったです。

https://dev.classmethod.jp/articles/amazon-codewhisperer/

プレビューについて

  • 無料
  • 良い結果を得るには、コメントがCodeWhispererの知っている構文にマッチしたときに提案しやすい。関数名を分かりやすくしたほうがよい。
  • プレビューではデータはCodeWhisperer学習用に使われない(※)。提案を使ったどうかの統計などは取得されている

(※)学習用に使われないということですが、自分の書いたコメント文がコメント提案候補として自動で現れるようになったのですが・・・???データはいろいろ取られてると思ったほうが良いでしょうね。

https://aws.amazon.com/jp/codewhisperer/faqs/?nc1=h_ls

プレビュー申込みで失敗した件

初期の申込みに応募していたのですが、通知のアクティベーション期限を見落としていて(そのときは7日だった)、再申し込みしたらけっこう後で再通知が来ました(ちなみに今回は30日でした)。

Thank you for signing up for the preview of Amazon CodeWhisperer. We are pleased to inform you that you now have access to Amazon CodeWhisperer. You can use this Preview Access Code to get started:

(Code)

You must use this access code within 7 days of receiving this email.

Timestreamのクエリ

boto3の実装のバリエーションを教えてもらった感じです。

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/timestream-query.html#TimestreamQuery.Client.query

やったこと

  • # Query Timestream と書いていると、残りのコメント部分を提案してくれるので # Query Timestream with multiple aggregation, having and limit のように補完する。その次の行でdefを打って提案してもらう(Alt+Cとか)。
    • そのうち、何もしなくてもコメント全部を提案してくれたりする
    • def XXXX(arg, arg,..): を書いておいた方が正確

実際の画面はこんな感じ。関数名を書いておいて、CodeWhispererが実行されると提案が薄く出てくるので、Tabキーで確定します。ちなみにこのときは、引数daysを使っていない結果が出て失敗しています。

準備

これは自力で書いたほうがよさそう。

import boto3
from botocore.config import Config

with Configurationをつけるとdocで推奨されているConfigが入ります。

# Create client for Timestream query 
client = boto3.client('timestream-query')

# Create client for Timestream query with Configuration
client = boto3.client('timestream-query', config=Config(read_timeout=20,
                      max_pool_connections=5000, retries={'max_attempts': 10}))

クエリを提案してもらう

# Query ... というコメント文で、CodeWhispererが def... 以下のクエリ関数を提案してくれます。

  • 関数定義def func_name()... からコードまで全部出してくれるときと、定義の部分だけ出してくれるときがある。定義の部分だけ、のときは(おそらく)コメントがあいまいなので定義を確認して、再度提案してもらえばよさそう。

  • 同じコメントで何度か試すと別の書き方を提案してくれたりする

とりあえず適当に# Query Timestream

by_client_tokenのやり方が提案されています。

# Query Timestream
def query_by_client_token(client, database_name, table_name, column_name, token_value):
    """
    Query a timestream database by client token.
    """
    return client.query(
        QueryString=f'SELECT * FROM "{database_name}"."{table_name}" WHERE "{column_name}" = \'{token_value}\'',
        ClientRequestToken=token_value)

微妙な結果のとき

所望の提案結果が出ないとき、関数名やdocstringsでコントロールした例です。

# Query Timestream with aggregationというコメントからの提案で、def query_by_day()が出てきました。daysを使っているクエリなのに、なぜかわざわざ秒に直しています。別に同じ結果なのでいいのですが・・・

# Query Timestream with aggregation
def query_by_day(client, database_name, table_name, days):
    """
    Query a timestream database by day.
    """
    return client.query(
        QueryString=f'SELECT * FROM "{database_name}"."{table_name}" WHERE time > now() - {days} * 24 * 60 * 60 SECONDS',
        ScanIndexForward=False)

コメントを書き直す

コメントを書き直してみます。これでWHERE time > now() - {days}d'にできました。失敗するときは、docstringsのQuery a timestream database from now.まで書いたら成功率上がります。しかしdateという存在しない変数を使う提案がよく出てきます。

# Query Timestream from now from days, with days as arg
def query_by_day(client, database_name, table_name, days):
    """
    Query a timestream database from now.
    """
    return client.query(
        QueryString=f'SELECT * FROM "{database_name}"."{table_name}" WHERE time > now() - {days}d',
        NextToken='string')

関数名とdocstringを書き直す

def query_from_days_ago(client, database_name, table_name, days):
    """
    Query a timestream database by day.
    """

とした状態で提案してもらうと、より良さそうです。(defの上のコメントはなし)

def query_from_days_ago(client, database_name, table_name, days):
    """
    Query a timestream database by day.
    """
    return client.query(
        QueryString=f'SELECT * FROM "{database_name}"."{table_name}" WHERE time > ago({days}day)',
        NextToken=next_token)

うまく行った例

(クエリを元々知っていたのですが、)関数と引数を先に書いてから提案してもらったとき

def query_between_timestamp(client, database_name, table_name, time_stamp_1, time_stamp_2):
    """
    Query a timestream database by timestamp.
    """
    return client.query(
        QueryString=f'SELECT * FROM "{database_name}"."{table_name}" WHERE time BETWEEN \'{time_stamp_1}\' AND \'{time_stamp_2}\'',
        NextToken='string')

まとめ

  • CodeWhispererのプレビューで使ってみました
    • PythonでTimestreamのクエリ文を出してもらいました
  • 所望の結果を出すには
    • (AIにとって)分かりやすいコメントを書く
    • 関数名を分かりやすくする
    • docstringもつけたす
  • どのみち自分で判断しないといけないので使いこなすのが難しそう、というのが感想です

おまけ

# Lambda handler to query Timestream with multiple offset だとそれっぽいhandlerが出てきました。この中のquery_by_offset()はそのとき同じファイル内にあった関数です。

# Lambda handler to query Timestream with multiple offset
def timestream_multiple_offset(event, context):
    """
    Lambda handler to query Timestream with multiple offset.
    """
    client = boto3.client('timestream-query')
    database_name = os.environ['DATABASE_NAME']
    table_name = os.environ['TABLE_NAME']
    days = int(event['multi_offset_days'])
    response = query_by_offset(client, database_name, table_name, days)
    print(f'Response: {response}')
    return response
    

Discussion