Presto コネクターを実装する 第二回

こんにちは。松本です。

前回に続き、Presto のコネクター実装方法について解説します。第二回の今回はテーブルのハンドルクラスやメタデータを操作するクラスを扱います。

実装する主なクラスは次の 4 つです。

  • TechscoreColumnHandle implements com.facebook.presto.spi.ConnectorColumnHandle
  • TechscoreTableHandle implements com.facebook.presto.spi.ConnectorTableHandle
  • TechscoreHandleResolver implements com.facebook.presto.spi.ConnectorHandleResolver
  • TechscoreMetadata extends com.facebook.presto.spi.ReadOnlyConnectorMetadata

ハンドルクラス

Presto コネクターでは、ConnectorTableHandle インターフェースと ConnectorColumnHandle インターフェースの実装クラスを使って、テーブルやカラムをハンドリングします。

まずはカラムハンドル。

com.techscore.example.presto.plugin.TechscoreColumnHandle

ConnectorColumnHandle 実装クラスは、コネクター内でカラムを扱いやすいよう好きに実装します。

実装のポイントとして、Presto 本体側で本クラスのインスタンスがキャッシュされるよう、@JsonCreator@JsonProperty アノテーションを使って JSON でのシリアライズ/デシリアライズを可能とすることです。

Presto ではケース無視でカラム名が扱われる為、caseSensitiveName で渡されたカラム名を小文字化した name プロパティも持つようにしています。

type プロパティはカラムのデータ型を表すクラスで、com.facebook.presto.spi.type パッケージ内に基本的なデータ型が用意されています。

主なデータ型です。

ordinalPosition プロパティはテーブル内でのこのカラムの順序を表します。このプロパティは Presto が使用するカラムメタデータクラスである ColumnMetadata にも引き継がれ、SELECT * 等で SQL が発行された場合のカラムの並び順として利用されます。

最終的に、これらの情報を使い ColumnMetadata を生成します。

次にテーブルハンドル。

com.techscore.example.presto.plugin.TechscoreTableHandle

ConnectorTableHandle の実装クラスも、コネクター内でテーブル情報が扱いやすいよう好きに実装します。

今回の実装では connectorIdSchemaTableName のインスタンスを持つだけとしています。SchemaTableName はその名の通り対象テーブルのスキーマ名とテーブル名を持つクラスです。

こちらも TechscoreColumnHandle 同様、JSON でのシリアライズ/デシリアライズが可能になるようアノテーションを付けています。TechscoreTableHandle では JSON でのキャッシュ化を見込んで、あまりファットなオブジェクトにならないよう考慮しています。

com.techscore.example.presto.plugin.TechscoreHandleResolver

ConnectorHandleResulver インターフェースの実装クラスはこんなものと見て頂けば十分です。各種ハンドルクラスを扱うシンプルなメソッドを持っているだけのクラスです。

今回の実装では ConnectorTableHandle, ConnectorColumnHandle, ConnectorSplit 以外は扱わないので、これらに関係しないメソッドは UnsupportedOperationException をスローしたり、false を返すのみとしました。

canHandle() メソッドや getSplitClass() 等で使われている ConnectorSplit インターフェースとその実装クラスである TechscoreSplit については次回、触れる予定です。

メタデータ操作クラス

次は重要なメタデータクラス。Presto は ConnectorMetadata インターフェースの実装クラスを通して、コネクターが扱う各種メタデータにアクセスします。

com.techscore.example.presto.plugin.TechscoreMetadata

ConnectorMetadata は、ConnectorTableHandle インターフェースおよび TechscoreColumnHandle インターフェースを操作する重要なインターフェースです。その実装クラスである TechscoreMetadata は、ConnectorMetadata の抽象クラスである ReadOnlyConnectorMetadata のサブクラスとして実装しています。

コンストラクタで注入している TechscoreClient は本サンプルコネクターの為に用意した POJO で、仮想の「TECHSCORE ブログ API クライアント」です。サンプルコネクターはこのクラスを通してテーブルのメタデータやレコードを取得します(今回はサンプルなので静的に情報を返しているだけのクラスとなっています)。TechscoreClient とその関連クラスについては本記事の最後にソースコードを掲載します。

listSchemaNames() メソッドはコネクターが扱うスキーマの名前を返すもので、show schemas from techscore; 等のコマンドを実行した場合に利用されます。

getTableHandle() メソッドや getColumnHandles() メソッドは指定されたテーブルのテーブルハンドルやカラムハンドルを返すものです。シグニチャ的には戻り値の型が ConnectorTableHandleConnectorColumnHandle となっていますが、本コネクターでの実装クラスである TechscoreTableHandle, TechscoreColumnHandle を返すよう実装します。

getTableMetadata() メソッドや getColumnMetadata() メソッドは、ハンドルを ConnectorTableMetadataColumnMetadata といったメタデータに変換するものです。引数は型として ConnectorTableHandle インターフェースや ConnectorColumnHandle インターフェースが定義されていますが、実際にはその実装クラスである TechscoreTableHandle, TechscoreColumnHandle のインスタンスが渡されます。

listTables() メソッドはコネクターが扱うテーブルの SchemaTableName オブジェクトのリストを返すもので、show tables from techscore.schema1; のようなコマンド発行時に利用されます。ここで返す SchemaTableName のリストは、引数 String schemaNameOrNull が指定するスキーマに属すテーブルについてだけを扱いますが、schemaNameOrNull の値が null の場合はスキーマに関係なく全てのテーブルの SchemaTableName を返すよう実装します。

listTableColumns() メソッドは引数に従って対象テーブルのカラムリストを返します。引数の SchemaTablePrefixSchemaTableName と同様、スキーマ名とテーブル名を持つクラスですが、SchemaTableName とは違い各プロパティが null を許可していますので、その内容によって次のように処理を分ける必要があります。

  • 「スキーマ名もテーブル名も null 」 - 全テーブルを対象とし、テーブルごとのカラムリストを作成する
  • 「テーブル名のみ null 」 - 指定されたスキーマに属す全てのテーブルを対象とし、テーブルごとのカラムリストを作成する
  • 「いずれも null ではない」 - 指定されたひとつのテーブルを対象とし、カラムリストを作成する

ここで役に立つのが SchemaTablePrefix#matches(SchemaTableName) メソッドで、引数として渡した SchemaTableName オブジェクトが SchemaTablePrefix にマッチするかを上手く判断してくれます。

テーブル定義とデータ

最後に TechscoreMetadata で少し触れた TechscoreClient とその関連クラスのソースを掲載します。

「記事テーブル / techscore.schema1.entries 」と「著者テーブル / techscore.schema1.authors 」を定義しています。

com.techscore.example.presto.plugin.TechscoreClient

com.techscore.example.presto.plugin.TechscoreTables

com.techscore.example.presto.plugin.TechscoreTable

と、ここで気づきましたが、このままでは TechscoreTables 内の文字列リテラルが文字化けを起こしてしまいますね。build.gradle にエンコーディング設定を追加しておきましょう。

次回は

第三回の次回はいよいよレコード操作系のクラスの実装に進みます。

Comments are closed, but you can leave a trackback: Trackback URL.