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

Tablestore:結果のソートとページング

最終更新日:May 13, 2026

多次元インデックスを使用してデータをクエリする場合、あらかじめソート順序を定義するか、クエリ時に順序を指定して、特定の順序で結果を取得できます。結果セットが大きい場合は、オフセットベースまたはトークンベースのページングを使用して、必要なデータをすばやく特定できます。

インデックスソート

デフォルトでは、多次元インデックスはインデックスソートに基づいてデータをソートします。多次元インデックスでデータをクエリする際、このIndexSort設定によってデフォルトのソート順序が決まります。

多次元インデックスを作成する際に、カスタムIndexSortを定義できます。指定しない場合、多次元インデックスはデフォルトでプライマリキーによりソートされます。

重要
  • インデックスソートは、PrimaryKeySort (プライマリキーでソート) とFieldSort (フィールド値でソート) のみをサポートします。

  • ネスト型のフィールドを含む多次元インデックスでは、インデックスソートはサポートされません。

クエリ時のソート

enableSortAndAggtrueに設定されているフィールドでのみソートできます。

各クエリに対してソート順序を指定できます。多次元インデックスは、次の 4 種類のソーター (Sorter) をサポートします。ソーターを組み合わせて、多段 (マルチレベル) ソートを作成することもできます。

ScoreSort

BM25 アルゴリズムで計算される関連度スコアに基づいて結果をソートします。全文検索などのシナリオに適しています。

重要

関連度スコアで結果をソートする必要がある場合は、ScoreSortを明示的に指定する必要があります。指定しない場合、結果は多次元インデックスのIndexSort設定に基づいてソートされます。

SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new ScoreSort())));

PrimaryKeySort

プライマリキーで結果をソートします。

SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new PrimaryKeySort()))); // 昇順。
//searchQuery.setSort(new Sort(Arrays.asList(new PrimaryKeySort(SortOrder.DESC)))); // 降順。

FieldSort

指定したカラムの値で結果をソートします。

単一カラムのソート

単一カラムの値で結果をソートします。

SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new FieldSort("col", SortOrder.ASC))));

複数カラムのソート

1 つのカラムの値でソートした後、別のカラムの値でソートします。

SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(
    new FieldSort("col1", SortOrder.ASC), new FieldSort("col2", SortOrder.ASC))));

フォールバックソート

Long、 Double、または Date カラムでソートする場合は、missingFieldパラメータを使用して、同じ型のフォールバックカラムを指定できます。このフォールバックは、プライマリのソートカラムに値が存在しない行に対して使用されます。

/**
* `Col_Long` を降順でソートします。行に `Col_Long` の値がない場合は、代わりに `Col_Long_sec` の値を使用します。
*/
SearchQuery searchQuery = new SearchQuery();
FieldSort fieldSort = new FieldSort("Col_Long");
// `Col_Long` の欠損値に対するフォールバックとして `Col_Long_sec` を指定します。
fieldSort.setMissingField("Col_Long_sec");
fieldSort.setOrder(SortOrder.DESC); 

欠損値のソート

ドキュメントにソートフィールドが存在しない場合は、missingValueパラメータを使用して、ソート結果内での位置を制御できます。

ソート動作は次のとおりです:

  • missingValueFieldSort.FIRST_WHEN_MISSINGに設定すると、ソート順序 (昇順または降順) に関係なく、欠損値のあるドキュメントは常に結果の先頭に配置されます。

  • missingValueFieldSort.LAST_WHEN_MISSINGに設定するか、未設定 (null) の場合、ソート順序に関係なく、欠損値のあるドキュメントは常に結果の末尾に配置されます。

    /**
     * `Col_Long` を降順でソートします。`Col_Long` の値が欠損しているドキュメントを結果の先頭に配置します。
     */
    SearchQuery searchQuery = new SearchQuery();
    FieldSort fieldSort = new FieldSort("Col_Long");
    // 欠損値のあるドキュメントを先頭に配置します。
    fieldSort.setMissingValue(FieldSort.FIRST_WHEN_MISSING);
    fieldSort.setOrder(SortOrder.DESC);
    searchQuery.setSort(new Sort(Arrays.asList(fieldSort)));

