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

Java クライアント

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

セットアップ

<dependency>
  <groupId>com.clickhouse</groupId>
  <artifactId>client-v2</artifactId>
  <version>0.9.8</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"]} のような値が出力されます)

設定

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

設定はクライアントの作成時に定義されます。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

クライアントの識別

クエリログには、リクエストの発信元アプリケーションを識別するフィールドが2つあります: client_namehttp_user_agent。ネイティブTCPプロトコルではアプリケーション識別に client_name を使用し、HTTPプロトコルでは http_user_agent を使用します。クライアントビルダーには両プロトコルに対して正しい値を設定する setClientName メソッドがあります。 http_user_agent フィールドは User-Agent ヘッダーの一般的な形式に従って設定されます: application-name[/version] [(operating-system; architecture; ...)]。 この値のセットはアプリケーション、クライアントライブラリ、HTTPクライアントライブラリの各レイヤーごとに繰り返されます。setClientName メソッドで設定されたものがリストの先頭に来ます。

例:

client.setClientName("my-app-01/1.0");

これにより、次の http_user_agent 値が生成されます:

my-app-01/1.0 clickhouse-java-v2/0.9.6-SNAPSHOT (Linux; jvm:17.0.17) Apache-HttpClient/5.4.4

アプリケーションは自身を識別するために独自のHTTPヘッダー User-Agent を設定できます。ただし、clickhouse-java-v2/0.9.6-SNAPSHOT の部分がヘッダーの末尾に追加されます。

操作識別

クエリログには、操作を識別しクエリログに追加情報を付加するために使用できる query_idlog_comment という2つのフィールドがあります。

query_id は操作の一意の識別子です。アプリケーションが QuerySettings クラスの setQueryId メソッドを呼び出すことで設定できます。

QuerySettings querySettings = new QuerySettings();
querySettings.setQueryId("some-query-id");

log_comment はクエリログに追加できるコメントです。QuerySettings クラスの logComment メソッドを呼び出すことで、アプリケーションから設定できます。

QuerySettings querySettings = new QuerySettings();
querySettings.logComment("some-comment");

サーバー設定

サーバー側の設定は、クライアント作成時の初期化フェーズに一度だけクライアントレベルで設定できます (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

サポートされている形式の列挙型 (Enum) です。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
JSONColumnsWithMetadatarawraw
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-
Npyrawraw
RowBinaryfullfull
RowBinaryWithNamesfullfull
RowBinaryWithNamesAndTypesfullfull
RowBinaryWithDefaultsfull-
Nativefullraw
Null-raw
XML-raw
CapnProtorawraw
LineAsStringrawraw
Regexpraw-
RawBLOBrawraw
MsgPackrawraw
MySQLDumpraw-
DWARFraw-
Markdown-raw
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

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

設定メソッド

MethodDescription
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)操作に対して、1 つのサーバー設定に複数の値を設定します。コレクションの要素は 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 型を処理する際に使用すべきタイムゾーンを返します。

  • サンプルコードはリポジトリで公開されています
  • Spring サービスの実装を参照してください

共通 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) アプリケーションでクライアントを使用する方法のサンプルです。

データの読み込み

データを読み込む一般的な方法は2つあります。

  • query() メソッドは、データを含む InputStream を保持する低レベルな QueryResponse オブジェクトを返します。通常はストリーミング読み取りのために ClickHouseBinaryFormatReader と組み合わせて使用されますが、 他の任意のカスタムリーダー実装でも利用できます。QueryResponse は、結果セットのメタデータおよびメトリクスへのアクセスも提供します。
  • queryAll() メソッドと GenericRecord を使用すると、行単位で結果にアクセスできます。この場合、結果セット全体がメモリに読み込まれます。
  • queryRecords() メソッドは com.clickhouse.client.api.query.Records を返し、これは GenericRecord オブジェクトのイテレータです。このメソッドはストリーミング方式で動作するため (データはメモリにロードされません) 、GenericRecord を利用してデータにアクセスします。

注意: ストリーミング方式ではデータをネットワークストリームから直接読み取るため、高速に読み取る必要があります。そうでない場合、サーバー側の書き込みタイムアウトが発生する可能性があります。

配列の読み込み

ClickHouseBinaryFormatReader メソッド

  • getList(...) - 任意の Array(...)List<T> として読み取ります。柔軟に型を扱う読み取りのデフォルトとして適しています。ネストされた配列をサポートします。
  • getByteArray(...), getShortArray(...), getIntArray(...), getLongArray(...), getFloatArray(...), getDoubleArray(...), getBooleanArray(...) - プリミティブ型と互換性のある値からなる一次元配列に最適です。
  • getStringArray(...) - Array(String) 型 (および名前で表される enum 値) 用。
  • getObjectArray(...) - ネストされた配列を含む任意の Array(...) 要素型に対応する汎用的なオプションです。Nullable な値やネストされた配列を含む配列を読み取るために使用します。

すべてのメソッドに対して、インデックスベースと名前ベースのオーバーロードが利用可能です。インデックスは1始まりです。インデックスベースのメソッドはカラムへ直接アクセスします。 名前ベースのメソッドは、毎回インデックスの検索が必要です。

try (QueryResponse response = client.query("SELECT * FROM my_table").get()) {
    ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);
    while (reader.next() != null) {

        Object[] uint64 = reader.getObjectArray("uint64_arr"); // Array(UInt64) -> BigInteger[]
        Object[] arr2d = reader.getObjectArray("arr2d");       // Array(Array(Int64)) -> Object[]

        // nested arrays are returned as nested Object[]:
        Object[] firstInner = (Object[]) arr2d[0];
        Long firstValue = (Long) firstInner[0];
    }
}

