メインコンテンツへスキップ
メインコンテンツへスキップ

Java クライアント

DBサーバーとそのプロトコルを通じて通信するためのJavaクライアントライブラリ。現在の実装ではHTTPインターフェースのみをサポートしています。 このライブラリは、サーバーへのリクエスト送信用の独自APIを提供します。また、異なるバイナリデータ形式(RowBinary* & Native*)を扱うためのツールも提供します。

セットアップ


<dependency>
    <groupId>com.clickhouse</groupId>
    <artifactId>client-v2</artifactId>
    <version>0.9.4</version>
</dependency>

初期化

Clientオブジェクトはcom.clickhouse.client.api.Client.Builder#build()によって初期化されます。各クライアントは独自のコンテキストを持ち、クライアント間でオブジェクトが共有されることはありません。 Builderには、セットアップを簡単に行うための設定メソッドが用意されています。

例:

 Client client = new Client.Builder()
                .addEndpoint("https://clickhouse-cloud-instance:8443/")
                .setUsername(user)
                .setPassword(password)
                .build();

ClientAutoCloseableであり、不要になった時点で閉じる必要があります。

認証

認証は初期化フェーズでクライアントごとに設定されます。サポートされている認証方式は3つあります: パスワード、アクセストークン、SSL クライアント証明書による認証です。

パスワード認証では、setUsername(String)setPassword(String) を呼び出してユーザー名とパスワードを設定する必要があります:

 Client client = new Client.Builder()
        .addEndpoint("https://clickhouse-cloud-instance:8443/")
        .setUsername(user)
        .setPassword(password)
        .build();

アクセストークンによる認証を行うには、setAccessToken(String) を呼び出してアクセストークンを設定します:

 Client client = new Client.Builder()
        .addEndpoint("https://clickhouse-cloud-instance:8443/")
        .setAccessToken(userAccessToken)
        .build();

SSLクライアント証明書による認証を行うには、setUsername(String)useSSLAuthentication(boolean)setClientCertificate(String)setClientKey(String)を呼び出して、ユーザー名の設定、SSL認証の有効化、クライアント証明書とクライアントキーの設定を行う必要があります:

Client client = new Client.Builder()
        .useSSLAuthentication(true)
        .setUsername("some_user")
        .setClientCertificate("some_user.crt")
        .setClientKey("some_user.key")
注記

SSL認証は、SSLライブラリから出力されるエラーの多くが十分な情報を提供しないため、本番環境でのトラブルシューティングが困難になる場合があります。例えば、クライアント証明書と秘密鍵が一致しない場合、サーバーは即座に接続を切断します(HTTPの場合、HTTPリクエストが送信される前の接続初期化段階で切断されるため、レスポンスは返されません)。

証明書と鍵を検証するには、opensslのようなツールを使用してください:

  • 鍵の整合性を確認します: openssl rsa -in [key-file.key] -check -noout
  • クライアント証明書の CN が対象ユーザーと一致していることを確認:
    • ユーザー証明書から CN を取得します - openssl x509 -noout -subject -in [user.cert]
    • 次のクエリを実行して、同じ値がデータベースに設定されていることを確認します: select name, auth_type, auth_params from system.users where auth_type = 'ssl_certificate'(このクエリでは、auth_params{"common_names":["some_user"]} のような形式で出力されます)

設定

すべての設定はインスタンスメソッド(構成メソッドとも呼ばれる)によって定義され、各値のスコープとコンテキストが明確になります。 主要な構成パラメータは単一のスコープ(クライアントまたはオペレーション)で定義され、相互に上書きされることはありません。

設定はクライアント作成時に定義します。com.clickhouse.client.api.Client.Builderを参照してください。

クライアント構成

MethodArgumentsDescriptionDefaultKey
addEndpoint(String endpoint)endpoint - URL 形式のサーバーアドレス利用可能なサーバーのリストにサーバーエンドポイントを追加します。現在は 1 つのエンドポイントのみがサポートされています。nonenone
addEndpoint(Protocol protocol, String host, int port, boolean secure)protocol - 接続プロトコル
host - IP もしくはホスト名
secure - HTTPS を使用
利用可能なサーバーのリストにサーバーエンドポイントを追加します。現在は 1 つのエンドポイントのみがサポートされています。nonenone
enableConnectionPool(boolean enable)enable - 有効/無効を切り替えるフラグコネクションプールを有効にするかどうかを設定します。trueconnection_pool_enabled
setMaxConnections(int maxConnections)maxConnections - コネクション数各サーバーエンドポイントに対してクライアントが開くことができる接続数の上限を設定します。10max_open_connections
setConnectionTTL(long timeout, ChronoUnit unit)timeout - タイムアウト値
unit - 時間単位
接続が非アクティブと見なされるまでの接続の有効期限 (TTL) を設定します。-1connection_ttl
setKeepAliveTimeout(long timeout, ChronoUnit unit)timeout - タイムアウト値
unit - 時間単位
HTTP 接続の Keep-Alive タイムアウトを設定します。Keep-Alive を無効にするには 0 を設定します。-http_keep_alive_timeout
setConnectionReuseStrategy(ConnectionReuseStrategy strategy)strategy - LIFO または FIFOコネクションプールが使用する接続再利用戦略を選択します。FIFOconnection_reuse_strategy
setDefaultDatabase(String database)database - データベース名デフォルトデータベースを設定します。defaultdatabase

