Executable および ExecutablePool テーブルエンジン
Executable および ExecutablePool テーブルエンジンを使用すると、(行を stdout に書き出すことで)ユーザー定義のスクリプトによって行が生成されるテーブルを定義できます。実行可能スクリプトは users_scripts ディレクトリに保存され、任意のソースからデータを読み取ることができます。
Executableテーブル: クエリごとにスクリプトが実行されますExecutablePoolテーブル: 永続プロセスのプールを維持し、読み取り時にそのプールからプロセスを取得します
オプションとして、1 つ以上の入力用クエリを含めることができ、その結果を stdin にストリームしてスクリプトが読み取れるようにできます。
Executable テーブルの作成
Executable テーブルエンジンには、スクリプト名と入力データの形式という 2 つのパラメータを指定する必要があります。必要に応じて、1 つ以上の入力クエリを渡すこともできます。
Executable テーブルに関連する設定は次のとおりです:
send_chunk_header- 説明: チャンクを処理に送る前に、そのチャンク内の行数を送信します。この設定を有効にすると、スクリプト側でリソースを事前割り当てするなど、より効率的な記述が可能になります。
- デフォルト値: false
command_termination_timeout- 説明: コマンドを終了させるタイムアウト(秒)
- デフォルト値: 10
command_read_timeout- 説明: コマンドの標準出力からデータを読み取るタイムアウト(ミリ秒)
- デフォルト値: 10000
command_write_timeout- 説明: コマンドの標準入力へデータを書き込むタイムアウト(ミリ秒)
- デフォルト値: 10000
例を見てみましょう。次の Python スクリプトは my_script.py という名前で、user_scripts フォルダ内に保存されています。数値 i を入力として受け取り、i 個のランダムな文字列を出力します。各文字列の先頭には、タブで区切られた番号が付与されます:
次の my_executable_table は my_script.py の出力から作成されたもので、my_executable_table に対して SELECT を実行するたびに 10 個のランダムな文字列を生成します。
テーブルを作成しても、スクリプトは呼び出されず、即座に処理が返されます。my_executable_table をクエリすると、スクリプトが呼び出されます。
クエリ結果をスクリプトに渡す
Hacker News サイトのユーザーはコメントを投稿します。Python には自然言語処理ツールキット (nltk) があり、その中の SentimentIntensityAnalyzer を使うと、コメントがポジティブかネガティブかニュートラルかを判定し、-1(非常にネガティブなコメント)から 1(非常にポジティブなコメント)の値を割り当てることができます。nltk を使って Hacker News のコメントのセンチメント(感情)を計算する Executable テーブルを作成してみましょう。
この例では、こちら で説明している hackernews テーブルを使用します。hackernews テーブルには、型が UInt64 の id 列と、comment という名前の String 型の列があります。まずは Executable テーブルを定義することから始めましょう。
sentiment テーブルについての補足:
- ファイル
sentiment.pyはuser_scriptsフォルダ(user_scripts_path設定のデフォルトフォルダ)に保存されています TabSeparatedフォーマットは、Python スクリプトがタブ区切りの値を含む生データ行を生成する必要があることを意味します- クエリは
hackernewsから 2 つのカラムを選択します。Python スクリプトでは、入力として渡される各行からこれらのカラム値をパース(抽出)する必要があります
sentiment.py の定義は次のとおりです:
Python スクリプトについての補足説明です。
- これを動作させるには、
nltk.downloader.download('vader_lexicon')を実行する必要があります。これはスクリプト内に含めることもできますが、その場合はsentimentテーブルに対してクエリが実行されるたびに毎回ダウンロードされてしまい、非効率です rowのそれぞれの値は、SELECT id, comment FROM hackernews WHERE id > 0 AND comment != '' LIMIT 20の結果セットの 1 行に対応します- 入力として渡される行はタブ区切りになっているため、Python の
split関数を使ってidとcommentをパースします polarity_scoresの結果は、いくつかの値を持つ JSON オブジェクトです。ここでは、この JSON オブジェクトからcompoundの値だけを取得することにしました- ClickHouse の
sentimentテーブルはTabSeparatedフォーマットを使用し 2 つのカラムを持っているので、print関数ではそれらのカラムをタブで区切っています
sentiment テーブルから行を選択するクエリを記述するたびに、SELECT id, comment FROM hackernews WHERE id > 0 AND comment != '' LIMIT 20 クエリが実行され、その結果が sentiment.py に渡されます。実際に試してみましょう。
レスポンスは次のとおりです。
ExecutablePool テーブルの作成
ExecutablePool の構文は Executable と似ていますが、ExecutablePool テーブルに固有の重要な設定がいくつかあります。
pool_size- 説明: プロセスプールのサイズ。サイズが 0 の場合はサイズ制限がありません。
- デフォルト値: 16
max_command_execution_time- 説明: コマンドの最大実行時間(秒単位)
- デフォルト値: 10
上記の sentiment テーブルは、Executable の代わりに ExecutablePool を使用するように容易に変更できます。
クライアントが sentiment_pooled テーブルをクエリすると、ClickHouse は必要に応じて 4 つのプロセスを起動して維持します。