GenericRecord のメソッド

  • getList(...) - 任意の Array(...)List<T> として読み取ります。柔軟な型付き読み取りのデフォルトとして適しています。ネストされた配列をサポートします。
  • getByteArray(...), getShortArray(...), getIntArray(...), getLongArray(...), getFloatArray(...), getDoubleArray(...), getBooleanArray(...) - プリミティブ型互換の値で構成された一次元配列に最適です。
  • getStringArray(...) - Array(String) 型 (および名前で表される enum 値) 向け。
  • getObjectArray(...) - ネストされた配列を含む任意の Array(...) 要素型に対応する汎用的なオプションです。Nullable な値やネストされた配列を含む配列を読み取るために使用します。

すべてのメソッドに対して、インデックスベースと名前ベースのオーバーロードが利用可能です。インデックスは1始まりです。インデックスベースのメソッドはカラムへ直接アクセスします。 名前ベースのメソッドは、毎回インデックスの検索が必要です。

try (QueryResponse response = client.query("SELECT * FROM my_table").get()) {
    List<GenericRecord> rows = client.queryAll(
        "SELECT int_arr, arr2d_nullable FROM test_arrays ORDER BY id");

    for (GenericRecord row : rows) {
        Object[] intArr = row.getObjectArray("int_arr");                 // Array(Int32) -> Integer[]
        Object[] arr2d = row.getObjectArray("arr2d_nullable");           // Array(Array(Nullable(Int32)))

        Object[] inner = (Object[]) arr2d[0];
        Object maybeNull = inner[1]; // may be null
    }
}

移行ガイド

Old client (V1) was using com.clickhouse.client.ClickHouseClient#builder as start point. The new client (V2) uses similar pattern with com.clickhouse.client.api.Client.Builder. Main differences are:

  • 実装の取得に ServiceLoader は使用されません。com.clickhouse.client.api.Client は、将来的にさまざまな実装に対応するためのファサードクラスです。
  • 設定のソースが少なくなりました。1 つは builder に渡され、もう 1 つは操作設定 (QuerySettings, InsertSettings) に含まれます。以前のバージョンではノードごとの設定があり、場合によっては 環境変数も読み込んでいました。

設定パラメータの対応

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 クライアントでは、com.clickhouse.client.api.Client.Builder がすべてのクライアント設定オプションの単一の辞書として機能します。すべての設定パラメータ名は com.clickhouse.client.api.ClientConfigProperties に一覧されています。

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

凡例: ✔ = サポート済み、✗ = 廃止

V1 ConfigurationV2 Builder MethodComments
ClickHouseDefaults#HOSTClient.Builder#addEndpoint
ClickHouseDefaults#PROTOCOLOnly HTTP supported in V2
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]]。例:

  • http://localhost:8443?ssl=true&sslmode=NONE
  • https://(https://explorer@play.clickhouse.com:443

単一ノードに接続する:

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 型 (StringString[]Map<String, String>) を含むすべての params シグネチャは、渡されるキーが有効な 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クライアントはsystem テーブルおよび/または clickhouse-keeper や zookeeper から追加のノードを自動的に検出します。

以下のオプションは自動検出の設定に使用します:

プロパティデフォルト説明
auto_discoveryfalseクライアントが system テーブルや clickhouse-keeper/zookeeper から追加のノードを検出するかどうか。
node_discovery_interval0ノード検出の間隔 (ミリ秒単位) 。0 以下の値は一度限りの検出を意味します。
node_discovery_limit100一度に検出できるノード数の上限。値が 0 以下の場合は上限なしを意味します。

負荷分散

Javaクライアントは、負荷分散ポリシーに従ってどのClickHouseノードにリクエストを送信するかを選択します。一般に、負荷分散ポリシーは次のような役割を担います。

  1. 管理対象ノードの一覧からノードを1つ取得します。
  2. ノードの状態を管理します。
  3. 必要に応じてノードディスカバリ用のバックグラウンドプロセスをスケジュールし、ヘルスチェックを実行します。

ロードバランシングを設定するためのオプションは次のとおりです:

プロパティデフォルト説明
load_balancing_policy""ロードバランシングポリシーとして指定できる値は次のいずれかです:
  • firstAlive - リクエストは管理対象ノードのリスト内で最初に見つかった正常なノードに送信されます
  • random - リクエストは管理対象ノードのリストからランダムに選択されたノードに送信されます
  • roundRobin - リクエストは管理対象ノードのリスト内の各ノードに順番に送信されます
  • ClickHouseLoadBalancingPolicy を実装する完全修飾クラス名 - カスタムのロードバランシングポリシー
  • ポリシーが指定されていない場合、リクエストは管理対象ノードのリストの最初のノードに送信されます。
    load_balancing_tags""ノードを絞り込むためのロードバランシング用タグ。リクエストは指定したタグを持つノードにのみ送信されます。
    health_check_interval0ヘルスチェックの間隔をミリ秒単位で指定します。0 以下の値は一度だけ実行されることを意味します。
    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 クライアントは、失敗したクエリに対するフェイルオーバーおよびリトライの動作を設定するための設定オプションを提供します:

    プロパティデフォルト説明
    failover0リクエストに対してフェイルオーバーが発生できる最大回数。ゼロまたは負の値はフェイルオーバーなしを意味します。フェイルオーバーは、失敗したリクエストを別のノード (負荷分散ポリシーに従って) に送信し、フェイルオーバーから回復します。
    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");