すべてのプロダクト
Search
ドキュメントセンター

Tablestore:シナリオ

最終更新日:Sep 10, 2026

セカンダリインデックスは、さまざまなシナリオでクエリ効率を向上させます。指定したカラムにインデックスを作成できます。作成されたインデックステーブル内のデータは、これらのインデックスカラムによってソートされます。プライマリテーブルにデータを書き込むと、データは自動的にインデックステーブルに同期され、インデックステーブルへのクエリによってデータを迅速に取得できます。

シナリオ例

通話記録をクエリするシナリオでは、各通話に関する情報が通話終了後にデータテーブルに保存されます。

データテーブルのプライマリキーと事前定義列は次のとおりです:

  • CellNumber と StartTime がプライマリキーです。これらはそれぞれ、発信者番号と通話開始時刻を表します。

  • CalledNumber、Duration、BaseStationNumber が事前定義列です。これらはそれぞれ、着信者番号、通話時間、基地局番号を表します。

次の表は、データテーブルのサンプルデータを示しています。Tablestore のワイドテーブルモデルは、すべての行をプライマリキーでソートし、データを読み取るためのシーケンシャルスキャン (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 へのすべての着信通話記録をクエリする。

  • タイムスタンプ 1532574740 以降に開始された、基地局 2 からのすべての通話記録をクエリする。

  • 基地局 3 で、タイムスタンプ 1532574861 から 1532584054 の間に発生したすべての通話の通話時間をクエリする。

  • 基地局 3 で、タイムスタンプ 1532574861 から 1532584054 の間に発生したすべての通話について、通話時間の合計、平均、最大値、最小値をクエリする。

  • 発信者番号 456789 から着信者番号 345678 へのすべての通話記録をクエリする。

データクエリ

要件に応じて適切なクエリ メソッドを選択してください。

実装方法

次の表に、各クエリ要件の実装方法を示します。

重要
  • テーブルとセカンダリインデックスの作成例については、「付録:データテーブルとセカンダリインデックスの作成例」をご参照ください。

    プライマリテーブルを作成した後、サンプルデータを書き込みます。データは自動的にインデックステーブルに同期されます。データの書き込み方法の詳細については、「データの書き込み」をご参照ください。

  • システムは自動的にプライマリキー補完を実行します。これにより、プライマリテーブルのプライマリキー列がインデックス列に追加され、インデックステーブルのプライマリキーが形成されます。

  • ローカルセカンダリインデックスの最初のプライマリキー列は、プライマリテーブルの最初のプライマリキー列と同じである必要があります。

クエリ要件

実装方法

番号 234567 のすべての発信通話記録をクエリする。

getRange API を呼び出して、データテーブルをスキャンします。

番号 123456 のすべての着信通話記録をクエリする。

CalledNumber 列にインデックスを作成します。次に、getRange API を呼び出して、インデックステーブルをスキャンします。

タイムスタンプ 1532574740 以降に開始された、基地局 002 からのすべての通話記録をクエリする。

BaseStationNumber 列と StartTime 列に複合インデックスを作成します。次に、getRange API を呼び出して、インデックステーブル (グローバルセカンダリインデックス) をスキャンします。

タイムスタンプ 1532574861 と 1532584054 の間に基地局 003 で発生したすべての通話の通話時間をクエリする。

BaseStationNumber 列と StartTime 列に複合インデックスを作成し、Duration 列を属性列としてインデックスに含めます。次に、getRange API を呼び出して、インデックステーブル (グローバルセカンダリインデックス) をスキャンします。

タイムスタンプ 1532574861 と 1532584054 の間に基地局 003 で発生したすべての通話の合計、平均、最大、最小の通話時間をクエリするには、同じ実装方法を使用します。次に、返された各通話時間から最終結果を計算します。

説明

Tablestore SQL クエリを使用することもできます。この方法では、クライアントで計算を実行する必要はありません。SQL ステートメントを使用して、最終的な統計結果を直接取得できます。詳細については、「データのクエリ」をご参照ください。

発信者番号 456789 から着信者番号 345678 へのすべての通話記録をクエリする。

発信者番号に対応する CellNumber 列と、着信者番号に対応する CalledNumber 列に複合インデックスを作成します。Duration 列と BaseStationNumber 列を属性列としてインデックステーブルに含めます。次に、getRange API を呼び出して、インデックステーブル (ローカルセカンダリインデックス) をスキャンします。

番号 234567 のすべての発信通話記録のクエリ

CellNumber 列はプライマリテーブルのプライマリキーであり、高速なクエリが可能です。GetRange API を呼び出してプライマリテーブルをスキャンし、結果を取得できます。

GetRange API を呼び出す際は、CellNumber 列の値を 234567 に設定します。StartTime 列については、検索範囲の開始を 0 (この値を含む)、終了を PrimaryKeyValue.INF_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 を最初のプライマリキー列とする IndexOnBeCalledNumber という名前のインデックスを作成できます。その後、getRange API を呼び出してインデックステーブルをスキャンし、結果を取得できます。

インデックステーブルの最初のプライマリキー列がプライマリテーブルの最初のプライマリキー列と異なるため、このインデックスはグローバルセカンダリインデックスです。

インデックステーブルのデータ

次の表は、IndexOnBeCalledNumber インデックステーブルのデータを示しています。

DEFINED_COL_NAME_1

PRIMARY_KEY_NAME_1

PRIMARY_KEY_NAME_2

CalledNumber

CellNumber

StartTime

123456

234567

1532574734

123456

345678

1532574795

123456

345678

1532574861

345678

456789

1532584054

654321

123456

1532574644

765432

234567

1532574714

GetRange API を呼び出す際は、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;
        }
    }
}

タイムスタンプ 1532574740 以降に開始された、基地局 002 からのすべての通話記録のクエリ

このクエリは、BaseStationNumber 列と StartTime 列を条件として使用します。BaseStationNumber はベーステーブルの事前定義列であり、高速クエリをサポートしていません。この問題を解決するには、BaseStationNumber 列と StartTime 列に IndexOnBaseStation1 という名前の複合インデックスを作成します。これらの列をインデックステーブルのプライマリキーとして使用します。その後、getRange API を呼び出してインデックステーブルをスキャンし、結果を取得します。

インデックステーブルの最初のプライマリキー列がベーステーブルの最初のプライマリキー列と異なるため、このインデックスはグローバルセカンダリインデックスです。

インデックステーブルのデータ

次の表は、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 API を呼び出してデータをクエリする際は、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;
        }
    }
}

タイムスタンプ 1532574861 と 1532584054 の間に基地局 003 で発生したすべての通話の期間のクエリ

BaseStationNumber 列と StartTime 列をクエリ条件として使用し、Duration 列のみを取得するため、「1532574740 以降に基地局 002 からのすべての通話記録をクエリ」シナリオの 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 列に IndexOnBaseStation2 という名前の複合インデックスを作成できます。Duration 列を属性列としてインデックステーブルに含めます。その後、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 列の最小値と最大値の両方を「003」に設定します。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 はプライマリテーブルの事前定義列であり、高速クエリをサポートしていません。この問題を解決するには、LocalIndexOnBeCalledNumber という名前の複合インデックスを作成します。このインデックスでは、CellNumber 列、CalledNumber 列、および StartTime 列をプライマリキーとして使用します。Duration 列と BaseStationNumber 列は属性列として含めます。その後、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("All call records between number " + strNum + " and number " + 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));
    // データの有効期間 (TTL) (秒)。値が -1 の場合、データは期限切れになりません。インデックステーブルを持つプライマリテーブルの TTL は -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);
}