使用场景

二级索引支持在指定列上建立索引,生成的索引表中的数据按照指定的索引列进行排序,数据表的每一个数据写入都会自动同步到索引表中。您只需向数据表中写入数据,然后根据索引表进行查询,在许多场景下能提高查询的效率。

样例场景

在电话话单查询场景下,每次用户通话结束后,都会将此次通话的信息记录到该数据表中。

数据表的主键和预定义列如下:

  • CellNumber、StartTime作为数据表的主键,分别代表主叫号码和通话发生时间。

  • CalledNumber、DurationBaseStationNumber为数据表的预定义列,分别代表被叫号码、通话时长和基站号码。

数据表的样例数据请参见下表。表格存储的宽表模型是对所有行按照主键进行排序,并且提供顺序扫描(GetRange)接口用于数据读取。

CellNumber

StartTime(Unix时间戳)

CalledNumber

Duration

BaseStationNumber

123456

1532574644

654321

60

1

234567

1532574714

765432

10

1

234567

1532574734

123456

20

3

345678

1532574795

123456

5

2

345678

1532574861

123456

100

2

456789

1532584054

345678

200

3

假设如下查询需求,请根据实际情况通过数据表、全局二级索引或者本地二级索引查询所需数据。

  • 查询号码234567的所有主叫话单

  • 查询号码123456的被叫话单

  • 查询基站002从时间1532574740开始的所有话单

  • 查询发生在基站003上时间从15325748611532584054的所有通话记录的通话时长

  • 查询发生在基站003上时间从15325748611532584054的所有通话记录的总通话时长、平均通话时长、最大通话时长和最小通话时长

  • 查询主叫号码456789到被叫号码345678的所有话单

数据查询

请根据查询需求选择合适的查询方式。

实现方式

不同查询需求的具体实现方式请参见下表说明。

重要
  • 关于创建表和二级索引的示例请参见附录:创建数据表和二级索引示例

    创建数据表后需要写入样例数据到数据表,数据表中的数据会自动同步到索引表中。关于写入数据的具体操作,请参见写入数据

  • 系统会自动进行索引列补齐,即把数据表的主键添加到索引列后,共同作为索引表的主键。

  • 本地二级索引的第一个主键列必须与数据表的第一个主键列相同。

查询需求

实现方式

查询号码234567的所有主叫话单

直接调用getRange接口对数据表进行扫描。

查询号码123456的被叫话单

CalledNumber列上建立索引,然后调用getRange接口对索引表进行扫描。

查询基站002从时间1532574740开始的所有话单

BaseStationNumberStartTime列上建立组合索引,然后调用getRange接口对索引表(全局二级索引)进行扫描。

查询发生在基站003上时间从15325748611532584054的所有通话记录的通话时长

BaseStationNumberStartTime列上建立组合索引,而且只把Duration列作为返回结果,然后调用getRange接口对索引表(全局二级索引)进行扫描。

您可以手动反查数据表获取Duration列值或者将Duration列作为索引表的属性列。

如果要查询发生在基站003上时间从15325748611532584054的所有通话记录的总通话时长、平均通话时长、最大通话时长和最小通话时长,您可以使用与本查询需求相同的实现方式,然后对返回的每条通话时长做计算并得到最终结果。

说明

您也可以使用表格存储SQL查询,无需客户端计算,直接使用SQL语句返回最终统计结果。更多信息,请参见查询数据

查询主叫号码456789到被叫号码345678的所有话单

CellNumber列和CalledNumber列上建立组合索引,而且将Duration列和BaseStationNumber列作为索引表的属性列,然后调用getRange接口对索引表(本地二级索引)进行扫描。

查询号码234567的所有主叫话单

由于CellNumber列为数据表的主键,支持调用GetRange接口进行快速查询,因此您可以直接调用getRange接口扫描数据表获取结果。

调用GetRange接口查询数据时,您可以将CellNumber列的最大值和最小值均设置为234567,StartTime列的最小值设置为0且最大值设置为INT_MAX。

具体示例代码如下:

