pythonからhiveserver2につなごうとしていろいろハマったのでメモっておく
CDH4.5のhiveserver2にpython 2.7+NOSASLでつなごうとしていろいろハマったのでメモっておきます。
Setting Up HiveServer2 - Apache Hive - Apache Software Foundation をみると GitHub - BradRuderman/pyhs2をインストールして使えばいいようだがうまくいかなかった。
具体的には「Required field 'sessionHandle' is unset!」と言われる。
別のライブラリ使ってみるかと思ってGitHub - y-lan/python-hiveserver2: Python binding for HiveServer2を使ったけど「Required field 'client_protocol' is unset!」と言われる。
うっきー。
pyhs2のソースをもとにライブラリ使わずに自分で書いていろいろ試した結果、下記のようなソースでうまく接続出来た。
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import os sys.path.append('/usr/lib/hive/lib/py') from TCLIService import TCLIService from TCLIService.ttypes import TOpenSessionReq, TGetTablesReq, TFetchResultsReq,\ TStatusCode, TGetResultSetMetadataReq, TGetColumnsReq, TType,\ TExecuteStatementReq, TGetOperationStatusReq, TFetchOrientation,\ TCloseSessionReq, TGetSchemasReq, TCancelOperationReq from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol def get_value(colValue): if colValue.boolVal is not None: return colValue.boolVal.value elif colValue.byteVal is not None: return colValue.byteVal.value elif colValue.i16Val is not None: return colValue.i16Val.value elif colValue.i32Val is not None: return colValue.i32Val.value elif colValue.i64Val is not None: return colValue.i64Val.value elif colValue.doubleVal is not None: return colValue.doubleVal.value elif colValue.stringVal is not None: return colValue.stringVal.value socket = TSocket.TSocket('localhost', 10000) transport = TTransport.TBufferedTransport(socket) protocol = TBinaryProtocol.TBinaryProtocol(transport) client = TCLIService.Client(protocol) transport.open() request = TOpenSessionReq(username='...') res = client.OpenSession(request) session = res.sessionHandle hql = "select * from ..." query = TExecuteStatementReq(session, statement=hql, confOverlay={}) res = client.ExecuteStatement(query) fetch_req = TFetchResultsReq(operationHandle=res.operationHandle, orientation=TFetchOrientation.FETCH_NEXT, maxRows=100) resultsRes = client.FetchResults(fetch_req) rows = [] for row in resultsRes.results.rows: rowData= [] for i, col in enumerate(row.colVals): rowData.append(get_value(col)) rows.append(rowData) if len(resultsRes.results.rows) == 0: break for row in rows: print row
NOSASLの場合はusernameを指定して接続しないとダメみたいなんだけどpyhs2だとそれが出来ないという状況でした。
これに関してはとりあえずpull reqestしときました。
https://github.com/BradRuderman/pyhs2/pull/14
もうひとつハマったのは結果を取得してきたときに日本語文字列が?になること。「あああ」だったら「???」になる。
Hive CLIだと問題なかったしshibとbeeswaxでも問題無かった。特にbeeswaxはpythonなのでなんでうまく言っているのか不思議に思ってソースも見たんだけど特に変わったことしてなさそうでした。
諦めてCLIでいくかshibのHTTP API使おうかとも考えたんですけど、hiveからMySQLにselect insertしたくて、そうするとCLIだと外部プロセス起動になって標準出力を扱わないといけないし、shibだとselectした後にpollingして終了を待つ必要があるしで、まあhiveserver2経由で出来た方がいいよねと。
hiveで集計してsqoopでMySQLにもってくるってのもちょっと考えたけどね。
で、まあ、いろいろググった結果ひっかかったのがこれ。この人はどうもperlのhiveserver2クライアント Thrift::API::HiveClient2 - Perl to HiveServer2 Thrift API wrapper - metacpan.org を書いていてこの問題に遭遇したようだ。
Google グループ
「-Dfile.encoding=UTF-8」を指定してhiveserver2を再起動したら無事解決した。やったー。