サーバー設定

サーバー側設定は、クライアント作成時に一度クライアントレベルで設定できます(BuilderserverSettingメソッドを参照)。また、操作レベルでも設定できます(操作設定クラスのserverSettingを参照)。

 try (Client client = new Client.Builder().addEndpoint(Protocol.HTTP, "localhost", mockServer.port(), false)
        .setUsername("default")
        .setPassword(ClickHouseServerForTest.getPassword())
        .compressClientRequest(true)

        // Client level
        .serverSetting("max_threads", "10")
        .serverSetting("async_insert", "1")
        .serverSetting("roles", Arrays.asList("role1", "role2"))

        .build()) {

	// Operation level
	QuerySettings querySettings = new QuerySettings();
	querySettings.serverSetting("session_timezone", "Europe/Zurich");

	...
}

⚠️ setOptionメソッド(Client.Builderまたは操作設定クラス)でオプションを設定する場合、サーバー設定名にはclickhouse_setting_のプレフィックスを付ける必要があります。この場合、com.clickhouse.client.api.ClientConfigProperties#serverSetting()を使用すると便利です。

カスタムHTTPヘッダー

カスタムHTTPヘッダーは、すべての操作(クライアントレベル)に対して設定することも、単一の操作(操作レベル)に対して設定することもできます。


QuerySettings settings = new QuerySettings()
    .httpHeader(HttpHeaders.REFERER, clientReferer)
    .setQueryId(qId);

setOptionメソッド(Client.Builderまたは操作設定クラスのいずれか)でオプションを設定する場合、カスタムヘッダー名にはhttp_header_のプレフィックスを付ける必要があります。この場合、com.clickhouse.client.api.ClientConfigProperties#httpHeader()メソッドが役立ちます。

共通定義

ClickHouseFormat

サポートされている形式の列挙型。ClickHouseがサポートするすべての形式を含みます。

  • raw - ユーザーは生データをトランスコードする必要があります
  • full - クライアント側でデータをトランスコードでき、生のデータストリームを受け入れます
  • - - このフォーマットでは ClickHouse がサポートしない操作

このクライアントバージョンは以下をサポートします:

フォーマット入力出力
TabSeparatedrawraw
TabSeparatedRawrawraw
TabSeparatedWithNamesrawraw
TabSeparatedWithNamesAndTypesrawraw
TabSeparatedRawWithNamesrawraw
TabSeparatedRawWithNamesAndTypesrawraw
Templaterawraw
TemplateIgnoreSpacesraw*
CSVrawraw
CSVWithNamesrawraw
CSVWithNamesAndTypesrawraw
CustomSeparatedrawraw
CustomSeparatedWithNamesrawraw
CustomSeparatedWithNamesAndTypesrawraw
SQLInsert-raw
Valuesrawraw
Vertical*raw
JSONrawraw
JSONAsStringraw-
JSONAsObjectraw*
JSONStringsrawraw
JSONColumnsrawraw
JSONColumnsWithMetadataraw未加工
JSONCompactrawraw
JSONCompactStrings-raw
JSONCompactColumnsrawraw
JSONEachRowrawraw
PrettyJSONEachRow*raw
JSONEachRowWithProgress-raw
JSONStringsEachRowrawraw
JSONStringsEachRowWithProgress*raw
JSONCompactEachRowrawraw
JSONCompactEachRowWithNamesrawraw
JSONCompactEachRowWithNamesAndTypesrawraw
JSONCompactStringsEachRowrawraw
JSONCompactStringsEachRowWithNamesrawraw
JSONCompactStringsEachRowWithNamesAndTypesrawraw
JSONObjectEachRowrawraw
BSONEachRowrawraw
TSKVrawraw
Pretty-raw
PrettyNoEscapes*raw
PrettyMonoBlock-raw
PrettyNoEscapesMonoBlock*raw
PrettyCompact-raw
PrettyCompactNoEscapes*raw
PrettyCompactMonoBlock-raw
PrettyCompactNoEscapesMonoBlock*raw
PrettySpace-raw
PrettySpaceNoEscapes*raw
PrettySpaceMonoBlock-raw
PrettySpaceNoEscapesMonoBlock*raw
Prometheus-raw
Protobufrawraw
ProtobufSinglerawraw
ProtobufListrawraw
Avrorawraw
AvroConfluentraw*
Parquetrawraw
ParquetMetadataraw-
Arrowrawraw
ArrowStreamrawraw
ORCrawraw
Oneraw*
Npyraw生データ
RowBinaryfullfull
RowBinaryWithNamesfullfull
RowBinaryWithNamesAndTypesフルフル
RowBinaryWithDefaultsfull-
Nativefull生データ
Null*raw
XML-raw
CapnProtoraw生データ
LineAsStringrawraw
Regexpraw*
RawBLOBrawraw
MsgPackrawraw
MySQLDumpraw-
DWARFraw*
Markdown-未加工
Formraw*

