二级索引相当于把数据表的主键查询能力扩展到了不同的列,当需要使用属性查询数据时,您可以通过创建二级索引加快数据查询的效率。设置预定义列后,在创建二级索引时将预定义列作为索引表的索引列或者属性列。创建二级索引后,您可以使用二级索引进行数据查询。
前提条件
已创建数据表,且数据表的最大版本数(max Versions)必须为1,数据生命周期(Time to Live)必须满足如下条件中的任意一个。
数据表的数据生命周期为-1(数据永不过期)。
数据表的数据生命周期不为-1时,数据表处于禁止更新状态(即是否允许更新为否)。
二级索引的数据生命周期与数据表的数据生命周期相同。
步骤一:(可选)管理预定义列
使用二级索引时,如果未设置预定义列或者已有预定义列不满足需求,您可以为数据表添加或者删除预定义列。您可以使用Java SDK或者Go SDK管理预定义列,此处以Java SDK为例介绍预定义列的使用。
添加预定义列
以下示例用于为数据表增加预定义列,预定义列分别为definedColumnName01(String类型)、definedColumnName02(Integer类型)和definedColumnName03(String类型)。
public static void addDefinedColumnRequest(SyncClient client) {
AddDefinedColumnRequest addDefinedColumnRequest = new AddDefinedColumnRequest();
//设置数据表名称。
addDefinedColumnRequest.setTableName("<TABLE_NAME>");
//为数据表添加预定义列。
addDefinedColumnRequest.addDefinedColumn("definedColumnName01",DefinedColumnType.STRING);
addDefinedColumnRequest.addDefinedColumn("definedColumnName02",DefinedColumnType.INTEGER);
addDefinedColumnRequest.addDefinedColumn("definedColumnName03",DefinedColumnType.STRING);
client.addDefinedColumn(addDefinedColumnRequest);
}
删除预定义列
删除数据表上不需要的预定义列。
以下示例用于删除数据表的预定义列definedColumnName01和definedColumnName02。
public static void deleteDefinedColumnRequest(SyncClient client){
DeleteDefinedColumnRequest deleteDefinedColumnRequest = new DeleteDefinedColumnRequest();
//设置数据表名称。
deleteDefinedColumnRequest.setTableName("<TABLE_NAME>");
//添加要删除的预定义列。
deleteDefinedColumnRequest.addDefinedColumn("definedColumnName01");
deleteDefinedColumnRequest.addDefinedColumn("definedColumnName02");
client.deleteDefinedColumn(deleteDefinedColumnRequest);
}
步骤二:创建二级索引
使用CreateIndex接口在已存在的数据表上创建一个索引表用于加速数据查询。二级索引包括全局二级索引和本地二级索引,请根据实际创建。
您也可以使用CreateTable接口在创建数据表的同时创建一个或者多个索引表。具体操作,请参见创建数据表。
您可以通过Java SDK、Go SDK、Python SDK、Node.js SDK、.NET SDK和PHP SDK创建二级索引,此处以Java SDK为例介绍二级索引的创建。
创建全局二级索引
以下示例用于为数据表创建一个全局二级索引。
private static void createIndex(SyncClient client) {
//设置索引表名称。
IndexMeta indexMeta = new IndexMeta("<INDEX_NAME>");
//为索引表添加主键列,设置DEFINED_COL_NAME_1列为索引表的第一列主键。
indexMeta.addPrimaryKeyColumn(DEFINED_COL_NAME_1);
//为索引表添加主键列,设置PRIMARY_KEY_NAME_2列为索引表的第二列主键。
indexMeta.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2);
//为索引表添加属性列,设置DEFINED_COL_NAME_2列为索引表的属性列。
indexMeta.addDefinedColumn(DEFINED_COL_NAME_2);
//添加索引表到数据表,包含存量数据。
//CreateIndexRequest request = new CreateIndexRequest("<TABLE_NAME>", indexMeta, true);
//添加索引表到数据表,不包含存量数据。
CreateIndexRequest request = new CreateIndexRequest("<TABLE_NAME>", indexMeta, false);
/**通过将IncludeBaseData参数设置为true,创建索引表后会开启数据表中存量数据的同步,然后可以通过索引表查询全部数据,
同步时间和数据量的大小有一定的关系。
*/
//request.setIncludeBaseData(true);
//创建索引表。
client.createIndex(request);
}
创建本地二级索引
以下示例用于创建一个本地二级索引。
private static void createIndex(SyncClient client) {
//设置索引表名称。
IndexMeta indexMeta = new IndexMeta("<INDEX_NAME>");
//为索引表添加主键列,设置PRIMARY_KEY_NAME_1列为索引表的第一列主键。
//本地二级索引的第一列主键必须与数据表的第一列主键相同。
indexMeta.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1);
//为索引表添加主键列,设置DEFINED_COL_NAME_1列为索引表的第二列主键。
indexMeta.addPrimaryKeyColumn(DEFINED_COL_NAME_1);
//为索引表添加属性列,设置DEFINED_COL_NAME_2列为索引表的属性列。
indexMeta.addDefinedColumn(DEFINED_COL_NAME_2);
//设置索引类型为IT_LOCAL_INDEX(本地二级索引)。
indexMeta.setIndexType(IT_LOCAL_INDEX);
//设置同步模式为IUM_SYNC_INDEX(同步更新)。
indexMeta.setIndexUpdateMode(IUM_SYNC_INDEX);
//添加索引表到数据表,包含存量数据。
//CreateIndexRequest request = new CreateIndexRequest("<TABLE_NAME>", indexMeta, true);
//添加索引表到数据表,不包含存量数据。
CreateIndexRequest request = new CreateIndexRequest("<TABLE_NAME>", indexMeta, false);
/**通过将IncludeBaseData参数设置为true,创建索引表后会开启数据表中存量数据的同步,然后可以通过索引表查询全部数据,
同步时间和数据量的大小有一定的关系。
*/
//request.setIncludeBaseData(true);
//创建索引表。
client.createIndex(request);
}
步骤三:读取索引表中数据
从索引表中单行或者范围读取数据,当返回的属性列在索引表中时,您可以直接读取索引表获取数据,否则请自行反查数据表获取数据。
您可以通过Java SDK、Go SDK、Python SDK、Node.js SDK、.NET SDK和PHP SDK读取二级索引表中的数据,此处以Java SDK为例介绍二级索引的数据读取。
单行读取数据
读取一行数据。
以下示例用于使用索引表读取一行数据,设置读取指定的列。
private static void getRowFromIndex(SyncClient client) {
//构造主键。如果读取本地二级索引中的数据,索引表的第一列主键必须与数据表的第一列主键相同。
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
primaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.fromString("def1"));
primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.fromLong(100));
primaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.fromString("pri1"));
PrimaryKey primaryKey = primaryKeyBuilder.build();
//读取一行数据,设置索引表名称。
SingleRowQueryCriteria criteria = new SingleRowQueryCriteria("<INDEX_NAME>", primaryKey);
//设置读取最新版本。
criteria.setMaxVersions(1);
GetRowResponse getRowResponse = client.getRow(new GetRowRequest(criteria));
Row row = getRowResponse.getRow();
//如果读取的行不存在,则返回值为null。
System.out.println("读取完毕,结果为: ");
System.out.println(row);
//设置读取某些列。
criteria.addColumnsToGet("Col0");
getRowResponse = client.getRow(new GetRowRequest(criteria));
row = getRowResponse.getRow();
System.out.println("读取完毕,结果为:");
System.out.println(row);
}
范围读取数据
读取指定主键范围内的数据。
使用全局二级索引
当需要返回的属性列在索引表中时,可以直接读取索引表获取数据。
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为例介绍二级索引的删除。
以下示例用于删除指定索引表。
private static void deleteIndex(SyncClient client) {
//设置数据表名称和索引表名称。
DeleteIndexRequest request = new DeleteIndexRequest("<TABLE_NAME>", "<INDEX_NAME>");
//删除索引表。
client.deleteIndex(request);
}
常见问题
相关文档
您还可以使用控制台或者命令行工具使用二级索引。更多信息,请参见通过控制台使用二级索引和通过命令行工具使用二级索引。
如果需要更灵活丰富的数据加速查询方式,例如多条件组合查询、全文检索、前缀查询、模糊查询等,您可以使用多元索引实现。更多信息,请参见多元索引简介。