複数値フィールドのソート

配列やネスト型フィールドなどの複数値フィールドでは、modeパラメータを使用して、コレクション内のどの値をソートに使用するかを指定できます。

配列内の指定した値でソートします。

// 行 doc1 と doc2 には、field1 という名前の配列フィールドが含まれています。doc1 の field1 の値は [2,3]、doc2 の値は [1,3,4] です。
// mode パラメータを設定して、配列内のどの値をソートに使用するかを指定できます。
{
    // mode を SortMode.MAX に設定した場合、結果は doc2 (4 でソート) の後に doc1 (3 でソート) となります。
    FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
    fieldSort.setMode(SortMode.MAX);
}
{
    // mode を SortMode.MIN に設定した場合、結果は doc1 (2 でソート) の後に doc2 (1 でソート) となります。
    FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
    fieldSort.setMode(SortMode.MIN);
}

ネスト型のサブフィールド内の値でソートすることもできます。

// 行 doc1 と doc2 には、field1 という名前のネスト型フィールドが含まれています。
// doc1 の field1 の値は [{"name":"b", "age":1},{"name":"a", "age":7}] です。
// doc2 の field1 の値は [{"name":"a", "age":1},{"name":"c", "age":1},{"name":"d", "age":5}] です。

{
    // すべてのサブ行をソートし、mode パラメータでどの値をソートに使用するかを指定します。
    // mode を SortMode.MAX に設定し、age フィールドでソートした場合、結果は doc1 (7 でソート) の後に doc2 (5 でソート) となります。
    FieldSort fieldSort = new FieldSort("field1.age", SortOrder.DESC);
    fieldSort.setMode(SortMode.MAX);
    String path = "field1";
    NestedFilter nestedFilter = new NestedFilter(path, QueryBuilders.matchAll().build());
    fieldSort.setNestedFilter(nestedFilter);
}
{
    // age=1 のサブ行のみをソートし、mode パラメータでどの値をソートに使用するかを指定します。
    {
        // mode を SortMode.MAX に設定し、name フィールドでソートした場合、結果は doc2 ("c" でソート) の後に doc1 ("b" でソート) となります。
        FieldSort fieldSort = new FieldSort("field1.name", SortOrder.DESC);
        fieldSort.setMode(SortMode.MAX);
        String path = "field1";
        NestedFilter nestedFilter = new NestedFilter(path, QueryBuilders.term("field1.age",1).build());
        fieldSort.setNestedFilter(nestedFilter);
    }
    {
        // mode を SortMode.MIN に設定し、name フィールドでソートした場合、結果は doc1 ("b" でソート) の後に doc2 ("a" でソート) となります。
        FieldSort fieldSort = new FieldSort("field1.name", SortOrder.DESC);
        fieldSort.setMode(SortMode.MIN);
        String path = "field1";
        NestedFilter nestedFilter = new NestedFilter(path, QueryBuilders.term("field1.age",1).build());
        fieldSort.setNestedFilter(nestedFilter);
    }
}

GeoDistanceSort

指定した地理座標ポイントからの距離で結果をソートします。

SearchQuery searchQuery = new SearchQuery();
// `geo` (Geopoint) カラムの値からポイント "0,0" までの距離で結果をソートします。
Sort.Sorter sorter = new GeoDistanceSort("geo", Arrays.asList("0, 0"));
searchQuery.setSort(new Sort(Arrays.asList(sorter)));

ページング方法

limitoffsetパラメータ、またはトークンを使用してページングできます。

limit と offset によるページング

limitoffsetを使用してページングできますが、limitoffsetの合計は 100,000 を超えてはならず、limitの最大値は 100 です。

説明

limitを 1,000 に引き上げる方法については、「How can I increase the query result limit of the Search API to 1,000 for a search index?」をご参照ください。

指定しない場合、limitのデフォルト値は 10、offsetのデフォルト値は 0 です。

SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setLimit(100);
searchQuery.setOffset(100);

トークンベースのページング

ディープページングでは、深さ制限がないため、トークンベースのページングを推奨します。

クエリに返却すべき結果が残っている場合、レスポンスにはnextTokenが含まれます。次のリクエストでこのトークンを使用して、次ページの結果を取得します。