Insert API

insert(String tableName, InputStream data, ClickHouseFormat format)

指定されたフォーマットのバイト列をInputStreamとして受け取ります。dataformatでエンコードされている必要があります。

署名

CompletableFuture<InsertResponse> insert(String tableName, InputStream data, ClickHouseFormat format, InsertSettings settings)
CompletableFuture<InsertResponse> insert(String tableName, InputStream data, ClickHouseFormat format)

パラメータ

tableName - 対象テーブル名。

data - エンコードされたデータの入力ストリーム。

format - データのエンコード形式。

settings - リクエストの設定。

戻り値

InsertResponse 型の Future - 操作結果とサーバー側メトリクスなどの追加情報。

try (InputStream dataStream = getDataStream()) {
    try (InsertResponse response = client.insert(TABLE_NAME, dataStream, ClickHouseFormat.JSONEachRow,
            insertSettings).get(3, TimeUnit.SECONDS)) {

        log.info("Insert finished: {} rows written", response.getMetrics().getMetric(ServerMetrics.NUM_ROWS_WRITTEN).getLong());
    } catch (Exception e) {
        log.error("Failed to write JSONEachRow data", e);
        throw new RuntimeException(e);
    }
}

insert(String tableName, List<?> data, InsertSettings settings)

データベースに書き込みリクエストを送信します。オブジェクトのリストは効率的な形式に変換され、サーバーに送信されます。リストアイテムのクラスは、register(Class, TableSchema) メソッドを使用して事前に登録しておく必要があります。

署名

client.insert(String tableName, List<?> data, InsertSettings settings)
client.insert(String tableName, List<?> data)

パラメータ

tableName - 対象テーブルの名前。

data - DTO(Data Transfer Object)オブジェクトのコレクション。

settings - リクエストの設定。

戻り値

InsertResponse 型の Future - 操作結果とサーバー側メトリクスなどの追加情報。

// Important step (done once) - register class to pre-compile object serializer according to the table schema.
client.register(ArticleViewEvent.class, client.getTableSchema(TABLE_NAME));

List<ArticleViewEvent> events = loadBatch();

try (InsertResponse response = client.insert(TABLE_NAME, events).get()) {
    // handle response, then it will be closed and connection that served request will be released.
}

InsertSettings

挿入操作の構成オプション。

構成方法

メソッド説明
setQueryId(String queryId)操作に割り当てられるクエリ ID を設定します。デフォルト値: null
setDeduplicationToken(String token)重複排除用トークンを設定します。このトークンはサーバーに送信され、クエリを識別するために使用できます。デフォルト: null
setInputStreamCopyBufferSize(int size)コピー用バッファのサイズ。書き込み処理中に、ユーザー提供の入力ストリームから出力ストリームへデータをコピーするために使用されます。デフォルト: 8196
serverSetting(String name, String value)操作に対するサーバーの個別設定を指定します。
serverSetting(String name, Collection values)操作に対して複数の値を取る個別のサーバー設定を指定します。コレクションの要素は String 型の値である必要があります。
setDBRoles(Collection dbRoles)操作の実行前に設定する DB ロールを指定します。コレクションの要素は String 値でなければなりません。
setOption(String option, Object value)生の値として構成オプションを設定します。これはサーバー側の設定ではありません。

InsertResponse

挿入操作の結果を保持するレスポンスオブジェクト。サーバーからレスポンスを受信した場合にのみ利用可能です。

注記

このオブジェクトは接続を解放するため、できるだけ早くクローズする必要があります。前のレスポンスのすべてのデータが完全に読み取られるまで、接続を再利用できないためです。

メソッド説明
OperationMetrics getMetrics()操作メトリクスを保持するオブジェクトを返します。
String getQueryId()アプリケーション(操作設定経由、またはサーバーによって)この操作に割り当てられたクエリ ID を返します。

クエリAPI

query(String sqlQuery)

sqlQueryをそのまま送信します。レスポンス形式はクエリ設定によって設定されます。QueryResponseは、サポートされている形式のリーダーによって消費されるべきレスポンスストリームへの参照を保持します。

署名

CompletableFuture<QueryResponse> query(String sqlQuery, QuerySettings settings)
CompletableFuture<QueryResponse> query(String sqlQuery)

パラメータ

sqlQuery - 単一のSQLステートメント。クエリはそのままサーバーに送信されます。

