Skip to content

Commit

Permalink
added initial version of client v2 example
Browse files Browse the repository at this point in the history
  • Loading branch information
chernser committed May 23, 2024
1 parent bfc4c60 commit b5a9359
Show file tree
Hide file tree
Showing 7 changed files with 385 additions and 0 deletions.
26 changes: 26 additions & 0 deletions examples/client-v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Client V2 Example

## Overview

This example demonstrates how to use the client V2 to interact with the


## How to Run

Apache Maven or IDE with Maven support is required to run this example.

First we need to compile the example :
```shell
mvn clean compile
```

To run:
```shell
mvn exec:java -Dexec.mainClass="com.clickhouse.examples.client_v2.Main"
```

Addition options can be passed to the application:
- `-DchEndpoint` - Endpoint to connect in the format of URL (default: http://localhost:8123/)
- `-DchUser` - ClickHouse user name (default: default)
- `-DchPassword` - ClickHouse user password (default: empty)
- `-DchDatabase` - ClickHouse database name (default: default)
147 changes: 147 additions & 0 deletions examples/client-v2/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>

<groupId>com.clickhouse</groupId>
<artifactId>java-client-examples</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>

<name>java-client-examples</name>
<description>Java Client Examples</description>
<url>https://github.com/ClickHouse/clickhouse-java</url>
<inceptionYear>2022</inceptionYear>

<organization>
<name>ClickHouse, Inc.</name>
<url>https://clickhouse.com/</url>
</organization>

<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>

<scm>
<url>https://github.com/ClickHouse/clickhouse-java</url>
<connection>scm:[email protected]:ClickHouse/clickhouse-java.git</connection>
<developerConnection>scm:[email protected]:ClickHouse/clickhouse-java.git</developerConnection>
<tag>HEAD</tag>
</scm>

<issueManagement>
<system>Github</system>
<url>https://github.com/ClickHouse/clickhouse-java/issues</url>
</issueManagement>

<ciManagement>
<system>Github</system>
<url>https://github.com/ClickHouse/clickhouse-java/actions</url>
</ciManagement>

<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</repository>

<!-- For the night builds -->
<!-- <repository>-->
<!-- <id>ossrh</id>-->
<!-- <name>Sonatype OSSRH</name>-->
<!-- <url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>-->
<!-- </repository>-->
</repositories>

<properties>
<project.current.year>2023</project.current.year>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

<clickhouse-java.version>0.6.0-SNAPSHOT</clickhouse-java.version>
<apache-httpclient.version>5.2.1</apache-httpclient.version>

<compiler-plugin.version>3.8.1</compiler-plugin.version>

<minJdk>1.8</minJdk>
</properties>

<dependencies>
<dependency>
<groupId>com.clickhouse</groupId>
<artifactId>client-v2</artifactId>
<version>${clickhouse-java.version}</version>
</dependency>
<dependency>
<groupId>com.clickhouse</groupId>
<artifactId>clickhouse-http-client</artifactId>
<version>${clickhouse-java.version}</version>
</dependency>

<!-- Recommended to communicate with ClickHouse server over http -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>${apache-httpclient.version}</version>
</dependency>

<!-- Miscellaneous application dependencies -->

<!-- Project Lombok simplifies some routine tasks -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.32</version>
<scope>provided</scope>
</dependency>

<!-- Basic logging -->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.13</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.13</version>
<scope>runtime</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<source>${minJdk}</source>
<target>${minJdk}</target>
<showWarnings>true</showWarnings>
<compilerArgs>
<arg>-Xlint:all</arg>
<!-- arg>-Werror</arg -->
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.32</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>

</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.clickhouse.examples.client_v2;

import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;

@Slf4j
public class Main {

public static void main(String[] args) {
final String endpoint = System.getProperty("chEndpoint", "http://localhost:8123");
final String user = System.getProperty("chUser", "default");
final String password = System.getProperty("chPassword", null);
final String database = System.getProperty("chDatabase", "default");

SimpleWriter writer = new SimpleWriter(endpoint, user, password, database);

if (writer.isServerAlive()) {
log.info("ClickHouse server is alive");
} else {
log.error("ClickHouse server is not alive");
Runtime.getRuntime().exit(-503);
}

writer.resetTable();


log.info("Inserting data from resources/sample_hacker_news_posts.json");
try (InputStream is = Main.class.getResourceAsStream("/sample_hacker_news_posts.json")) {
writer.insertData_JSONEachRowFormat(is);
} catch (Exception e) {
log.error("Failed to insert data", e);
}

SimpleReader reader = new SimpleReader(endpoint, user, password, database);

reader.readData();

log.info("Done");

Runtime.getRuntime().exit(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.clickhouse.examples.client_v2;

import com.clickhouse.client.api.Client;
import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
import com.clickhouse.client.api.data_formats.RowBinaryWithNamesAndTypesFormatReader;
import com.clickhouse.client.api.query.QueryResponse;
import com.clickhouse.client.api.query.QuerySettings;
import com.clickhouse.data.ClickHouseFormat;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

@Slf4j
public class SimpleReader {

private static final String TABLE_NAME = "hacker_news_articles";

Client client;

String database;

public SimpleReader(String endpoint, String user, String password, String database) {
// Create a lightweight object to interact with ClickHouse server
this.client = new Client.Builder()
.addEndpoint(endpoint)
.addUsername(user).addPassword(password)
.enableCompression(false)
.enableDecompression(false)
.build();
this.database = database;
}

public boolean isServerAlive() {
return client.ping();
}

public void readData() {
try {
// Read data from the table
log.info("Reading data from table: {}", TABLE_NAME);
QuerySettings settings = new QuerySettings();
settings.setDatabase(database);
settings.setFormat(ClickHouseFormat.RowBinaryWithNamesAndTypes.name());
settings.setCompress(false);
final String sql = "select * from " + TABLE_NAME + " where title <> '' limit 10";
QueryResponse response = client.query(sql, Collections.emptyMap(), settings)
.get(10, TimeUnit.SECONDS);
response.ensureDone();

ClickHouseBinaryFormatReader reader = new RowBinaryWithNamesAndTypesFormatReader(response.getInputStream(),
settings);

while (reader.next()) {
double id = reader.getDouble("id");
String title = reader.getString("title");
String url = reader.getString("url");

log.info("id: {}, title: {}, url: {}", id, title, url);
}

log.info("Data read successfully: {}", response.getOperationStatistics());

} catch (Exception e) {
log.error("Failed to read data", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.clickhouse.examples.client_v2;

import com.clickhouse.client.api.Client;
import com.clickhouse.client.api.exception.ClientException;
import com.clickhouse.client.api.insert.InsertResponse;
import com.clickhouse.client.api.insert.InsertSettings;
import com.clickhouse.client.api.query.QueryResponse;
import com.clickhouse.client.api.query.QuerySettings;
import com.clickhouse.data.ClickHouseFormat;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
public class SimpleWriter {

private static final String TABLE_NAME = "hacker_news_articles";

Client client;

String database;

public SimpleWriter(String endpoint, String user, String password, String database) {
// Create a lightweight object to interact with ClickHouse server
this.client = new Client.Builder()
.addEndpoint(endpoint)
.addUsername(user).addPassword(password)
.enableCompression(false)
.enableDecompression(false)
.build();
this.database = database;
}

public boolean isServerAlive() {
return client.ping();
}

// Initializes a table for the specific dataset
public void resetTable() {
try (InputStream initSql = SimpleWriter.class.getResourceAsStream("/simple_writer_init.sql")) {
BufferedReader reader = new BufferedReader(new InputStreamReader(initSql));
String sql = reader.lines().collect(Collectors.joining("\n"));
log.debug("Executing Create Table: {}", sql);
QuerySettings settings = new QuerySettings();
settings.setDatabase(database);
settings.setFormat(ClickHouseFormat.TabSeparated.name());
settings.setCompress(false);
client.query("drop table if exists hacker_news_articles", Collections.emptyMap(), settings).get(10, TimeUnit.SECONDS);
QueryResponse response = client.query(sql, Collections.emptyMap(), settings).get(10, TimeUnit.SECONDS);
response.ensureDone();
log.info("Table initialized");
} catch (Exception e) {
log.error("Failed to initialize table", e);
}
}

public void insertData_JSONEachRowFormat(InputStream inputStream) {
InsertSettings insertSettings = new InsertSettings();
insertSettings.setFormat(ClickHouseFormat.JSONEachRow);

try {
InsertResponse response = client.insert(TABLE_NAME, inputStream, insertSettings);
log.info("Insert finished: {}", response.getOperationStatistics());
} catch (Exception | ClientException e) {
log.error("Failed to write JSONEachRow data", e);
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{"id":11132929,"deleted":0,"type":"story","by":"brakmic","time":"2016-02-19 11:40:55","text":"","dead":1,"parent":0,"poll":0,"kids":[11133170],"url":"https:\/\/www.washingtonpost.com\/news\/morning-mix\/wp\/2016\/02\/18\/s-f-tech-bro-writes-open-letter-to-mayor-i-shouldnt-have-to-see-the-pain-struggle-and-despair-of-homeless-people\/","score":3,"title":"SF ‘tech bro’ writes to mayor: ‘I shouldn’t have to see the despair of homeless’","parts":[],"descendants":0}
{"id":11132930,"deleted":0,"type":"comment","by":"kherraza","time":"2016-02-19 11:41:07","text":"a new way to travel without moving through a new system!","dead":0,"parent":11132928,"poll":0,"kids":[],"url":"","score":0,"title":"","parts":[],"descendants":0}
{"id":11132931,"deleted":0,"type":"comment","by":"DanielBMarkham","time":"2016-02-19 11:41:50","text":"I don&#x27;t want huge denominations, but assuming inflation over the last 50 years, seems to me that we should have a $500US note.<p>Yes, I understand if LE had their way we&#x27;d be paying with 5-spots, but convenience has to mean something also. Let&#x27;s bring back the $500 bill and then index the entire thing to inflation such that there isn&#x27;t more than a dozen or so steps between the smallest and largest monetary units.<p>I don&#x27;t think this is a political discussion&#x2F;argument we need to have constantly. Fix it once and then leave it alone. I&#x27;m also completely opposed to eliminating all currency and going totally electronic, which sounds like an even more dystopian state than the current one our betters have created for us over the last decade or two.","dead":0,"parent":11132443,"poll":0,"kids":[11132960],"url":"","score":0,"title":"","parts":[],"descendants":0}
{"id":11132932,"deleted":0,"type":"comment","by":"choosername","time":"2016-02-19 11:41:50","text":"&gt; With math, there are no docs, no playground, no explanations, no nothing. Either you are the part of mathematical community and can hope for explanations and knowledge transfer, or you are not<p>what&#x27;s the difference to CS here, where did you get that coding sample you mentioned? The playground is your mind, pebbles or pen and paper, maths are a projection of the real world.<p>Mathematics is not inconsistent. Isn&#x27;t this the premisses of rigor? Math has mathematical consistency and that&#x27;s not the same as literal consistency, but maybe that&#x27;s a problem in semiotics and language. The language and the literature is inconsistent.","dead":0,"parent":11132614,"poll":0,"kids":[11132963],"url":"","score":0,"title":"","parts":[],"descendants":0}
{"id":11132933,"deleted":0,"type":"story","by":"mt_caret","time":"2016-02-19 11:42:32","text":"","dead":0,"parent":0,"poll":0,"kids":[],"url":"https:\/\/github.com\/php\/php-src\/commit\/a0724d30817600540946b41e40f4cfc2a0c30f80","score":3,"title":"Commit to revert to mistaken implementation of mt_rand()","parts":[],"descendants":0}
{"id":11132934,"deleted":0,"type":"story","by":"rayascott","time":"2016-02-19 11:42:34","text":"","dead":0,"parent":0,"poll":0,"kids":[],"url":"http:\/\/www.wired.com\/2015\/10\/this-living-clothing-morphs-when-you-sweat\/","score":1,"title":"This Living Clothing Morphs When You Sweat","parts":[],"descendants":0}
{"id":11132935,"deleted":0,"type":"comment","by":"refal","time":"2016-02-19 11:43:03","text":"I&#x27;m basically with you.<p>However, as a German, I find it interesting why you mention Germany as &quot;less-principled&quot;. Less-principled than the US? Do you talk about current Germany or about former east Germany or even Nazi Germany?<p>Of course, there are enough problems here as anywhere else regarding privacy, etc. But I have difficulties seeing current Germany as &quot;less-principled&quot; than the US wrt. privacy, human rights etc.<p>Just curious what your impression is based on.","dead":0,"parent":11132330,"poll":0,"kids":[],"url":"","score":0,"title":"","parts":[],"descendants":0}
{"id":11132936,"deleted":0,"type":"comment","by":"rwmj","time":"2016-02-19 11:43:32","text":"Against an insufficiently smart attacker. How about a computer that can learn to imitate any speech, perhaps by modelling the shape of the vocal tract (which is how modern speech synthesizers actually work, so it&#x27;s not a huge leap).","dead":0,"parent":11132918,"poll":0,"kids":[11133186,11132982],"url":"","score":0,"title":"","parts":[],"descendants":0}
{"id":11132937,"deleted":0,"type":"comment","by":"noir_lord","time":"2016-02-19 11:43:56","text":"Except the note size is kind of secondary here.<p>Having limits on transactions over 1000 euro (like France) does forces law-abiding citizens to handle transactions in a way that can be monitored by the security services (the non-law abiding citizens of course just ignore the damn law or wash the money through a front).<p>It&#x27;s yet another attack on privacy, if I want to buy a bike from someone legally and pay in cash for it what business is it of the governments, it&#x27;s a private transaction between two parties for a legally owned and sold item.<p>I&#x27;m rapidly coming to the view that Orwell wasn&#x27;t far of the mark with &quot;If you want a vision of the future, imagine a boot stamping on a human face - forever.&quot; except instead of an actual jackboot we just have the complete removal of privacy, fear of the boot stamping on your face instead of an actual boot.","dead":0,"parent":11132917,"poll":0,"kids":[],"url":"","score":0,"title":"","parts":[],"descendants":0}
{"id":11132938,"deleted":0,"type":"story","by":"vickymehta","time":"2016-02-19 11:44:07","text":"http:&#x2F;&#x2F;goo.gl&#x2F;tW7F2j","dead":1,"parent":0,"poll":0,"kids":[],"url":"","score":1,"title":"Letting You Online Stores to Find the Best Brand for You and Your Family","parts":[],"descendants":0}
17 changes: 17 additions & 0 deletions examples/client-v2/src/main/resources/simple_writer_init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
create table hacker_news_articles (
id Nullable(Float64),
deleted Nullable(Float64),
type Nullable(String),
by Nullable(String),
time Nullable(String),
text Nullable(String),
dead Nullable(Float64),
parent Nullable(Float64),
poll Nullable(Float64),
kids Array(Nullable(Float64)),
url Nullable(String),
score Nullable(Float64),
title Nullable(String),
parts Array(Nullable(Float64)),
descendants Nullable(Float64)
) engine = MergeTree order by ();

0 comments on commit b5a9359

Please sign in to comment.