//示例中的cellNumber参数对应于数据表中的CellNumber列。
private static void getRangeFromMainTable(SyncClient client, long cellNumber){
    RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria(TABLE_NAME);

    //构造起始主键。
    PrimaryKeyBuilder startPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.fromLong(cellNumber));
    startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.fromLong(0));
    rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startPrimaryKeyBuilder.build());

    //构造结束主键。
    PrimaryKeyBuilder endPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.fromLong(cellNumber));
    endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MAX);
    rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endPrimaryKeyBuilder.build());

    rangeRowQueryCriteria.setMaxVersions(1);

    String strNum = String.format("%d", cellNumber);
    System.out.println("号码" + strNum + "的所有主叫话单:");
    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;
        }
    }
}

查询号码123456的被叫话单

由于要使用CalledNumber列作为查询条件,但是CalledNumber列为数据表的预定义列,无法直接进行快速查询,因此您可以在CalledNumber列上建立索引,将CalledNumber列作为索引表的主键,索引名称为IndexOnBeCalledNumber,然后直接调用getRange接口扫描索引表获取结果。

由于索引表的第一列主键与数据表的第一列主键不同,因此索引类型为全局二级索引。

索引表数据

索引表IndexOnBeCalledNumber的数据请参见下表。

PK0

PK1

PK2

CalledNumber

CellNumber

StartTime

123456

234567

1532574734

123456

345678

1532574795

123456

345678

1532574861

345678

456789

1532584054

654321

123456

1532574644

765432

234567

1532574714

调用GetRange接口查询数据时,您可以将CalledNumber列的最大值和最小值均设置为123456,CellNumber列和StartTime列的最小值设置为INT_MIN且最大值设置为INT_MAX。具体示例代码如下:

//示例中的calledNumber参数对应于索引表中的CalledNumber列。
private static void getRangeFromIndexTable(SyncClient client, long calledNumber) {
    RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria(INDEX0_NAME);

    //构造起始主键。
    PrimaryKeyBuilder startPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    startPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.fromLong(calledNumber));
    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.fromLong(calledNumber));
    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);

    String strNum = String.format("%d", calledNumber);
    System.out.println("号码" + strNum + "的所有被叫话单:");
    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;
        }
    }
}

查询基站002从时间1532574740开始的所有话单

由于要使用BaseStationNumber列和StartTime列作为查询条件,其中BaseStationNumber列为数据表的预定义列,无法进行快速查询,因此您可以在BaseStationNumber列和StartTime列上建立组合索引,将BaseStationNumber列和StartTime列作为索引表的主键,索引表名称为IndexOnBaseStation1,然后直接调用getRange接口扫描索引表获取结果。

由于索引表的第一列主键与数据表的第一列主键不同,因此索引类型为全局二级索引。

索引表数据

索引表IndexOnBaseStation1的数据请参见下表。

PK0

PK1

PK2

BaseStationNumber

StartTime

CellNumber

1

1532574644

123456

1

1532574714

234567

2

1532574795

345678

2

1532574861

345678

3

1532574734

234567

3

1532584054

456789

调用GetRange接口查询数据时,您可以将BaseStationNumber列的最大值和最小值均设置为2,StartTime列的最小值设置为1532574740且最大值设置为INT_MAX,CellNumber列的最小值设置为INT_MIN且最大值设置为INT_MAX。具体示例代码如下:

//示例中的baseStationNumber参数对应于索引表中的BaseStationNumber列。
//示例中的startTime参数对应于索引表中StartTime列的起始时间。
private static void getRangeFromIndexTable(SyncClient client,
                                           long baseStationNumber,
                                           long startTime) {
    RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria(INDEX1_NAME);

    //构造起始主键。
    PrimaryKeyBuilder startPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    startPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_3, PrimaryKeyValue.fromLong(baseStationNumber));
    startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.fromLong(startTime));
    startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MIN);
    rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startPrimaryKeyBuilder.build());

    //构造结束主键。
    PrimaryKeyBuilder endPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    endPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_3, PrimaryKeyValue.fromLong(baseStationNumber));
    endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MAX);
    endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MAX);
    rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endPrimaryKeyBuilder.build());

    rangeRowQueryCriteria.setMaxVersions(1);

    String strBaseStationNum = String.format("%d", baseStationNumber);
    String strStartTime = String.format("%d", startTime);
    System.out.println("基站" + strBaseStationNum + "从时间" + strStartTime + "开始的所有被叫话单:");
    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;
        }
    }
}

