bozerkins/clickhouse-client

简单的PHP Clickhouse客户端

v1.1.0 2019-03-16 12:28 UTC

This package is auto-updated.

Last update: 2024-08-29 04:37:11 UTC


README

这是一个简单的Clickhouse客户端版本(使用HTTP接口)。这个版本提供了对HTTP接口的最接近的访问,允许你在PHP应用中最大限度地使用Clickhouse数据库的能力。

CircleCI MIT Licence

安装

使用composer进行基本安装

composer require bozerkins/clickhouse-client

配置

use ClickhouseClient\Client\Config;

$config = new Config(
    // basic connection information
    ['host' => '127.0.0.1', 'port' => '8123', 'protocol' => 'http'],
    // settings
    ['database' => 'default'],
    // credentials
    ['user' => 'default', 'password' => '']
);

您可以在第二个参数中传递额外的设置,包括数据库名称。

完整的设置列表可以在Clickhouse文档的设置部分中找到。

如果您使用默认配置,则不需要定义所有这些设置。

例如,如果您需要创建一个只读访问的客户端对象,请传递 "readonly" 参数。

$config = new Config(
    // basic connection information - set to default
    [],
    // settings
    [ 'database' => 'my_shiny_database', 'readonly' => 1 ]
    // credentials - set to defauult
    []
);

与Clickhouse数据库的通信使用php-curl库。如果您想更紧密地控制查询执行,可以在Config构造函数中传递第四个参数,包含php-curl库的参数。

例如,如果我们想设置5秒的连接超时,我们将创建以下配置

use ClickhouseClient\Client\Config;

$config = new Config(
    // basic connection information - set to default
    [],
    // settings
    [ 'database' => 'my_shiny_database', 'readonly' => 1 ]
    // credentials - set to defauult
    [],
    // additional CURL options
    [ CURLOPT_TIMEOUT => 5 ]
);

支持的常量完整列表可以在curl_setopt函数文档中找到。

您可以在创建配置对象之后定义凭据或设置

use ClickhouseClient\Client\Config;

$config = new Config(
    // basic connection information
    ['host' => '127.0.0.1', 'port' => '8123', 'protocol' => 'http']
);
$config->setUser('user');
$config->setPassword('password');
$config->change('database', 'new-db');

尚未实现更改基本连接信息和curl设置的功能,因为从概念上和技术上讲,更改这些设置应被视为一个新的客户端。

客户端

创建客户端相对简单。

use ClickhouseClient\Client\Client;

$client= new Client($config);

从Clickhouse读取

从Clickhouse读取数据有几种方法。

简单查询

此方法主要用于从Clickhouse获取统计数据、聚合数据。

# perform select
$response = $client->query(
    'SELECT * FROM system.numbers LIMIT 10'
);
# get decoded output - database response
$response->getContent();
# get raw output string - raw string received from clickhouse
$response->getOutput();
# get communication details - curl defails for the request
$response->getDetails();
# and a neat shortcut for getting http response code
$response->getHttpCode();

每个客户端查询返回一个响应,其中包含有关执行连接和响应的所有信息。

将查询数据流入流

可以将数据直接从Clickhouse读取到流中,例如文件。

# create a stream - open a file
$stream = fopen('/tmp/file-to-read-data-into', 'r+');
# query data into the file
$client->queryStream(
    "SELECT * FROM system.numbers LIMIT 5", 
    $stream
);

将查询数据流入闭包(函数可调用)

此方法在您打算将一个Clickhouse响应分割到几个目的地时非常有用。

# open file 1
$file1 = fopen('/tmp/file-to-read-data-into-1', 'r+');
# open file 2
$file2 = fopen('/tmp/file-to-read-data-into-2', 'r+');

# query data, process response with anonymous function
$client->queryClosure(
   "SELECT * FROM system.numbers LIMIT 100", 
   function($line) use ($file1, $file2) {
       $row = json_decode($line);
       if ($row['number'] % 2 === 0) {
           fwrite($file1, $line . PHP_EOL);
       } else {
           fwrite($file2, $line . PHP_EOL);
       }
    }
);

向Clickhouse写入

向数据库写入也有几种方式。

简单插入

