二级索引相当于把数据表的主键查询能力扩展到了不同的列,当需要使用属性查询数据时,您可以通过创建二级索引加快数据查询的效率。设置预定义列后,在创建二级索引时将预定义列作为索引表的索引列或者属性列。创建二级索引后,您可以使用二级索引进行数据查询。
前提条件
已创建数据表,且数据表的最大版本数(max Versions)必须为1,数据生命周期(Time to Live)必须满足如下条件中的任意一个。
-
数据表的数据生命周期为-1(数据永不过期)。
-
数据表的数据生命周期不为-1时,数据表处于禁止更新状态(即是否允许更新为否)。
二级索引的数据生命周期与数据表的数据生命周期相同。
步骤一:(可选)管理预定义列
使用二级索引时,如果未设置预定义列或者已有预定义列不满足需求,您可以为数据表添加或者删除预定义列。您可以使用Java SDK或者Go SDK管理预定义列,此处以Java SDK为例介绍预定义列的使用。
添加预定义列
以下示例向 example_table 添加名为 name 的 STRING 类型预定义列。
AddDefinedColumnRequest request = new AddDefinedColumnRequest();
request.setTableName("example_table");
request.addDefinedColumn("name", DefinedColumnType.STRING);
client.addDefinedColumn(request);删除预定义列
删除数据表上不需要的预定义列。
以下示例从 example_table 中删除名为 name 的预定义列。
DeleteDefinedColumnRequest request = new DeleteDefinedColumnRequest();
request.setTableName("example_table");
request.addDefinedColumn("name");
client.deleteDefinedColumn(request);步骤二:创建二级索引
使用CreateIndex接口在已存在的数据表上创建一个索引表用于加速数据查询。二级索引包括全局二级索引和本地二级索引,请根据实际创建。
您也可以使用CreateTable接口在创建数据表的同时创建一个或者多个索引表。具体操作,请参见创建数据表。
您可以通过Java SDK、Go SDK、Python SDK、Node.js SDK、.NET SDK和PHP SDK创建二级索引,此处以Java SDK为例介绍二级索引的创建。
创建全局二级索引
以下示例为 example_table 创建全局二级索引 example_global_index。索引表包含存量数据。
IndexMeta indexMeta = new IndexMeta("example_global_index");
indexMeta.addPrimaryKeyColumn("category");
indexMeta.addDefinedColumn("status");
CreateIndexRequest request =
new CreateIndexRequest("example_table", indexMeta, true);
client.createIndex(request);创建本地二级索引
创建本地二级索引时,将数据表的第一列主键作为第一列索引主键,并将索引类型和更新模式分别设置为 IT_LOCAL_INDEX 和 IUM_SYNC_INDEX。
IndexMeta indexMeta = new IndexMeta("example_local_index");
indexMeta.addPrimaryKeyColumn("user_id");
indexMeta.addPrimaryKeyColumn("category");
indexMeta.addDefinedColumn("status");
indexMeta.setIndexType(IndexType.IT_LOCAL_INDEX);
indexMeta.setIndexUpdateMode(IndexUpdateMode.IUM_SYNC_INDEX);
CreateIndexRequest request =
new CreateIndexRequest("example_table", indexMeta, true);
client.createIndex(request);步骤三:读取索引表中数据
从索引表中单行或者范围读取数据,当返回的属性列在索引表中时,您可以直接读取索引表获取数据,否则请自行反查数据表获取数据。
您可以通过Java SDK、Go SDK、Python SDK、Node.js SDK、.NET SDK和PHP SDK读取二级索引表中的数据,此处以Java SDK为例介绍二级索引的数据读取。
单行读取数据
读取一行数据。
以下示例根据完整主键从全局二级索引 example_global_index 读取一行数据,并仅返回 status 属性列。
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("category", PrimaryKeyValue.fromString("books"))
.addPrimaryKeyColumn("user_id", PrimaryKeyValue.fromString("user-1"))
.addPrimaryKeyColumn("order_id", PrimaryKeyValue.fromLong(101L))
.build();
SingleRowQueryCriteria criteria =
new SingleRowQueryCriteria("example_global_index", primaryKey);
criteria.addColumnsToGet("status");
criteria.setMaxVersions(1);
GetRowResponse response = client.getRow(new GetRowRequest(criteria));
System.out.println(response.getRow());范围读取数据
读取指定主键范围内的数据。
使用全局二级索引
当需要返回的属性列在索引表中时,可以直接读取索引表获取数据。
private static void scanFromIndex(SyncClient client) {
//设置索引表名称。
RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria("<INDEX_NAME>");
//设置起始主键。
PrimaryKeyBuilder startPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
//设置需要读取的索引列最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.INF_MIN);
//设置数据表主键最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MIN);
//设置数据表主键最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MIN);
rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startPrimaryKeyBuilder.build());
//设置结束主键。
PrimaryKeyBuilder endPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
//设置需要读取的索引列最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.INF_MAX);
//设置数据表主键最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MAX);
//设置数据表主键最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MAX);
rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endPrimaryKeyBuilder.build());
rangeRowQueryCriteria.setMaxVersions(1);
System.out.println("扫描索引表的结果为:");
while (true) {
GetRangeResponse getRangeResponse = client.getRange(new GetRangeRequest(rangeRowQueryCriteria));
for (Row row : getRangeResponse.getRows()) {
System.out.println(row);
}
//如果nextStartPrimaryKey不为null,则继续读取数据。
if (getRangeResponse.getNextStartPrimaryKey() != null) {
rangeRowQueryCriteria.setInclusiveStartPrimaryKey(getRangeResponse.getNextStartPrimaryKey());
} else {
break;
}
}
}当需要返回的属性列不在索引表中时,请自行反查数据表获取数据。
private static void scanFromIndex(SyncClient client) {
//设置索引表名称。
RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria("<INDEX_NAME>");
//设置起始主键。
PrimaryKeyBuilder startPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
//设置需要读取的索引列最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.INF_MIN);
//设置数据表主键最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MIN);
//设置数据表主键最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MIN);
rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startPrimaryKeyBuilder.build());
//设置结束主键。
PrimaryKeyBuilder endPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
//设置需要读取的索引列最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.INF_MAX);
//设置数据表主键最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MAX);
//设置数据表主键最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MAX);
rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endPrimaryKeyBuilder.build());
rangeRowQueryCriteria.setMaxVersions(1);
while (true) {
GetRangeResponse getRangeResponse = client.getRange(new GetRangeRequest(rangeRowQueryCriteria));
for (Row row : getRangeResponse.getRows()) {
PrimaryKey curIndexPrimaryKey = row.getPrimaryKey();
PrimaryKeyColumn pk1 = curIndexPrimaryKey.getPrimaryKeyColumn(PRIMARY_KEY_NAME_1);
PrimaryKeyColumn pk2 = curIndexPrimaryKey.getPrimaryKeyColumn(PRIMARY_KEY_NAME_2);
PrimaryKeyBuilder mainTablePKBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
mainTablePKBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, pk1.getValue());
mainTablePKBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, pk2.getValue());
//根据索引表主键构造数据表主键。
PrimaryKey mainTablePK = mainTablePKBuilder.build();
//反查数据表。
SingleRowQueryCriteria criteria = new SingleRowQueryCriteria("<TABLE_NAME>", mainTablePK);
//设置读取数据表的DEFINED_COL_NAME_3列。
criteria.addColumnsToGet(DEFINED_COL_NAME_3);
//设置读取最新版本。
criteria.setMaxVersions(1);
GetRowResponse getRowResponse = client.getRow(new GetRowRequest(criteria));
Row mainTableRow = getRowResponse.getRow();
System.out.println(row);
}
//如果nextStartPrimaryKey不为null,则继续读取数据。
if (getRangeResponse.getNextStartPrimaryKey() != null) {
rangeRowQueryCriteria.setInclusiveStartPrimaryKey(getRangeResponse.getNextStartPrimaryKey());
} else {
break;
}
}
}使用本地二级索引
当需要返回的属性列在索引表中时,可以直接读取索引表获取数据。
private static void scanFromIndex(SyncClient client) {
//设置索引表名称。
RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria("INDEX_NAME");
//设置起始主键。
PrimaryKeyBuilder startPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
//设置需要读取的索引列最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MIN);
//设置需要读取的索引列最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.INF_MIN);
//设置数据表主键最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MIN);
rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startPrimaryKeyBuilder.build());
//设置结束主键。
PrimaryKeyBuilder endPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
//设置需要读取的索引列最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MAX);
//设置需要读取的索引列最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.INF_MAX);
//设置数据表主键最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MAX);
rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endPrimaryKeyBuilder.build());
rangeRowQueryCriteria.setMaxVersions(1);
System.out.println("扫描索引表的结果为:");
while (true) {
GetRangeResponse getRangeResponse = client.getRange(new GetRangeRequest(rangeRowQueryCriteria));
for (Row row : getRangeResponse.getRows()) {
System.out.println(row);
}
//如果nextStartPrimaryKey不为null, 则继续读取。
if (getRangeResponse.getNextStartPrimaryKey() != null) {
rangeRowQueryCriteria.setInclusiveStartPrimaryKey(getRangeResponse.getNextStartPrimaryKey());
} else {
break;
}
}
}当需要返回的属性列不在索引表中时,请自行反查数据表获取数据。
private static void scanFromIndex(SyncClient client) {
//设置索引表名称。
RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria("<INDEX_NAME>");
//设置起始主键。
PrimaryKeyBuilder startPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
//设置需要读取的索引列最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MIN);
//设置需要读取的索引列最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.INF_MIN);
//设置数据表主键最小值。
startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MIN);
rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startPrimaryKeyBuilder.build());
//设置结束主键。
PrimaryKeyBuilder endPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
//设置需要读取的索引列最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MAX);
//设置需要读取的索引列最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.INF_MAX);
//设置数据表主键最大值。
endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MAX);
rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endPrimaryKeyBuilder.build());
rangeRowQueryCriteria.setMaxVersions(1);
while (true) {
GetRangeResponse getRangeResponse = client.getRange(new GetRangeRequest(rangeRowQueryCriteria));
for (Row row : getRangeResponse.getRows()) {
PrimaryKey curIndexPrimaryKey = row.getPrimaryKey();
PrimaryKeyColumn pk1 = curIndexPrimaryKey.getPrimaryKeyColumn(PRIMARY_KEY_NAME_1);
PrimaryKeyColumn pk2 = curIndexPrimaryKey.getPrimaryKeyColumn(PRIMARY_KEY_NAME_2);
PrimaryKeyBuilder mainTablePKBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
mainTablePKBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, pk1.getValue());
mainTablePKBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, pk2.getValue());
//根据索引表主键构造数据表主键。
PrimaryKey mainTablePK = mainTablePKBuilder.build();
//反查数据表。
SingleRowQueryCriteria criteria = new SingleRowQueryCriteria("TABLE_NAME", mainTablePK);
// 读取主表的DEFINED_COL_NAME3列。
criteria.addColumnsToGet(DEFINED_COL_NAME3);
//设置读取最新版本。
criteria.setMaxVersions(1);
GetRowResponse getRowResponse = client.getRow(new GetRowRequest(criteria));
Row mainTableRow = getRowResponse.getRow();
System.out.println(row);
}
//如果nextStartPrimaryKey不为null, 则继续读取。
if (getRangeResponse.getNextStartPrimaryKey() != null) {
rangeRowQueryCriteria.setInclusiveStartPrimaryKey(getRangeResponse.getNextStartPrimaryKey());
} else {
break;
}
}
}附录:删除索引表
删除不需要的索引表。
您可以通过Java SDK、Go SDK、Python SDK、Node.js SDK、.NET SDK和PHP SDK删除二级索引,此处以Java SDK为例介绍二级索引的删除。
以下示例删除数据表 example_table 中的二级索引 example_index。
DeleteIndexRequest request =
new DeleteIndexRequest("example_table", "example_index");
DeleteIndexResponse response = client.deleteIndex(request);
System.out.println(response.getRequestId());常见问题
相关文档
您还可以使用控制台或者命令行工具使用二级索引。更多信息,请参见通过控制台使用二级索引和通过命令行工具使用二级索引。
如果需要更灵活丰富的数据加速查询方式,例如多条件组合查询、全文检索、前缀查询、模糊查询等,您可以使用多元索引实现。更多信息,请参见多元索引简介。