查询发生在基站003上时间从15325748611532584054的所有通话记录的通话时长

由于要使用BaseStationNumber列和StartTime列作为查询条件,而且只将Duration列作为返回结果,因此您可以使用查询基站002从时间1532574740开始的所有话单中的索引表IndexOnBaseStation1,查询索引表成功后反查数据表获取通话时长。

由于索引表的第一列主键与数据表的第一列主键不同,因此索引类型为全局二级索引。

具体示例代码如下:

//示例中的baseStationNumber参数对应于索引表中的BaseStationNumber列。
//示例中的startTime和endTime参数对应于索引表中要查询的StartTime列值的开始时间和结束时间。
//示例中的DEFINED_COL_NAME_2参数对应于要反查的数据表中的Duration列。
private static void getRowFromIndexAndMainTable(SyncClient client,
 long baseStationNumber,
 long startTime,
 long endTime) {
 RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria(INDEX1_NAME);

 //构造起始主键。
 PrimaryKeyBuilder startPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
 startPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_3, PrimaryKeyValue.fromLong(baseStationNumber));
 startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.fromLong(startTime));
 startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MIN);
 rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startPrimaryKeyBuilder.build());

 //构造结束主键。
 PrimaryKeyBuilder endPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
 endPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_3, PrimaryKeyValue.fromLong(baseStationNumber));
 endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.fromLong(endTime));
 endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MAX);
 rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endPrimaryKeyBuilder.build());

 rangeRowQueryCriteria.setMaxVersions(1);

 String strBaseStationNum = String.format("%d", baseStationNumber);
 String strStartTime = String.format("%d", startTime);
 String strEndTime = String.format("%d", endTime);

 System.out.println("基站" + strBaseStationNum + "从时间" + strStartTime + "到" + strEndTime + "的所有话单通话时长:");
 while (true) {
 GetRangeResponse getRangeResponse = client.getRange(new GetRangeRequest(rangeRowQueryCriteria));
 for (Row row : getRangeResponse.getRows()) {
 PrimaryKey curIndexPrimaryKey = row.getPrimaryKey();
 //构造数据表主键。
 PrimaryKeyColumn mainCalledNumber = curIndexPrimaryKey.getPrimaryKeyColumn(PRIMARY_KEY_NAME_1);
 PrimaryKeyColumn callStartTime = curIndexPrimaryKey.getPrimaryKeyColumn(PRIMARY_KEY_NAME_2);
 PrimaryKeyBuilder mainTablePKBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
 mainTablePKBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, mainCalledNumber.getValue());
 mainTablePKBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, callStartTime.getValue());
 PrimaryKey mainTablePK = mainTablePKBuilder.build(); 

 //反查数据表。
 SingleRowQueryCriteria criteria = new SingleRowQueryCriteria(TABLE_NAME, mainTablePK);
 //读取数据表的Duration列。
 criteria.addColumnsToGet(DEFINED_COL_NAME_2); 
 //设置读取最新版本。
 criteria.setMaxVersions(1);
 GetRowResponse getRowResponse = client.getRow(new GetRowRequest(criteria));
 Row mainTableRow = getRowResponse.getRow();

 System.out.println(mainTableRow);
 }

 //如果nextStartPrimaryKey不为null,则继续读取数据。
 if (getRangeResponse.getNextStartPrimaryKey() != null) {
 rangeRowQueryCriteria.setInclusiveStartPrimaryKey(getRangeResponse.getNextStartPrimaryKey());
 } else {
 break;
 }
 }
}

为了提高查询效率,您可以在BaseStationNumber列和StartTime列上建立组合索引,并将Duration列作为索引表的属性列,索引表名称为IndexOnBaseStation2,然后直接调用getRange接口扫描索引表获取结果。

索引表数据

