如前面几篇文章所述,kudu的环境已经搭建好了,剩下就是对kudu-api的上手操作了。
本次主要是创建表,添加,删除字段。
private static final String KUDU_MASTERS = "192.168.220.145";
private static final Logger logger = LoggerFactory.getLogger(TableDDL.class);
public static void main(String[] args) throws KuduException {
KuduClient kuduClient = new KuduClient.KuduClientBuilder(KUDU_MASTERS).build();
createExampleTable(kuduClient, "kudu_test");
createExample2Table(kuduClient, "kudu_test2");
alterTableAddColumn(kuduClient, "kudu_test2", "domain_id_default", Type.INT32);
alterTableDeleteColumn(kuduClient, "kudu_test2", "domain_id_default");
kuduClient.close();
}
单column主键设置,与app一一对应的关系,也是我们常见的结构,然后根据ID进行hash分区。
需要注意以下几点:
必需指定一个或多个字段为主键,多个即为联合主键,如果不设置为报异常
org.apache.kudu.client.NonRecoverableException: must specify at least one key column
buckets数值也就是cto.addHashPartitions(hashKeys, 2);
第二个参数必须是>=2
, 否则会报异常
org.apache.kudu.client.NonRecoverableException: must have at least two hash buckets
因为我搭建的是单机模式(kudu-master与kudu-tserver均安装在一台机器上),副本数一定要设置为1
,
否则会报如下异常
org.apache.kudu.client.NonRecoverableException: Not enough live tablet servers to create a table
with the requested replication factor 3. 1 tablet servers are alive.
并且副本数一定要设置成奇数,否则会报异常
org.apache.kudu.client.NonRecoverableException: illegal replication factor 2 (replication factor must be odd)
/**
* 背景:
* 单column主键设置,与app一一对应的关系
* 根据Id hash分了两个区。
*
* @param client
* @param tableName
* @throws KuduException
*/
static void createExampleTable(KuduClient client, String tableName) throws KuduException {
List<ColumnSchema> columnSchemas = Lists.newArrayList();
columnSchemas.add(new ColumnSchema.ColumnSchemaBuilder("id", Type.STRING).key(true).build());
columnSchemas.add(new ColumnSchema.ColumnSchemaBuilder("app", Type.INT8).build());
Schema schema = new Schema(columnSchemas);
ImmutableList<String> hashKeys = ImmutableList.of("id");
CreateTableOptions cto = new CreateTableOptions();
cto.addHashPartitions(hashKeys, 2);
cto.setNumReplicas(1);
client.createTable(tableName, schema, cto);
System.out.println("Create table " + tableName);
}
创建好后,可以在界面查看到,我们可以看到,即使没有装impala-kudu
组件,但页面一样显示了impala create table
的语法。这点很友好。
由于需求原因,一个device_id
,可能会有多个app
的情况,所以仅使用device_id
做为主键是不够用的。
这时就需要有联合主键了。此处根据业务场景,应使用device_id
与app_id
做为联合主键, 此外对于多个主键,
可以对不同的主键进行不同的分区策略。而Kudu共有两种分区策略,一个是hash
,另一个是range
在创建联合主键的表是时,还需要注意以下几点:
联合主键是有序的,这就意味着,你的主键在进行代码添加(也就是通过columnSchemas.add()
方法)时,
必须要严格按照你的业务来进行,比如你不能把action_time
放在非主键app_name
之后,否则会报异常
org.apache.kudu.client.NonRecoverableException: Got out-of-order key column: name: “action_time” type: INT64 is_key: true is_nullable: false cfile_block_size: 0
设备action_time
为range分区时,那么action_time
必须要设置为主键, 否则会报异常
org.apache.kudu.client.NonRecoverableException: must specify only primary key columns for range partition component
/**
* range分区数
*/
private static final int RANGE_PARTITION_NUMS = 10;
/**
*
* @param client
* @param tableName
*/
static void createExample2Table (KuduClient client, String tableName) throws KuduException {
List<ColumnSchema> columnSchemas = Lists.newArrayList();
//org.apache.kudu.client.NonRecoverableException: must specify at least one key column
columnSchemas.add(new ColumnSchema.ColumnSchemaBuilder("device_id", Type.STRING).key(true).build());
columnSchemas.add(new ColumnSchema.ColumnSchemaBuilder("app_id", Type.INT32).key(true).build());
columnSchemas.add(new ColumnSchema.ColumnSchemaBuilder("action_time", Type.INT64).key(true).build());
columnSchemas.add(new ColumnSchema.ColumnSchemaBuilder("app_name", Type.STRING).nullable(true).build());
Schema schema = new Schema(columnSchemas);
//设置hash分区
CreateTableOptions cto = new CreateTableOptions();
cto.addHashPartitions(ImmutableList.of("device_id", "app_id"), 2);
cto.setNumReplicas(1);
//设置action_time的range分区
cto.setRangePartitionColumns(ImmutableList.of("action_time"));
int count = 0;
for (long i = 0; i < RANGE_PARTITION_NUMS; i++) {
PartialRow lower = schema.newPartialRow();
lower.addLong("action_time", count);
PartialRow upper = schema.newPartialRow();
count += 10;
upper.addLong("action_time", count);
cto.addRangePartition(lower, upper);
}
// 创建table, 并设置partition
client.createTable(tableName, schema, cto);
System.out.println("Create table " + tableName);
}
需要注意以下两点就行
给表添加字段,但要注意的是添加的字段不能再设置成主键。(kudu-version: 1.10.0),也就是主键必须要在创建表之前就要根据业务实际情况想好,因为后续是不能进行更改的,否则会报如下异常
java.lang.IllegalArgumentException: Key columns cannot be added
添加的字段nullabel参数默认为false,所以要设置defaultValue的值,或者将nullable设置为true, 否则会异常:
java.lang.IllegalArgumentException: A new non-null column must have a default value
static void dropExampleTable(KuduClient client, String tableName) throws KuduException {
client.deleteTable(tableName);
}
static void alterTableAddColumn(KuduClient client, String tableName, String column, Type type) {
AlterTableOptions alterTableOptions = new AlterTableOptions();
alterTableOptions.addColumn(new ColumnSchema.ColumnSchemaBuilder(column, type).nullable(true).build());
try {
client.alterTable(tableName, alterTableOptions);
} catch (KuduException e) {
e.printStackTrace();
logger.debug("给表{}添加字段失败, 失败信息: cause -> {}, message -> {}", tableName, e.getCause(), e.getMessage());
}
}
static void alterTableDeleteColumn(KuduClient client, String tableName, String column){
AlterTableOptions alterTableOptions = new AlterTableOptions().dropColumn(column);
try {
client.alterTable(tableName, alterTableOptions);
} catch (KuduException e) {
e.printStackTrace();
logger.error("删除表{}字段失败, 失败信息: cause -> {}, message -> {}", tableName, e.getCause(), e.getMessage());
}
}