通过SDK使用二级索引

二级索引相当于把数据表的主键查询能力扩展到了不同的列,当需要使用属性查询数据时,您可以通过创建二级索引加快数据查询的效率。设置预定义列后,在创建二级索引时将预定义列作为索引表的索引列或者属性列。创建二级索引后,您可以使用二级索引进行数据查询。

前提条件

已创建数据表,且数据表的最大版本数(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);
}

删除预定义列

删除数据表上不需要的预定义列。

以下示例用于删除数据表的预定义列definedColumnName01definedColumnName02。

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 SDKGo SDKPython SDKNode.js SDK.NET SDKPHP 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 SDKGo SDKPython SDKNode.js SDK.NET SDKPHP 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 SDKGo SDKPython SDKNode.js SDK.NET SDKPHP SDK删除二级索引,此处以Java SDK为例介绍二级索引的删除。

以下示例用于删除指定索引表。

private static void deleteIndex(SyncClient client) {
    //设置数据表名称和索引表名称。
    DeleteIndexRequest request = new DeleteIndexRequest("<TABLE_NAME>", "<INDEX_NAME>"); 
    //删除索引表。
    client.deleteIndex(request); 
}

常见问题

相关文档