索引表IndexOnBaseStation2的数据请参见下表。

PK0

PK1

PK2

Defined0

BaseStationNumber

StartTime

CellNumber

Duration

1

1532574644

123456

60

1

1532574714

234567

10

2

1532574795

345678

5

2

1532574861

345678

100

3

1532574734

234567

20

3

1532584054

456789

200

调用GetRange接口查询数据时,您可以将BaseStationNumber列的最大值和最小值均设置为3,StartTime列的最小值设置为1532574861且最大值设置为1532584054,CellNumber列的最小值设置为INT_MIN且最大值设置为INT_MAX。

具体示例代码如下:

//示例中的baseStationNumber参数对应于索引表中的BaseStationNumber列。
//示例中的startTime和endTime参数对应于索引表中要查询的StartTime列值的开始时间和结束时间。
//示例中的DEFINED_COL_NAME_2参数对应于索引表中的Duration列。
private static void getRangeFromIndexTable(SyncClient client,
 long baseStationNumber,
 long startTime,
 long endTime) {
 RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria(INDEX2_NAME);

 //构造起始主键。
 PrimaryKeyBuilder startPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
 startPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_3, PrimaryKeyValue.fromLong(baseStationNumber));
 startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.fromLong(startTime));
 startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MIN);
 rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startPrimaryKeyBuilder.build());

 //构造结束主键。
 PrimaryKeyBuilder endPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
 endPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_3, PrimaryKeyValue.fromLong(baseStationNumber));
 endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.fromLong(endTime));
 endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.INF_MAX);
 rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endPrimaryKeyBuilder.build());

 //设置要读取的列。
 rangeRowQueryCriteria.addColumnsToGet(DEFINED_COL_NAME_2);

 rangeRowQueryCriteria.setMaxVersions(1);

 String strBaseStationNum = String.format("%d", baseStationNumber);
 String strStartTime = String.format("%d", startTime);
 String strEndTime = String.format("%d", endTime);

 System.out.println("基站" + strBaseStationNum + "从时间" + strStartTime + "到" + strEndTime + "的所有话单通话时长:");
 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;
 }
 }
}

查询主叫号码456789到被叫号码345678的所有话单

由于要使用CellNumber列和CalledNumber列作为查询条件,其中CalledNumber列为数据表的预定义列,无法进行快速查询,因此您需要在CellNumber列和CalledNumber列上建立组合索引,将CellNumber列和CalledNumber列作为索引表的主键,并将Duration列和BaseStationNumber列作为索引表的属性列,索引表名称为LocalIndexOnBeCalledNumber,然后直接调用getRange接口扫描索引表获取结果。

由于索引表的第一列主键与数据表的第一列主键相同,因此索引类型为本地二级索引。

索引表数据

索引表LocalIndexOnBeCalledNumber的数据请参见下表。

PK0

Defined0

PK1

Defined1

Defined2

CellNumber

CalledNumber

StartTime(Unix时间戳)

Duration

BaseStationNumber

123456

654321

1532574644

60

1

234567

123456

1532574734

20

3

234567

765432

1532574714

10

1

345678

123456

1532574795

5

2

345678

123456

1532574861

100

2

456789

345678

1532584054

200

3

调用GetRange接口查询数据时,您可以将CellNumber列的最大值和最小值均设置为456789,CalledNumber列的最大值和最小值均设置为345678,StartTime列的最小值设置为0且最大值设置为INT_MAX。具体示例代码如下:

//示例中的cellNumber、calledNumber参数分别对应于索引表中的CellNumber列和CalledNumber列。
private static void getRangeFromLocalIndex(SyncClient client, long cellNumber, long calledNumber){

    RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria(INDEX3_NAME);

    // 构造起始主键。
    PrimaryKeyBuilder startPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.fromLong(cellNumber));
    startPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.fromLong(calledNumber));
    startPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.fromLong(0));
    rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startPrimaryKeyBuilder.build());

    // 构造结束主键。
    PrimaryKeyBuilder endPrimaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1, PrimaryKeyValue.fromLong(cellNumber));
    endPrimaryKeyBuilder.addPrimaryKeyColumn(DEFINED_COL_NAME_1, PrimaryKeyValue.fromLong(calledNumber));
    endPrimaryKeyBuilder.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2, PrimaryKeyValue.INF_MAX);
    rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endPrimaryKeyBuilder.build());

    rangeRowQueryCriteria.setMaxVersions(1);

    String strNum = String.format("%d", cellNumber);
    String strCalledNum = String.format("%d", calledNumber);
    System.out.println("号码" + strNum + "和号码" +strCalledNum+ "的所有话单:");
    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 final String TABLE_NAME = "CallRecordTable";