settings - リクエストの設定。

戻り値

QueryResponse型のFuture - 結果データセットとサーバー側メトリクスなどの追加情報を含みます。データセットの使用後は、Responseオブジェクトをクローズする必要があります。

final String sql = "select * from " + TABLE_NAME + " where title <> '' limit 10";

// Default format is RowBinaryWithNamesAndTypesFormatReader so reader have all information about columns
try (QueryResponse response = client.query(sql).get(3, TimeUnit.SECONDS);) {

    // Create a reader to access the data in a convenient way
    ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);

    while (reader.hasNext()) {
        reader.next(); // Read the next record from stream and parse it

        // get values
        double id = reader.getDouble("id");
        String title = reader.getString("title");
        String url = reader.getString("url");

        // collecting data
    }
} catch (Exception e) {
    log.error("Failed to read data", e);
}

// put business logic outside of the reading block to release http connection asap.

query(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings)

sqlQueryをそのまま送信します。加えて、サーバーがSQL式をコンパイルできるように、クエリパラメータも送信します。

署名

CompletableFuture<QueryResponse> query(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings)

パラメータ

sqlQuery - プレースホルダー {} を含むSQL式。

queryParams - サーバー上でSQL式を完成させるための変数マップ。

settings - リクエストの設定。

戻り値

QueryResponse型のFuture - 結果データセットとサーバー側メトリクスなどの追加情報を含みます。データセットの使用後は、Responseオブジェクトをクローズする必要があります。


// define parameters. They will be sent to the server along with the request.
Map<String, Object> queryParams = new HashMap<>();
queryParams.put("param1", 2);

try (QueryResponse response =
        client.query("SELECT * FROM " + table + " WHERE col1 >= {param1:UInt32}", queryParams, new QuerySettings()).get()) {

    // Create a reader to access the data in a convenient way
    ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);

    while (reader.hasNext()) {
        reader.next(); // Read the next record from stream and parse it

        // reading data
    }

} catch (Exception e) {
    log.error("Failed to read data", e);
}

queryAll(String sqlQuery)

RowBinaryWithNamesAndTypes形式でデータをクエリします。結果はコレクションとして返されます。読み取りパフォーマンスはリーダーと同じですが、データセット全体を保持するためにより多くのメモリが必要になります。

署名

List<GenericRecord> queryAll(String sqlQuery)

パラメータ

sqlQuery - サーバーからデータをクエリするためのSQL式。

戻り値

結果データに行単位でアクセスできるGenericRecordオブジェクトのリストで表現される完全なデータセット。

try {
    log.info("Reading whole table and process record by record");
    final String sql = "select * from " + TABLE_NAME + " where title <> ''";

    // Read whole result set and process it record by record
    client.queryAll(sql).forEach(row -> {
        double id = row.getDouble("id");
        String title = row.getString("title");
        String url = row.getString("url");

        log.info("id: {}, title: {}, url: {}", id, title, url);
    });
} catch (Exception e) {
    log.error("Failed to read data", e);
}

QuerySettings

クエリ操作の設定オプション。

構成方法

メソッド説明
setQueryId(String queryId)操作に割り当てるクエリ ID を設定します。
setFormat(ClickHouseFormat format)レスポンス形式を設定します。利用可能な形式の完全な一覧については RowBinaryWithNamesAndTypes を参照してください。
setMaxExecutionTime(Integer maxExecutionTime)サーバー側での操作の最大実行時間を設定します。読み取りタイムアウトには影響しません。
waitEndOfQuery(Boolean waitEndOfQuery)レスポンスを返す前にクエリの終了を待機するようサーバーに要求します。
setUseServerTimeZone(Boolean useServerTimeZone)サーバーのタイムゾーン(クライアント側の設定を参照)が、操作結果内の日付/時刻型のパースに使用されます。デフォルトは false です。
setUseTimeZone(String timeZone)サーバーに対して、時刻変換に timeZone を使用するよう要求します。session_timezone を参照してください。
serverSetting(String name, String value)操作ごとに個別のサーバー設定を行います。
serverSetting(String name, Collection values)操作時に複数の値を持つ個々のサーバー設定を構成します。コレクションの各要素は String 値である必要があります。
setDBRoles(Collection dbRoles)操作を実行する前に有効化する DB ロールを設定します。コレクションの要素は String 値である必要があります。
setOption(String option, Object value)生形式で構成オプションを設定します。これはサーバー設定ではありません。

QueryResponse

クエリ実行結果を保持するレスポンスオブジェクト。クライアントがサーバーからレスポンスを受信した場合にのみ利用可能です。

注記

このオブジェクトは接続を解放するため、できるだけ早くクローズする必要があります。前のレスポンスのすべてのデータが完全に読み取られるまで、接続を再利用できないためです。

