[examples] Improve the basic Java example This improves the Java example in a bunch of ways:
1. Renames java-sample -> java-example. 2. Renames class to org.apache.kudu.examples.Example. 3. Adds licenses everywhere. 4. Rewrites the README, using adoc format. 5. Updates the pom, including syncing some plugin versions with java/pom and updating the version of the client the example uses. 6. Expands and improves the Example class: - Adds range partitioning with split rows. - Adds an alter table example. - Scans with a predicate and checks the results. Change-Id: I79ab5b0b2c30e8fd7c799857a0e3754b7618a580 Reviewed-on: http://gerrit.cloudera.org:8080/9852 Reviewed-by: Adar Dembo <a...@cloudera.com> Tested-by: Will Berkeley <wdberke...@gmail.com> Project: http://git-wip-us.apache.org/repos/asf/kudu/repo Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/c3684b6e Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/c3684b6e Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/c3684b6e Branch: refs/heads/master Commit: c3684b6e10ece50dd382d178e392a25e3130a86e Parents: cc8c5e3 Author: Will Berkeley <wdberke...@apache.org> Authored: Wed Mar 28 21:27:10 2018 -0700 Committer: Will Berkeley <wdberke...@gmail.com> Committed: Tue Apr 3 04:30:29 2018 +0000 ---------------------------------------------------------------------- examples/java/java-example/README.adoc | 46 ++++ examples/java/java-example/pom.xml | 78 +++++++ .../java/org/apache/kudu/examples/Example.java | 215 +++++++++++++++++++ examples/java/java-sample/README | 15 -- examples/java/java-sample/pom.xml | 72 ------- .../java/org/kududb/examples/sample/Sample.java | 77 ------- 6 files changed, 339 insertions(+), 164 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kudu/blob/c3684b6e/examples/java/java-example/README.adoc ---------------------------------------------------------------------- diff --git a/examples/java/java-example/README.adoc b/examples/java/java-example/README.adoc new file mode 100644 index 0000000..950c4e5 --- /dev/null +++ b/examples/java/java-example/README.adoc @@ -0,0 +1,46 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + += Kudu Java client example README +:author: Kudu Team +:homepage: https://kudu.apache.org/ + +This is an example program that uses the synchronous Kudu Java client APIs to + +- Create a table +- Insert some rows +- Alter the table +- Scan some rows +- Delete the table + +To build and run, ensure maven is installed and from the java-example directory run: + +[source,bash] +---- +$ mvn package +$ java -jar target/kudu-java-example-1.0-SNAPSHOT.jar +---- + +By default, the example assumes the Kudu cluster has a single master running on +localhost with the default port 7051. To specify a different set of masters for +Kudu cluster, set the property `kuduMasters` to a CSV of the master addresses in +the form `host:port`, as shown: + +[source,bash] +---- +$ java -DkuduMasters=master-0:7051,master-1:7051,master-2:7051 -jar target/kudu-java-example-1.0-SNAPSHOT.jar +---- http://git-wip-us.apache.org/repos/asf/kudu/blob/c3684b6e/examples/java/java-example/pom.xml ---------------------------------------------------------------------- diff --git a/examples/java/java-example/pom.xml b/examples/java/java-example/pom.xml new file mode 100644 index 0000000..67b0754 --- /dev/null +++ b/examples/java/java-example/pom.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.apache.kudu</groupId> + <artifactId>kudu-java-example</artifactId> + <packaging>jar</packaging> + <version>1.0-SNAPSHOT</version> + <name>Kudu Java Client Examples</name> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.6.2</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>3.0.0</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + <configuration> + <transformers> + <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> + <mainClass>org.apache.kudu.examples.Example</mainClass> + </transformer> + </transformers> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.apache.kudu</groupId> + <artifactId>kudu-client</artifactId> + <version>1.7.0</version> + </dependency> + + <!-- For logging messages. --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <version>1.7.25</version> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/kudu/blob/c3684b6e/examples/java/java-example/src/main/java/org/apache/kudu/examples/Example.java ---------------------------------------------------------------------- diff --git a/examples/java/java-example/src/main/java/org/apache/kudu/examples/Example.java b/examples/java/java-example/src/main/java/org/apache/kudu/examples/Example.java new file mode 100644 index 0000000..0805c12 --- /dev/null +++ b/examples/java/java-example/src/main/java/org/apache/kudu/examples/Example.java @@ -0,0 +1,215 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.kudu.examples; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.kudu.ColumnSchema; +import org.apache.kudu.Schema; +import org.apache.kudu.Type; +import org.apache.kudu.client.AlterTableOptions; +import org.apache.kudu.client.CreateTableOptions; +import org.apache.kudu.client.Insert; +import org.apache.kudu.client.KuduClient; +import org.apache.kudu.client.KuduException; +import org.apache.kudu.client.KuduPredicate; +import org.apache.kudu.client.KuduPredicate.ComparisonOp; +import org.apache.kudu.client.KuduScanner; +import org.apache.kudu.client.KuduSession; +import org.apache.kudu.client.KuduTable; +import org.apache.kudu.client.PartialRow; +import org.apache.kudu.client.RowResult; +import org.apache.kudu.client.RowResultIterator; + +/* + * A simple example of using the synchronous Kudu Java client to + * - Create a table. + * - Insert rows. + * - Alter a table. + * - Scan rows. + * - Delete a table. + */ +public class Example { + private static final Double DEFAULT_DOUBLE = 12.345; + private static final String KUDU_MASTERS = System.getProperty("kuduMasters", "localhost:7051"); + + private static void createExampleTable(KuduClient client, String tableName) throws KuduException { + // Set up a simple schema. + List<ColumnSchema> columns = new ArrayList<>(2); + columns.add(new ColumnSchema.ColumnSchemaBuilder("key", Type.INT32) + .key(true) + .build()); + columns.add(new ColumnSchema.ColumnSchemaBuilder("value", Type.STRING).nullable(true) + .build()); + Schema schema = new Schema(columns); + + // Set up the partition schema, which distributes rows to different tablets by hash. + // Kudu also supports partitioning by key range. Hash and range partitioning can be combined. + // For more information, see http://kudu.apache.org/docs/schema_design.html. + CreateTableOptions cto = new CreateTableOptions(); + List<String> hashKeys = new ArrayList<>(1); + hashKeys.add("key"); + int numBuckets = 8; + cto.addHashPartitions(hashKeys, numBuckets); + + // Create the table. + client.createTable(tableName, schema, cto); + System.out.println("Created table " + tableName); + } + + private static void insertRows(KuduClient client, String tableName, int numRows) throws KuduException { + // Open the newly-created table and create a KuduSession. + KuduTable table = client.openTable(tableName); + KuduSession session = client.newSession(); + for (int i = 0; i < numRows; i++) { + Insert insert = table.newInsert(); + PartialRow row = insert.getRow(); + row.addInt("key", i); + // Make even-keyed row have a null 'value'. + if (i % 2 == 0) { + row.setNull("value"); + } else { + row.addString("value", "value " + i); + } + session.apply(insert); + } + + // Call session.close() to end the session and ensure the rows are + // flushed and errors are returned. + // You can also call session.flush() to do the same without ending the session. + // When flushing in AUTO_FLUSH_BACKGROUND mode (the default mode recommended + // for most workloads, you must check the pending errors as shown below, since + // write operations are flushed to Kudu in background threads. + session.close(); + if (session.countPendingErrors() != 0) { + System.out.println("errors inserting rows"); + org.apache.kudu.client.RowErrorsAndOverflowStatus roStatus = session.getPendingErrors(); + org.apache.kudu.client.RowError[] errs = roStatus.getRowErrors(); + int numErrs = Math.min(errs.length, 5); + System.out.println("there were errors inserting rows to Kudu"); + System.out.println("the first few errors follow:"); + for (int i = 0; i < numErrs; i++) { + System.out.println(errs[i]); + } + if (roStatus.isOverflowed()) { + System.out.println("error buffer overflowed: some errors were discarded"); + } + throw new RuntimeException("error inserting rows to Kudu"); + } + System.out.println("Inserted " + numRows + " rows"); + } + + private static void scanTableAndCheckResults(KuduClient client, String tableName, int numRows) throws KuduException { + KuduTable table = client.openTable(tableName); + Schema schema = table.getSchema(); + + // Scan with a predicate on the 'key' column, returning the 'value' and "added" columns. + List<String> projectColumns = new ArrayList<>(2); + projectColumns.add("key"); + projectColumns.add("value"); + projectColumns.add("added"); + int lowerBound = 0; + KuduPredicate lowerPred = KuduPredicate.newComparisonPredicate( + schema.getColumn("key"), + ComparisonOp.GREATER_EQUAL, + lowerBound); + int upperBound = numRows / 2; + KuduPredicate upperPred = KuduPredicate.newComparisonPredicate( + schema.getColumn("key"), + ComparisonOp.LESS, + upperBound); + KuduScanner scanner = client.newScannerBuilder(table) + .setProjectedColumnNames(projectColumns) + .addPredicate(lowerPred) + .addPredicate(upperPred) + .build(); + + // Check the correct number of values and null values are returned, and + // that the default value was set for the new column on each row. + // Note: scanning a hash-partitioned table will not return results in primary key order. + int resultCount = 0; + int nullCount = 0; + while (scanner.hasMoreRows()) { + RowResultIterator results = scanner.nextRows(); + while (results.hasNext()) { + RowResult result = results.next(); + if (result.isNull("value")) { + nullCount++; + } + double added = result.getDouble("added"); + if (added != DEFAULT_DOUBLE) { + throw new RuntimeException("expected added=" + DEFAULT_DOUBLE + + " but got added= " + added); + } + resultCount++; + } + } + int expectedResultCount = upperBound - lowerBound; + if (resultCount != expectedResultCount) { + throw new RuntimeException("scan error: expected " + expectedResultCount + + " results but got " + resultCount + " results"); + } + int expectedNullCount = expectedResultCount / 2 + (numRows % 2 == 0 ? 1 : 0); + if (nullCount != expectedNullCount) { + throw new RuntimeException("scan error: expected " + expectedNullCount + + " rows with value=null but found " + nullCount); + } + System.out.println("Scanned some rows and checked the results"); + } + + public static void main(String[] args) { + System.out.println("-----------------------------------------------"); + System.out.println("Will try to connect to Kudu master(s) at " + KUDU_MASTERS); + System.out.println("Run with -DkuduMasters=master-0:port,master-1:port,... to override."); + System.out.println("-----------------------------------------------"); + String tableName = "java_example-" + System.currentTimeMillis(); + KuduClient client = new KuduClient.KuduClientBuilder(KUDU_MASTERS).build(); + + try { + createExampleTable(client, tableName); + + int numRows = 150; + insertRows(client, tableName, numRows); + + // Alter the table, adding a column with a default value. + // Note: after altering the table, the table needs to be re-opened. + AlterTableOptions ato = new AlterTableOptions(); + ato.addColumn("added", org.apache.kudu.Type.DOUBLE, DEFAULT_DOUBLE); + client.alterTable(tableName, ato); + System.out.println("Altered the table"); + + scanTableAndCheckResults(client, tableName, numRows); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + client.deleteTable(tableName); + System.out.println("Deleted the table"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + client.shutdown(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/kudu/blob/c3684b6e/examples/java/java-sample/README ---------------------------------------------------------------------- diff --git a/examples/java/java-sample/README b/examples/java/java-sample/README deleted file mode 100644 index 71cd034..0000000 --- a/examples/java/java-sample/README +++ /dev/null @@ -1,15 +0,0 @@ -Here's a Java client sample that creates a table, writes some data, scans it, and then deletes -its table. - - -To build and run, do the following: - -$ mvn package -$ java -jar target/kudu-java-sample-1.0-SNAPSHOT.jar - -This example assumes that you are running the Quickstart VM with the host name -"quickstart.cloudera". If you are running against a different cluster, pass the -host name of the Kudu Master using a Java property: - -$ java -DkuduMaster=a1216.halxg.cloudera.com -jar target/kudu-java-sample-1.0-SNAPSHOT.jar - http://git-wip-us.apache.org/repos/asf/kudu/blob/c3684b6e/examples/java/java-sample/pom.xml ---------------------------------------------------------------------- diff --git a/examples/java/java-sample/pom.xml b/examples/java/java-sample/pom.xml deleted file mode 100644 index b078b04..0000000 --- a/examples/java/java-sample/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>kudu-java-sample</groupId> - <artifactId>kudu-java-sample</artifactId> - <packaging>jar</packaging> - <version>1.0-SNAPSHOT</version> - <name>kudu-java-sample</name> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>2.3.1</version> - <configuration> - <source>1.7</source> - <target>1.7</target> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-shade-plugin</artifactId> - <version>2.4</version> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>shade</goal> - </goals> - <configuration> - <transformers> - <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> - <mainClass>org.kududb.examples.sample.Sample</mainClass> - </transformer> - </transformers> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - - <repositories> - <repository> - <id>cdh.repo</id> - <name>Cloudera Repositories</name> - <url>https://repository.cloudera.com/artifactory/cloudera-repos</url> - <snapshots> - <enabled>false</enabled> - </snapshots> - </repository> - </repositories> - - <dependencies> - - <dependency> - <groupId>org.apache.kudu</groupId> - <artifactId>kudu-client</artifactId> - <version>1.1.0</version> - </dependency> - - <!-- for logging messages --> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.12</version> - </dependency> - - </dependencies> - -</project> http://git-wip-us.apache.org/repos/asf/kudu/blob/c3684b6e/examples/java/java-sample/src/main/java/org/kududb/examples/sample/Sample.java ---------------------------------------------------------------------- diff --git a/examples/java/java-sample/src/main/java/org/kududb/examples/sample/Sample.java b/examples/java/java-sample/src/main/java/org/kududb/examples/sample/Sample.java deleted file mode 100644 index 5c5285f..0000000 --- a/examples/java/java-sample/src/main/java/org/kududb/examples/sample/Sample.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.kududb.examples.sample; - -import org.apache.kudu.ColumnSchema; -import org.apache.kudu.Schema; -import org.apache.kudu.Type; -import org.apache.kudu.client.*; - -import java.util.ArrayList; -import java.util.List; - -public class Sample { - - private static final String KUDU_MASTER = System.getProperty( - "kuduMaster", "quickstart.cloudera"); - - public static void main(String[] args) { - System.out.println("-----------------------------------------------"); - System.out.println("Will try to connect to Kudu master at " + KUDU_MASTER); - System.out.println("Run with -DkuduMaster=myHost:port to override."); - System.out.println("-----------------------------------------------"); - String tableName = "java_sample-" + System.currentTimeMillis(); - KuduClient client = new KuduClient.KuduClientBuilder(KUDU_MASTER).build(); - - try { - List<ColumnSchema> columns = new ArrayList(2); - columns.add(new ColumnSchema.ColumnSchemaBuilder("key", Type.INT32) - .key(true) - .build()); - columns.add(new ColumnSchema.ColumnSchemaBuilder("value", Type.STRING) - .build()); - List<String> rangeKeys = new ArrayList<>(); - rangeKeys.add("key"); - - Schema schema = new Schema(columns); - client.createTable(tableName, schema, - new CreateTableOptions().setRangePartitionColumns(rangeKeys)); - - KuduTable table = client.openTable(tableName); - KuduSession session = client.newSession(); - for (int i = 0; i < 3; i++) { - Insert insert = table.newInsert(); - PartialRow row = insert.getRow(); - row.addInt(0, i); - row.addString(1, "value " + i); - session.apply(insert); - } - - List<String> projectColumns = new ArrayList<>(1); - projectColumns.add("value"); - KuduScanner scanner = client.newScannerBuilder(table) - .setProjectedColumnNames(projectColumns) - .build(); - while (scanner.hasMoreRows()) { - RowResultIterator results = scanner.nextRows(); - while (results.hasNext()) { - RowResult result = results.next(); - System.out.println(result.getString(0)); - } - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - client.deleteTable(tableName); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - client.shutdown(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } -} -