全部產品
Search
文件中心

Tablestore:使用情境

更新時間:Jun 30, 2024

二級索引支援在指定列上建立索引,產生的索引表中的資料按照指定的索引列進行排序,資料表的每一個資料寫入都會自動同步到索引表中。您只需向資料表中寫入資料,然後根據索引表進行查詢,在許多情境下能提高查詢的效率。

範例情境

在電話話單查詢情境下,每次使用者通話結束後,都會將此次通話的資訊記錄到該資料表中。

資料表的主鍵和預定義列如下:

  • CellNumber、StartTime作為資料表的主鍵,分別代表主叫號碼和通話發生時間。

  • CalledNumber、Duration和BaseStationNumber為資料表的預定義列,分別代表被叫號碼、通話時間長度和基站號碼。

資料表的範例資料請參見下表。Table Store的寬表模型是對所有行按照主鍵進行排序,並且提供順序掃描(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上時間從1532574861到1532584054的所有通話記錄的通話時間長度

  • 查詢發生在基站003上時間從1532574861到1532584054的所有通話記錄的總通話時間長度、平均通話時間長度、最大通話時間長度和最小通話時間長度

  • 查詢主叫號碼456789到被叫號碼345678的所有話單

資料查詢

請根據查詢需求選擇合適的查詢方式。

實現方式

不同查詢需求的具體實現方式請參見下表說明。

重要
  • 關於建立表和二級索引的樣本請參見附錄:建立資料表和二級索引樣本

    建立資料表後需要寫入範例資料到資料表,資料表中的資料會自動同步到索引表中。關於寫入資料的具體操作,請參見寫入資料

  • 系統會自動進行索引列補齊,即把資料表的主鍵添加到索引列後,共同作為索引表的主鍵。

  • 本地二級索引的第一個主鍵列必須與資料表的第一個主鍵列相同。

查詢需求

實現方式

查詢號碼234567的所有主叫話單

直接調用getRange介面對資料表進行掃描。

查詢號碼123456的被叫話單

在CalledNumber列上建立索引,然後調用getRange介面對索引表進行掃描。

查詢基站002從時間1532574740開始的所有話單

在BaseStationNumber和StartTime列上建立複合式索引,然後調用getRange介面對索引表(全域二級索引)進行掃描。

查詢發生在基站003上時間從1532574861到1532584054的所有通話記錄的通話時間長度

在BaseStationNumber和StartTime列上建立複合式索引,而且只把Duration列作為返回結果,然後調用getRange介面對索引表(全域二級索引)進行掃描。

您可以手動反查資料表擷取Duration列值或者將Duration列作為索引表的屬性列。

如果要查詢發生在基站003上時間從1532574861到1532584054的所有通話記錄的總通話時間長度、平均通話時間長度、最大通話時間長度和最小通話時間長度,您可以使用與本查詢需求相同的實現方式,然後對返回的每條通話時間長度做計算並得到最終結果。

說明

您也可以使用Table StoreSQL查詢,無需用戶端計算,直接使用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上時間從1532574861到1532584054的所有通話記錄的通話時間長度

由於要使用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);
}