private static final String INDEX0_NAME = "IndexOnBeCalledNumber";
private static final String INDEX1_NAME = "IndexOnBaseStation1";
private static final String INDEX2_NAME = "IndexOnBaseStation2";
private static final String INDEX3_NAME = "LocalIndexOnBeCalledNumber";
private static final String PRIMARY_KEY_NAME_1 = "CellNumber";
private static final String PRIMARY_KEY_NAME_2 = "StartTime";
private static final String DEFINED_COL_NAME_1 = "CalledNumber";
private static final String DEFINED_COL_NAME_2 = "Duration";
private static final String DEFINED_COL_NAME_3 = "BaseStationNumber";

private static void createTable(SyncClient client) {
    TableMeta tableMeta = new TableMeta(TABLE_NAME);
    tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema(PRIMARY_KEY_NAME_1, PrimaryKeyType.INTEGER));
    tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema(PRIMARY_KEY_NAME_2, PrimaryKeyType.INTEGER));
    tableMeta.addDefinedColumn(new DefinedColumnSchema(DEFINED_COL_NAME_1, DefinedColumnType.INTEGER));
    tableMeta.addDefinedColumn(new DefinedColumnSchema(DEFINED_COL_NAME_2, DefinedColumnType.INTEGER));
    tableMeta.addDefinedColumn(new DefinedColumnSchema(DEFINED_COL_NAME_3, DefinedColumnType.INTEGER));
    //数据的过期时间, 单位秒, -1代表永不过期. 带索引表的主表数据过期时间必须为-1。
    int timeToLive = -1; 
    //保存的最大版本数, 带索引表的主表最大版本数必须为1。
    int maxVersions = 1; 

    TableOptions tableOptions = new TableOptions(timeToLive, maxVersions);

    ArrayList<IndexMeta> indexMetas = new ArrayList<IndexMeta>();
 
    IndexMeta indexMeta0 = new IndexMeta(INDEX0_NAME);
    indexMeta0.addPrimaryKeyColumn(DEFINED_COL_NAME_1);
    indexMetas.add(indexMeta0);
   
    IndexMeta indexMeta1 = new IndexMeta(INDEX1_NAME);
    indexMeta1.addPrimaryKeyColumn(DEFINED_COL_NAME_3);
    indexMeta1.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2);
    indexMetas.add(indexMeta1);
   
    IndexMeta indexMeta2 = new IndexMeta(INDEX2_NAME);
    indexMeta2.addPrimaryKeyColumn(DEFINED_COL_NAME_3);
    indexMeta2.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2);
    indexMeta2.addDefinedColumn(DEFINED_COL_NAME_2);
    indexMetas.add(indexMeta2);
 
    IndexMeta indexMeta3 = new IndexMeta(INDEX3_NAME);
    indexMeta3.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1);
    indexMeta3.addPrimaryKeyColumn(DEFINED_COL_NAME_1);
    indexMeta3.addDefinedColumn(DEFINED_COL_NAME_2);
    indexMeta3.addDefinedColumn(DEFINED_COL_NAME_3);
    //设置索引同步模式。
    indexMeta3.setIndexUpdateMode(IUM_SYNC_INDEX);
    //设置索引类型为IT_LOCAL_INDEX(本地二级索引)。
    indexMeta3.setIndexType(IT_LOCAL_INDEX);
    indexMetas.add(indexMeta3);
 
    CreateTableRequest request = new CreateTableRequest(tableMeta, tableOptions, indexMetas);

    client.createTable(request);
}