ThriftHiveClient を少し便利にしてみた

以前、HiveServerを使用してPHPからHiveQLを実行するで、PHPから HiveQLを実行してみました。 その際に、ThriftHiveClientの使い勝手が少し悪かったので改良を施してみました。

どこが使い勝手が悪いどうこう言う前に、前回のコードを見てみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$GLOBALS['THRIFT_ROOT'] = dirname(__FILE__) . '/lib/';
require_once $GLOBALS['THRIFT_ROOT'] . 'packages/hive_service/ThriftHive.php';
require_once $GLOBALS['THRIFT_ROOT'] . 'transport/TSocket.php';
require_once $GLOBALS['THRIFT_ROOT'] . 'protocol/TBinaryProtocol.php';

$transport = new TSocket('localhost',  10000);
$protocol = new TBinaryProtocol($transport);
$client = new ThriftHiveClient($protocol);
$transport->open();

$client->execute('SHOW DATABASES');
var_dump($client->fetchAll());
$transport->close();

問題点

ボクとしては、ThriftHiveClientインスタンスをどこか別のクラスで管理してクエリーを投げれば実行してくれるようにして欲しかったので、ThriftHiveClientクラスからコネクションを張りたいというのがありました。

しかし、open関数が実装されているのは TBinaryProtocolクラスです。2つのインスタンスはできれば持ちたくない。面倒くさいし。

コードを見ると、ThriftHiveClientクラスは引数として TBinaryProtocolインスタンスを受け取っています。 じゃあ ThriftHiveClientクラスからもきっとopenメソッド呼べるよねって思いコードを追ってみるとgetTransportメソッドでTBinaryProtocol インスタンスが取得できました。

改良

というわけで、ThriftHiveClientを継承したクラス ThriftHiveClientEx を1発かましてみました。

ThriftHiveClientEx.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?php

/**
 * ThriftHiveClientEx
 *
 * @uses ThriftHiveClient
 * @author noto
 */
class ThriftHiveClientEx extends ThriftHiveClient {


    /**
     *  constructor
     *
     * @param mixed $input TSocket
     * @param mixed $output
     *
     * @return void
     */
    public function __construct($input, $output = null) {
        parent::__construct($input, $output);
    }


    /**
     * connection open
     *
     * @return void
     */
    public function open() {
        if (!$this->input_->getTransport()->isOpen()) {
            $this->input_->getTransport()->open();
        }
    }


    /**
     * connection close
     *
     * @return void
     */
    public function close() {
        if ($this->input_->getTransport()->isOpen()) {
            $this->input_->getTransport()->close();
        }
    }


    /**
     * execute HiveQL
     *
     * @param mixed $query HiveQL
     * @return void
     */
    public function execute($str) {

        // あるクエリーの前に実行したいHQLが存在する為
        // 「;」で区切って連続実行させる
        $queries = preg_split('/;/', $str);

        foreach ($queries as $query) {
            $query = str_replace(array('\r\n', '\n', '\r'),  ' ', $query);
            $query = ltrim($query);
            if ($query == '') return false;

            try {
                parent::execute($query);
            } catch (Exception $e) {
                $msg = $e->getMessage();
                $msg = "HiveExecuteException: Hive実行エラー ${msg}  実行クエリー:: ${query}";
                throw new Exception($msg);
            }
        }
    }
}

解説

openメソッドはTBinaryProtocolのopenメソッドをラップしてコネクションが貼られていない場合張るようにし、closeメソッドも同様にコネクションが破棄されていない場合、破棄するようにしています。

executeメソッドは、Thrift経由でHQLを実行させる際に「;(セミコロン)」があるとエラーになってしまいますが、UDF等使用したい場合は、HiveQLを連続で実行させたいのでセミコロンで分割したものをループさせ実行しています。

またThriftHiveClientクラスのexecuteはエラーが発生した場合、様々な例外を投げつけてくる為 全ての例外を一旦 ThriftHiveClientExで受け取って HiveExecuteException を投げつけてます。HiveExecuteExceptionは適当に実装するなどしてください。

使い方

使い方は、ThriftHiveClientと同じで TBinaryProtocolインスタンスを引数として受け取る必要があります。 ThriftHiveClientEx.php はどこかで requiereなりincludeなりしてください。

ここでは前回のコードと大して変わらないですが、ThriftHiveClientExインスタンスを返却するようなメソッドをかましてあげれば ThriftHiveClientExだけでコネクションの確立から実行までできるので管理はしやすいかなって思ってます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$GLOBALS['THRIFT_ROOT'] = dirname(__FILE__) . '/lib';
require_once $GLOBALS['THRIFT_ROOT'] . '/packages/hive_service/ThriftHive.php';
require_once $GLOBALS['THRIFT_ROOT'] . '/transport/TSocket.php';
require_once $GLOBALS['THRIFT_ROOT'] . '/protocol/TBinaryProtocol.php';

require_once $GLOBALS['THRIFT_ROOT'] . '/ThriftHiveClientEx.php';

$transport = new TSocket('localhost',  10000);
$protocol = new TBinaryProtocol($transport);
$client = new ThriftHiveClientEx($protocol);
$client->open();
$client->execute('SHOW DATABASES');
$client->close();

そろそろカテゴリーを整理整頓しないとまずい。。。

追記

githubにあげました。 php-thrift-hive-client

Comments