Superset で TD に接続できるか動作確認をした

サマリー

  • Superset から TD に接続する方法として pyhive、trino-python-client、sqlalchemy-trino を試したがどれも現時点までの実装だと対応が難しそう。
  • pyhive にパッチを当てることで接続でき、クエリが実行できることを確認した。
  • [2022-02-08 追記] 最新の trino-python-client をインストールすることでクエリが実行できることを確認した。

Superset を localhost で動かす

こんな感じの Dockerfile を用意して、

FROM apache/superset:1.4.0
USER root
RUN superset db upgrade && \
superset init && \
superset fab create-admin \
            --username superset-admin \
            --password superset-admin \
            --firstname Superset \
            --lastname Admin \
            --email admin@superset.com

build して run する。

docker build . -t superset-td-example
docker run -d -p 8088:8088 superset-td-example

http://localhost:8088/ にアクセスして、Dockerfile で指定したユーザー名とパスワードを入力し、ログインできることを確認。

f:id:wonderthinkanswer:20220206162707p:plain

TD への接続確認

PyHive で動作確認

PyHivePython から Hive/Presto に接続する際に使われる一番ポピュラーなライブラリであり、sqlalchemy の Hive/Presto dialect である。 上記の Superset の用意した docker image にもすで含まれており、デフォルトでは Hive/Presto への接続ではこれが使われる。

Superset のコンソール上から database を作成し、接続テストする。 設定はこんな感じ。<<TD_API_KEY>> は実際の API key に置換する。

# SQLALCHEMY URI
presto://api-presto.treasuredata.com/td-presto/sample_datasets
# ADVANCED > Others > ENGINE PARAMETERS
{
  "connect_args": {
    "username": "<<TD_API_KEY>>",
    "port": 443,
    "protocol": "https"
  }
}

f:id:wonderthinkanswer:20220206165551p:plain

f:id:wonderthinkanswer:20220206165600p:plain

Test Connection を実行すると、Connection looks good! と表示され成功するが、 Connect を実行すると An error occurred while creating databases: Fatal error と表示され失敗する。docker のエラーログを確認すると Missing X-Presto-User header が原因であることが分かる。

sqlalchemy.exc.OperationalError: (pyhive.exc.OperationalError) Unexpected status code 401
b'{"id":"20220206_075652_49433_c4j75","infoUri":"http://not_accessible","stats":{"state":"FAILED","queued":false,"scheduled":false,"nodes":0,"totalSplits":0,"queuedSplits":0,"runningSplits":0,"completedSplits":0,"cpuTimeMillis":0,"wallTimeMillis":0,"queuedTimeMillis":0,"elapsedTimeMillis":0,"processedRows":0,"processedBytes":0,"peakMemoryBytes":0,"spilledBytes":0},"error":{"message":"Missing X-Presto-User header","sqlState":"FAILED","errorCode":4,"errorName":"PERMISSION_DENIED","errorType":"USER_ERROR","errorLocation":{"lineNumber":1,"columnNumber":1},"failureInfo":{"type":"com.treasuredata.prestobase.core.PrestobaseException","message":"[InvalidArgument] Missing X-Presto-User header","suppressed":[],

同様の Issue は PyHive に報告されており、当該 PR は close はされているが問題は解消していないようだ。

Fix get/delete requests in Presto to accept headers by toru-takahashi · Pull Request #200 · dropbox/PyHive · GitHub

更に、今年 2022年 に入り、PyHive は unsupported であるというという明記がされてしまったため修正が取り入れられることはなさそうだ。

Mention that project is unsupported

Update README.rst by bkyryliuk · Pull Request #423 · dropbox/PyHive · GitHub

PyHive では trino の dialect もサポートしていたようだがベースは presto のものであり問題は解消されない。

trino-python-client で動作確認

trino-python-client では trino の sqlalchemy の dialect をサポートしている。 と言うことで、上記の Dockerfile に

pip uninstall -y pyhive && \
pip install trino

を追加して build & run する。 再度、Superset のコンソール上から database を作成し、接続テストする。

# SQLALCHEMY URI
trino://api-presto.treasuredata.com/td-presto/sample_datasets
# ADVANCED > Others > ENGINE PARAMETERS
{
  "connect_args": {
    "user": "<<TD_API_KEY>>",
    "port": 443,
    "http_scheme": "https"
  }
}

Test Connection を実行すると ERROR: line 1:8: Function 'version' not registered が表示され失敗する。

元の実装であった sqlalchemy-trino の issue を確認すると、どうやら当該 trino の dialect でサポートしている trino のバージョンは 352 以降らしい。エラーの元となっている select version(); がどこかの時点でライブラリで使用されるようになり、それをサポートしている trino が 352 以降ということのようだ。

Update Readme Instruction to clear supported trino version · Issue #7 · dungdm93/sqlalchemy-trino · GitHub

TD のサポートする trino のバージョンは 350 が最新であり、アップグレードによる問題の解消はできない。

[2022-02-08 追記]

twitter でつぶやいたところ、ebyhr さんに補足され、trino-python-client の修正パッチを書いていただいた!

server_version_info: Optional[Tuple[Any, ...]]
"""a tuple containing a version number for the DB backend in use.
This value is only available for supporting dialects, and is
typically populated during the initial connection to the database.
"""

[https://github.com/sqlalchemy/sqlalchemy/blob/main/lib/sqlalchemy/engine/interfaces.py#L518-L522:title]

どうやら server_version_info は dialect の実装補助のための情報で、trino-python-client では使っていなく、必須ではないようだ。 ということで、

pip uninstall -y pyhive && \
pip install trino==0.310.0

みたいな感じで最新のものを使うとクエリを実行できることを確認した。Happy!

[追記ここまで]

sqlalchemy-trino で動作確認

それではと、上記の select version(); の導入前の sqlalchemy-trino を使うことで問題が解消されるか確認する。

Dockerfile の pip 実行部を trino から sqlalchemy-trino に修正して、改めて build & run する。

pip uninstall -y pyhive && \
pip install git+https://github.com/dungdm93/sqlalchemy-trino.git@d343c46b79475b577c8a1fa166dfec30112c10e3

再度 Database を作成し、Test Connection を実行すると ERROR: Access Denied: Cannot select from table runtime.nodes が表示され失敗する。

これは、TD が runtime.nodesというシステム用テーブルへのアクセスを許可していないことに起因するため、こちらも解消は厳しそうだ。

誰も心当たりのないPrestoクエリについて - PLAZMA by Treasure Data

PyHive にパッチを当てて動作確認

pyhive、trino-python-client、sqlalchemy-trino の現時点までの実装だと対応が難しそうなので、パッチを当てることで接続できるか確認する。 pyhive を fork して下記 Toru-san の PR の修正をそのまま pyhive に適用し、適当に push する。

Fix get/delete requests in Presto to accept headers by toru-takahashi · Pull Request #200 · dropbox/PyHive · GitHub

Dockerfile の pip 実行部を下記のように修正して、再度 build & run。

pip uninstall -y pyhive && \ 
pip install git+https://github.com/satoshihirose/pyhive.git@develop

Superset にログインし、上記 pyhive のセクションの設定のまま Database を作成すると、成功した。

f:id:wonderthinkanswer:20220206183551p:plain

クエリエディターから実際にクエリを実行できることを確認した。

f:id:wonderthinkanswer:20220206183840p:plain