デフォルトでは、トークンベースのページングでは結果を前方向にのみ進めます。ただし、トークンはページングセッションの期間中は有効なため、以前のトークンをキャッシュすることで逆方向のページングを実装できます。

重要

nextToken を永続化するか、フロントエンドアプリケーションに送信するには、Base64 エンコードする必要があります。nextToken は文字列ではなく、バイト配列です。new String(nextToken) を使用して直接変換すると、トークンが破損し、データ損失が発生します。

トークンは、デフォルトのインデックスソートであってもカスタムソート順序であっても、前回リクエストのソート順序を保持します。そのため、トークンベースのリクエストではSortパラメータを指定できません。また、トークン自体が開始位置を決定するため、offsetパラメータも使用できません。

重要

ネスト型のフィールドを含む多次元インデックスでは、インデックスソートはサポートされません。このような多次元インデックスから結果をページングするには、クエリでソート順序を指定する必要があります。指定しない場合、返却すべき結果が残っていても、サーバーはnextTokenを返しません。

private static void readMoreRowsWithToken(SyncClient client) {
    SearchQuery searchQuery = new SearchQuery();
    searchQuery.setQuery(new MatchAllQuery());
    searchQuery.setGetTotalCount(true);// これを true に設定すると、マッチした行の総数が返されます。
    // テーブル名 (例:sampleTable) と多次元インデックス名 (例:sampleSearchIndex) を指定します。多次元インデックス名は、Tablestore コンソールでテーブルの [Indexes] タブに表示されるほか、SDK を使用して多次元インデックスを一覧表示して確認できます。
    SearchRequest searchRequest = new SearchRequest("<TABLE_NAME>", "<SEARCH_INDEX_NAME>", searchQuery);

    SearchResponse resp = client.search(searchRequest);
    if (!resp.isAllSuccess()) {
        throw new RuntimeException("not all success");
    }
    List<Row> rows = resp.getRows();
    while (resp.getNextToken()!=null) { // `nextToken` が null の場合は、すべてのデータを取得済みであることを意味します。
        // nextToken を取得します。
        byte[] nextToken = resp.getNextToken();

        {
            // nextToken を永続化する、またはフロントエンドアプリケーションに送信する必要がある場合は、Base64 エンコードを使用して文字列に変換します。
            // トークン自体は文字列ではありません。new String(nextToken) を使用して直接変換するとトークンが破損します。
            String tokenAsString = Base64.toBase64String(nextToken);
            // 文字列をバイト配列にデコードします。
            byte[] tokenAsByte = Base64.fromBase64String(tokenAsString);
        }

        // 次のリクエストにトークンを設定します。
        searchRequest.getSearchQuery().setToken(nextToken);
        resp = client.search(searchRequest);
        if (!resp.isAllSuccess()) {
            throw new RuntimeException("not all success");
        }
        rows.addAll(resp.getRows());
    }
    System.out.println("RowSize: " + rows.size());
    System.out.println("TotalCount: " + resp.getTotalCount());// このレスポンスで返された行数ではなく、マッチした行の総数を出力します。
}

よくある質問

関連ドキュメント

  • 多次元インデックスは、 Term queryTerms queryMatchAll queryMatch queryMatchPhrase queryPrefix query範囲クエリWildcard queryGeo queryVector queryBoolean queryNested queryExists query など、さまざまなクエリタイプをサポートします。多次元データの取得には、用途に応じて適切なクエリタイプを選択できます。

    結果セットをソートまたはページングするには、ソート機能とページング機能を使用します。詳細については、「結果のソートとページング」をご参照ください。

    結果セットを特定のカラムでグループ化し、各グループにつき 1 つのドキュメントのみを返すには、コラプシング機能を使用します。詳細については、「コラプシング」をご参照ください。

  • 最大値または最小値の検索、合計の計算、行数のカウントなどのデータ分析には、 Search API の集約機能または SQL クエリを使用できます。詳細については、「集約」および「SQL query」をご参照ください。

  • 全体の結果順序が重要ではない高速なデータエクスポートでは、 ParallelScan API と ComputeSplits API を使用して、データを並列にエクスポートできます。詳細については、「Export data in parallel」をご参照ください。