写入数据库的最常见方式。

# write data to a table
$client->write('INSERT INTO myTable VALUES (1), (2), (3)');

注意:clickhouse没有像MySQL / Oracle / 等.那样的转义机制。为了安全插入,请参阅其他插入方法。

行插入

将数据安全且容易地插入clickhouse表的最安全和最简单的方法是使用"writeRows"方法。该方法将插入语句的前半部分作为第一个参数,将PHP数组形式的行作为第二个参数。当插入数据时,"writeRows"方法将数据编码为Clickhouse数据库可以解释的适当格式。默认情况下是JSON格式。这种方法不需要显式的转义。

# write data to a table
$client->writeRows('INSERT INTO myTable',
    [
        ['number' => 5],
        ['number' => 6],
        ['number' => 7]
    ]
);

文件插入

另一种插入数据的方式是从文件直接插入。

注意:文件中的数据格式应与clickhouse期望的格式相匹配。

$stream = fopen('my/local/file.lines.json','r');

$client->writeStream(
    'INSERT INTO t',
    $stream
);

此方法实际上不仅接受来自文件的数据,还接受来自任何PHP流资源的数据。因此,我们可以从其他地方导入数据,例如内存(或任何可以表示为流的东西)。

# create memory stream
$stream = fopen('php://memory','r+');
# write some data into it
fwrite($stream, '{"a":8}'.PHP_EOL.'{"a":9}'.PHP_EOL );
# rewind pointer to the beginning
rewind($stream);

# insert the data
$client->writeStream(
    'INSERT INTO t',
    $stream
);

系统查询

客户端对象支持系统查询。此类查询可以管理数据库模式、进程等。

# drop table
$client->system('DROP TABLE IF EXISTS t');
# create table
$client->system('CREATE TABLE IF NOT EXISTS t  (a UInt8) ENGINE = Memory');
# kill query
$client->system('KILL QUERY WHERE query_id = "SOME-QUERY-ID"');

如果在执行操作时失败,客户端将抛出异常。

也可以更改整个客户端的数据库。

# change database
$client->config()->change('database', 'new-database');

它使用与创建“客户端”对象时传递的相同的配置对象,因此此代码也将正常工作。

# create config
$config = new Config();
# create client
$client = new Client($config);
# change database
$config->change('database', 'new-database');

格式

Clickhouse支持几种格式。这些格式用于检索和插入数据。默认格式设置为JSON。当执行简单的选择/插入查询时,数据将被编码为JSON,并在客户端和Clickhouse之间传输。这对于流/闭包查询/写入不适用。当执行任何查询/写入时,您可以通过传递一个类名作为最后一个参数来更改通信格式。

use ClickhouseClient\Client\Format;

# select using default JSON format
$client->query('SELECT * FROM system.numbers LIMIT 5');
# select using TabSeparated format
$client->query('SELECT * FROM system.numbers LIMIT 5', Format\TabSeparatedFormat::class);

# insert usin JSON format
$client->writeRows('INSERT INTO myTable',
    [
        ['number' => 5],
        ['number' => 6],
        ['number' => 7]
    ]
);
# insert usin TabSeparated format
$client->writeRows('INSERT INTO myTable',
    [
        ['number' => 5],
        ['number' => 6],
        ['number' => 7]
    ], 
    Format\TabSeparatedFormat::class
);

# create client with differrent default format
$client = new Client($config, Format\TabSeparatedFormat::class);
# create client without default format (which would result in errors in some cases)
$client = new Client($config, null);

Ping

Clickhouse数据库支持ping方法。

您可以使用客户端的ping方法检查数据库是否正确响应。

$client->ping();

如果出现连接问题,将抛出异常。

异常处理

客户端类发出的任何请求都可能抛出异常。

在执行查询时检查异常是一个好习惯。

use ClickhouseClient\Exception\Exception;

try {
    $client->ping();
} catch (Exception $ex) {
    # get configurations of the connector
    $ex->getConfig();
    # get repsonse 
    $ex->getResponse();
    # and get the message, ofc
    $ex->getMessage();
}

支持

如果库有任何问题,请在GitHub上创建问题,或通过电子邮件联系[email protected]