メソッド説明
ClickHouseFormat getFormat()レスポンスデータのエンコード形式を返します。
InputStream getInputStream()指定された形式の非圧縮データのバイトストリームを返します。
OperationMetrics getMetrics()操作メトリクスを表すオブジェクトを返します。
String getQueryId()アプリケーション(操作設定またはサーバー)によってこの操作に割り当てられたクエリ ID を返します。
TimeZone getTimeZone()レスポンス内の Date/DateTime 型を処理する際に使用するタイムゾーンを返します。

共通 API

getTableSchema(String table)

tableのテーブルスキーマを取得します。

署名

TableSchema getTableSchema(String table)
TableSchema getTableSchema(String table, String database)

パラメータ

table - スキーマデータを取得するテーブル名。

database - 対象テーブルが定義されているデータベース。

戻り値

テーブルカラムのリストを含むTableSchemaオブジェクトを返します。

getTableSchemaFromQuery(String sql)

SQL文からスキーマを取得します。

署名

TableSchema getTableSchemaFromQuery(String sql)

パラメータ

sql - スキーマを返す"SELECT" SQLステートメント。

戻り値

sql式に一致するカラムを含むTableSchemaオブジェクトを返します。

TableSchema

register(Class<?> clazz, TableSchema schema)

Java クラスが schema を使用してデータの書き込み/読み取りを行うためのシリアライゼーションおよびデシリアライゼーション層をコンパイルします。このメソッドは、getter/setter のペアと対応するカラムに対してシリアライザーとデシリアライザーを作成します。 カラムの一致は、メソッド名から名前を抽出することで検出されます。例えば、getFirstName は カラム first_name または firstname に対応します。

署名

void register(Class<?> clazz, TableSchema schema)

パラメータ

clazz - データの読み書きに使用するPOJOを表すクラス。

schema - POJOプロパティとのマッチングに使用するデータスキーマ。

client.register(ArticleViewEvent.class, client.getTableSchema(TABLE_NAME));

使用例

完全なサンプルコードは、リポジトリの example フォルダに格納されています:

  • client-v2 - 主要なサンプル一式です。
  • demo-service - Spring Boot アプリケーションにおけるクライアント利用例。
  • demo-kotlin-service - Ktor(Kotlin)アプリケーションにおけるクライアントの使用例です。

移行ガイド

旧クライアント(V1)はcom.clickhouse.client.ClickHouseClient#builderを開始点として使用していました。新クライアント(V2)はcom.clickhouse.client.api.Client.Builderを使用した同様のパターンを採用しています。主な相違点は以下の通りです:

  • 実装を取得するために service loader は使用しません。com.clickhouse.client.api.Client は、将来的にあらゆる種類の実装を扱うためのファサードクラスです。
  • 構成情報のソースが少なくなりました。1つはビルダーに渡されるもので、もう1つは操作設定(QuerySettingsInsertSettings)です。以前のバージョンではノードごとの構成があり、場合によっては環境変数を読み込んでいました。

設定パラメータの一致

V1には、設定に関連する3つの列挙型クラスがあります:

  • com.clickhouse.client.config.ClickHouseDefaults - ほとんどのユースケースで設定されることを想定したパラメータです。例えば USERPASSWORD などがあります。
  • com.clickhouse.client.config.ClickHouseClientOption - クライアント専用の設定パラメータで、HEALTH_CHECK_INTERVAL などがあります。
  • com.clickhouse.client.http.config.ClickHouseHttpOption - HTTP インターフェイスに固有の設定パラメータ(例:RECEIVE_QUERY_PROGRESS)。

これらはパラメータをグループ化し、明確に分離するように設計されていました。しかし、場合によっては混乱を招くことがありました(com.clickhouse.client.config.ClickHouseDefaults#ASYNCcom.clickhouse.client.config.ClickHouseClientOption#ASYNCの間に違いはあるのか)。 新しいV2クライアントは、すべてのクライアント設定オプションを格納する単一のDictionaryとしてcom.clickhouse.client.api.Client.Builderを使用します。すべての設定パラメータ名がリストされているcom.clickhouse.client.api.ClientConfigPropertiesが存在します。

以下の表は、新しいクライアントでサポートされている旧オプションと、その新しい意味を示しています。

凡例: ✔ = サポート、✗ = 非サポート

V1 設定値V2 Builder メソッドコメント
ClickHouseDefaults#HOSTClient.Builder#addEndpoint
ClickHouseDefaults#PROTOCOLV2 では HTTP のみをサポート
ClickHouseDefaults#DATABASE
ClickHouseClientOption#DATABASE
Client.Builder#setDefaultDatabase
ClickHouseDefaults#USERClient.Builder#setUsername
ClickHouseDefaults#PASSWORDClient.Builder#setPassword
ClickHouseClientOption#CONNECTION_TIMEOUTClient.Builder#setConnectTimeout
ClickHouseClientOption#CONNECTION_TTLClient.Builder#setConnectionTTL
ClickHouseHttpOption#MAX_OPEN_CONNECTIONSClient.Builder#setMaxConnections
ClickHouseHttpOption#KEEP_ALIVE
ClickHouseHttpOption#KEEP_ALIVE_TIMEOUT
Client.Builder#setKeepAliveTimeout
ClickHouseHttpOption#CONNECTION_REUSE_STRATEGYClient.Builder#setConnectionReuseStrategy
ClickHouseHttpOption#USE_BASIC_AUTHENTICATIONClient.Builder#useHTTPBasicAuth

一般的な違い

  • Client V2 は移植性を高めるために、プロプライエタリなクラスへの依存を減らしています。たとえば、V2 はサーバーにデータを書き込む際に、任意の java.io.InputStream の実装と連携して動作します。
  • Client V2 の async 設定はデフォルトで off です。これは追加のスレッドを起動せず、アプリケーションからクライアントをより細かく制御できることを意味します。この設定は、ほとんどのユースケースでは off のままにしておくことを推奨します。async を有効にすると、リクエストごとに専用のスレッドが作成されます。これは、アプリケーション側で制御される executor を使用する場合にのみ有用です(com.clickhouse.client.api.Client.Builder#setSharedOperationExecutor を参照)。

データの書き込み

  • 任意の実装の java.io.InputStream を使用できます。V1 の com.clickhouse.data.ClickHouseInputStream もサポートされていますが、非推奨です。
  • 入力ストリームの終端が検出されると、適切に処理されます。その前に、リクエストの出力ストリームをクローズしておく必要があります。

V1 TSV形式データの挿入。

InputStream inData = getInData();
ClickHouseRequest.Mutation request = client.read(server)
        .write()
        .table(tableName)
        .format(ClickHouseFormat.TSV);
ClickHouseConfig config = request.getConfig();
CompletableFuture<ClickHouseResponse> future;
try (ClickHousePipedOutputStream requestBody = ClickHouseDataStreamFactory.getInstance()
        .createPipedOutputStream(config)) {
    // start the worker thread which transfer data from the input into ClickHouse
    future = request.data(requestBody.getInputStream()).execute();

    // Copy data from inData stream to requestBody stream

    // We need to close the stream before getting a response
    requestBody.close();

    try (ClickHouseResponse response = future.get()) {
        ClickHouseResponseSummary summary = response.getSummary();
        Assert.assertEquals(summary.getWrittenRows(), numRows, "Num of written rows");
    }
}

V2 TSV形式データの挿入。

InputStream inData = getInData();
InsertSettings settings = new InsertSettings().setInputStreamCopyBufferSize(8198 * 2); // set copy buffer size
try (InsertResponse response = client.insert(tableName, inData, ClickHouseFormat.TSV, settings).get(30, TimeUnit.SECONDS)) {

  // Insert is complete at this point

} catch (Exception e) {
 // Handle exception
}
  • 呼び出すメソッドは 1 つだけで、追加のリクエストオブジェクトを作成する必要はありません。
  • すべてのデータのコピーが完了すると、リクエストボディのストリームは自動的にクローズされます。
  • 新しい低レベル API com.clickhouse.client.api.Client#insert(java.lang.String, java.util.List<java.lang.String>, com.clickhouse.client.api.DataStreamWriter, com.clickhouse.data.ClickHouseFormat, com.clickhouse.client.api.insert.InsertSettings) が利用可能です。com.clickhouse.client.api.DataStreamWriter は独自のデータ書き込みロジックを実装できるように設計されています。たとえば、キューからデータを読み取るといった用途に利用できます。

データの読み取り

  • データは既定で RowBinaryWithNamesAndTypes フォーマットで読み込まれます。現在、データバインディングが必要な場合にサポートされているのはこのフォーマットのみです。
  • データは、List<GenericRecord> com.clickhouse.client.api.Client#queryAll(java.lang.String) メソッドを使用して、レコードのコレクションとして読み取ることができます。このメソッドはデータをメモリ上に読み込み、接続を解放します。追加の処理は不要です。GenericRecord はデータへのアクセスを提供し、一部の変換処理を実装しています。
Collection<GenericRecord> records = client.queryAll("SELECT * FROM table");
for (GenericRecord record : records) {
    int rowId = record.getInteger("rowID");
    String name = record.getString("name");
    LocalDateTime ts = record.getLocalDateTime("ts");
}

DBサーバーとそのプロトコルを通じて通信するためのJavaクライアントライブラリ。現在の実装ではHTTPインターフェースのみをサポートしています。このライブラリは、サーバーへのリクエスト送信用の独自APIを提供します。

非推奨

このライブラリは間もなく非推奨になります。新規プロジェクトには最新のJava クライアントを使用してください

セットアップ

<!-- https://mvnrepository.com/artifact/com.clickhouse/clickhouse-http-client -->
<dependency>
    <groupId>com.clickhouse</groupId>
    <artifactId>clickhouse-http-client</artifactId>
    <version>0.7.2</version>
</dependency>

バージョン 0.5.0 以降、ドライバは新しいクライアント HTTP ライブラリを使用するため、依存関係として追加する必要があります。

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5 -->
<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.3.1</version>
</dependency>

初期化

接続URL形式: protocol://host[:port][/database][?param[=value][&param[=value]][#tag[,tag]]、例:

単一ノードに接続する:

ClickHouseNode server = ClickHouseNode.of("http://localhost:8123/default?compress=0");

複数ノードのクラスタに接続する:

ClickHouseNodes servers = ClickHouseNodes.of(
    "jdbc:ch:http://server1.domain,server2.domain,server3.domain/my_db"
    + "?load_balancing_policy=random&health_check_interval=5000&failover=2");

クエリAPI

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from numbers limit :limit")
        .params(1000)
        .executeAndWait()) {
            ClickHouseResponseSummary summary = response.getSummary();
            long totalRows = summary.getTotalRowsToRead();
}

ストリーミングクエリAPI

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from numbers limit :limit")
        .params(1000)
        .executeAndWait()) {
            for (ClickHouseRecord r : response.records()) {
            int num = r.getValue(0).asInteger();
            // type conversion
            String str = r.getValue(0).asString();
            LocalDate date = r.getValue(0).asDate();
        }
}

リポジトリ内の完全なコード例を参照してください。

Insert API


try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers).write()
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("insert into my_table select c2, c3 from input('c1 UInt8, c2 String, c3 Int32')")
        .data(myInputStream) // `myInputStream` is source of data in RowBinary format
        .executeAndWait()) {
            ClickHouseResponseSummary summary = response.getSummary();
            summary.getWrittenRows();
}

リポジトリ内の完全なコード例を参照してください。

RowBinaryエンコーディング

RowBinary形式の詳細は、こちらのページを参照してください。

コードの例を参照してください。

機能

圧縮

クライアントはデフォルトでLZ4圧縮を使用します。これには以下の依存関係が必要です:

<!-- https://mvnrepository.com/artifact/org.lz4/lz4-java -->
<dependency>
    <groupId>org.lz4</groupId>
    <artifactId>lz4-java</artifactId>
    <version>1.8.0</version>
</dependency>

接続URLにcompress_algorithm=gzipを設定することで、代わりにgzipを使用できます。

あるいは、圧縮を無効化する方法がいくつかあります。

  1. 接続URLで compress=0 を設定して無効化します: http://localhost:8123/default?compress=0
  2. クライアント設定で無効化する:
ClickHouseClient client = ClickHouseClient.builder()
   .config(new ClickHouseConfig(Map.of(ClickHouseClientOption.COMPRESS, false)))
   .nodeSelector(ClickHouseNodeSelector.of(ClickHouseProtocol.HTTP))
   .build();

各種圧縮オプションの詳細については、圧縮ドキュメントを参照してください。

複数のクエリ

同一セッション内でワーカースレッドにて複数のクエリを順次実行する:

CompletableFuture<List<ClickHouseResponseSummary>> future = ClickHouseClient.send(servers.apply(servers.getNodeSelector()),
    "create database if not exists my_base",
    "use my_base",
    "create table if not exists test_table(s String) engine=Memory",
    "insert into test_table values('1')('2')('3')",
    "select * from test_table limit 1",
    "truncate table test_table",
    "drop table if exists test_table");
List<ClickHouseResponseSummary> results = future.get();

名前付きパラメータ

パラメータリスト内の位置に依存せず、名前でパラメータを渡すことができます。この機能は params 関数を使用して利用可能です。

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from my_table where name=:name limit :limit")
        .params("Ben", 1000)
        .executeAndWait()) {
            //...
        }
}
パラメータ

String型を含むすべてのparamsシグネチャ(StringString[]Map<String, String>)は、渡されるキーが有効なClickHouse SQL文字列であることを前提としています。例えば:

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from my_table where name=:name")
        .params(Map.of("name","'Ben'"))
        .executeAndWait()) {
            //...
        }
}

String オブジェクトを手動で ClickHouse SQL に解析したくない場合は、com.clickhouse.data に配置されているヘルパー関数 ClickHouseValues.convertToSqlExpression を使用できます:

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from my_table where name=:name")
        .params(Map.of("name", ClickHouseValues.convertToSqlExpression("Ben's")))
        .executeAndWait()) {
            //...
        }
}

上記の例では、ClickHouseValues.convertToSqlExpressionが内部のシングルクォートをエスケープし、変数を有効なシングルクォートで囲みます。

IntegerUUIDArrayEnum などのその他の型は、params 内で自動的に変換されます。

ノードディスカバリー

JavaクライアントはClickHouseノードを自動検出する機能を提供します。自動検出はデフォルトで無効になっています。手動で有効にするには、auto_discoverytrueに設定します:

properties.setProperty("auto_discovery", "true");

または接続URLで指定します:

jdbc:ch://my-server/system?auto_discovery=true

自動検出が有効になっている場合、接続URLにすべてのClickHouseノードを指定する必要はありません。URLに指定されたノードはシードとして扱われ、Javaクライアントはシステムテーブルおよび/またはclickhouse-keeperやzookeeperから追加のノードを自動的に検出します。

以下のオプションは自動検出の設定を担当します:

プロパティデフォルト値説明
auto_discoveryfalseクライアントが system テーブルおよび/または clickhouse-keeper/zookeeper から追加ノードを検出するかどうか。
node_discovery_interval0ノード検出の間隔(ミリ秒)。0 または負の値を指定すると一度だけ検出を行います。
node_discovery_limit100同時に検出できるノードの最大数。ゼロ以下の値を指定した場合は上限なしを意味します。

ロードバランシング

Javaクライアントは、負荷分散ポリシーに従ってリクエストの送信先となるClickHouseノードを選択します。一般的に、負荷分散ポリシーは以下の処理を担当します:

  1. マネージドノードの一覧からノードを取得します。
  2. ノードの状態を管理する。
  3. (自動ディスカバリが有効な場合)ノードディスカバリ用のバックグラウンドプロセスを必要に応じてスケジュールし、ヘルスチェックを実行します。

ロードバランシングを設定するオプションの一覧:

プロパティデフォルト説明
load_balancing_policy""ロードバランシングポリシーとして指定できる値は次のとおりです:
  • firstAlive - リクエストは、管理対象ノードリストの最初の正常なノードに送信されます
  • random - リクエストは、管理対象ノードリストからランダムに選択されたノードに送信されます
  • roundRobin - リクエストは、管理対象ノードリスト内の各ノードに順番に送信されます
  • ClickHouseLoadBalancingPolicy を実装する完全修飾クラス名 - カスタムのロードバランシングポリシー
  • ポリシーが指定されていない場合、リクエストは管理対象ノードリストの最初のノードに送信されます
    load_balancing_tags""ノードを絞り込むためのロードバランシングタグ。リクエストは指定したタグを持つノードにのみ送信されます
    health_check_interval0ヘルスチェックの間隔をミリ秒単位で指定します。0 以下の値は 1 回のみ実行することを意味します。
    health_check_methodClickHouseHealthCheckMethod.SELECT_ONEヘルスチェックの方式。次のいずれかを指定できます:
  • ClickHouseHealthCheckMethod.SELECT_ONE - select 1 クエリを用いてチェック
  • ClickHouseHealthCheckMethod.PING - プロトコル固有のチェックで、一般的により高速です
  • node_check_interval0ノードチェック間隔(ミリ秒単位)。負の値は 0 として扱われます。前回のチェックから指定した時間が経過している場合にノードのステータスがチェックされます。
    health_check_intervalnode_check_interval の違いは、health_check_interval オプションがノード(全ノードまたは障害ノード)のリストに対してステータスをチェックするバックグラウンドジョブをスケジューリングするのに対し、node_check_interval は特定のノードについて前回のチェックから経過していなければならない時間を指定する点です
    check_all_nodesfalseすべてのノードを対象にヘルスチェックを行うか、障害が発生しているノードのみを対象にするかを指定します。

    フェイルオーバーとリトライ

    Javaクライアントは、失敗したクエリのフェイルオーバーおよびリトライ動作を設定するための構成オプションを提供します:

    プロパティデフォルト値説明
    failover01 つのリクエストに対して許可されるフェイルオーバーの最大回数。0 または負の値の場合は、フェイルオーバーは行われません。フェイルオーバーでは、障害から復旧するために、失敗したリクエストを(負荷分散ポリシーに従って)別のノードに送信します。
    retry01つのリクエストに対してリトライできる最大回数。0 または負の値の場合はリトライを行いません。リトライでは、ClickHouse サーバーが NETWORK_ERROR エラーコードを返した場合にのみ、同じノードに対してリクエストを再送信します
    repeat_on_session_locktrueセッションがロックされている間、session_timeout または connect_timeout に従ってタイムアウトに達するまで実行を繰り返すかどうか。ClickHouse サーバーが SESSION_IS_LOCKED エラーコードを返した場合、失敗したリクエストは再試行されます

    カスタムHTTPヘッダーの追加

    Javaクライアントは、リクエストにカスタムHTTPヘッダーを追加したい場合、HTTP/Sトランスポート層をサポートしています。 custom_http_headersプロパティを使用してください。ヘッダーは,で区切り、ヘッダーのキーと値は=で区切る必要があります。

    Javaクライアントのサポート

    options.put("custom_http_headers", "X-ClickHouse-Quota=test, X-ClickHouse-Test=test");
    

    JDBC ドライバー

    properties.setProperty("custom_http_headers", "X-ClickHouse-Quota=test, X-ClickHouse-Test=test");