All Products
Search
Document Center

Tablestore:Urutkan dan lamanisasi hasil

Last Updated:May 13, 2026

Saat mengkueri data menggunakan search index, Anda dapat menentukan urutan pengurutan sebelumnya atau menentukannya saat kueri untuk mengambil hasil dalam urutan tertentu. Jika set hasil berukuran besar, Anda dapat menggunakan lamanisasi berbasis offset atau berbasis token untuk dengan cepat menemukan data yang dibutuhkan.

Index sort

Secara default, search index mengurutkan data berdasarkan index sort-nya. Saat Anda mengkueri data dengan search index, pengaturan IndexSort ini menentukan urutan pengurutan default.

Saat membuat search index, Anda dapat menentukan IndexSort kustom. Jika tidak ditentukan, search index secara default mengurutkan berdasarkan primary key.

Penting
  • Index sort hanya mendukung PrimaryKeySort (urut berdasarkan primary key) dan FieldSort (urut berdasarkan nilai bidang).

  • Search index yang memiliki bidang bertipe nested tidak mendukung index sort.

Sort at query time

Anda hanya dapat mengurutkan berdasarkan bidang yang memiliki enableSortAndAgg diatur ke true.

Anda dapat menentukan urutan pengurutan untuk setiap kueri. Search index mendukung empat jenis sorter (Sorter) berikut. Anda juga dapat menggabungkan beberapa sorter untuk membuat pengurutan multi-level.

ScoreSort

Mengurutkan hasil berdasarkan skor relevansinya, yang dihitung menggunakan algoritma BM25. Ini cocok untuk skenario seperti pencarian teks lengkap.

Penting

Jika Anda perlu mengurutkan hasil berdasarkan skor relevansi, Anda harus secara eksplisit menentukan ScoreSort. Jika tidak, hasil akan diurutkan berdasarkan konfigurasi IndexSort dari search index.

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

PrimaryKeySort

Mengurutkan hasil berdasarkan primary key.

SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new PrimaryKeySort()))); // Urutan ascending.
//searchQuery.setSort(new Sort(Arrays.asList(new PrimaryKeySort(SortOrder.DESC)))); // Urutan descending.

FieldSort

Mengurutkan hasil berdasarkan nilai kolom tertentu.

Single-column sort

Mengurutkan hasil berdasarkan nilai dalam satu kolom.

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

Multi-column sort

Mengurutkan hasil berdasarkan nilai dalam satu kolom, lalu berdasarkan nilai dalam kolom lainnya.

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

Fallback sort

Saat mengurutkan berdasarkan kolom bertipe Long, Double, atau Date, Anda dapat menggunakan parameter missingField untuk menentukan kolom cadangan dengan tipe yang sama. Kolom cadangan ini digunakan untuk baris apa pun yang tidak memiliki nilai pada kolom utama pengurutan.

/**
* Mengurutkan berdasarkan `Col_Long` dalam urutan descending. Jika suatu baris tidak memiliki nilai `Col_Long`, maka menggunakan nilai dari `Col_Long_sec` sebagai gantinya.
*/
SearchQuery searchQuery = new SearchQuery();
FieldSort fieldSort = new FieldSort("Col_Long");
// Menentukan `Col_Long_sec` sebagai fallback untuk nilai yang hilang di `Col_Long`.
fieldSort.setMissingField("Col_Long_sec");
fieldSort.setOrder(SortOrder.DESC); 

Missing value sort

Jika suatu dokumen tidak memiliki bidang pengurutan, Anda dapat menggunakan parameter missingValue untuk mengontrol posisinya dalam hasil yang diurutkan.

Perilaku pengurutan adalah sebagai berikut:

  • Ketika missingValue diatur ke FieldSort.FIRST_WHEN_MISSING, dokumen dengan nilai yang hilang selalu ditempatkan di awal hasil, terlepas dari urutan pengurutan (ascending atau descending).

  • Ketika missingValue diatur ke FieldSort.LAST_WHEN_MISSING atau tidak diatur (null), dokumen dengan nilai yang hilang selalu ditempatkan di akhir hasil, terlepas dari urutan pengurutan.

    /**
     * Mengurutkan berdasarkan `Col_Long` dalam urutan descending. Menempatkan dokumen yang tidak memiliki nilai `Col_Long` di awal hasil.
     */
    SearchQuery searchQuery = new SearchQuery();
    FieldSort fieldSort = new FieldSort("Col_Long");
    // Menempatkan dokumen dengan nilai yang hilang di awal.
    fieldSort.setMissingValue(FieldSort.FIRST_WHEN_MISSING);
    fieldSort.setOrder(SortOrder.DESC);
    searchQuery.setSort(new Sort(Arrays.asList(fieldSort)));

Multi-value sort

Untuk bidang bernilai ganda, seperti array atau bidang bertipe nested type, Anda dapat menggunakan parameter mode untuk menentukan nilai mana dalam koleksi yang digunakan untuk pengurutan.

Urutkan berdasarkan nilai tertentu dalam array.

// Baris doc1 dan doc2 memiliki bidang array bernama field1. Di doc1, nilai field1 adalah [2,3]. Di doc2, nilainya adalah [1,3,4].
// Anda dapat mengatur parameter mode untuk menentukan nilai mana dalam array yang digunakan untuk pengurutan.
{
    // Jika mode diatur ke SortMode.MAX, hasilnya adalah doc2 (diurutkan berdasarkan 4) lalu doc1 (diurutkan berdasarkan 3).
    FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
    fieldSort.setMode(SortMode.MAX);
}
{
    // Jika mode diatur ke SortMode.MIN, hasilnya adalah doc1 (diurutkan berdasarkan 2) lalu doc2 (diurutkan berdasarkan 1).
    FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
    fieldSort.setMode(SortMode.MIN);
}

Anda juga dapat mengurutkan berdasarkan nilai dalam sub-bidang bertipe nested.

// Baris doc1 dan doc2 memiliki bidang bertipe nested bernama field1.
// Di doc1, nilai field1 adalah [{"name":"b", "age":1},{"name":"a", "age":7}].
// Di doc2, nilai field1 adalah [{"name":"a", "age":1},{"name":"c", "age":1},{"name":"d", "age":5}].

{
    // Urutkan semua sub-baris dan gunakan parameter mode untuk menentukan nilai mana yang digunakan untuk pengurutan.
    // Jika Anda mengatur mode ke SortMode.MAX dan mengurutkan berdasarkan bidang age, hasilnya adalah doc1 (diurutkan berdasarkan 7) lalu doc2 (diurutkan berdasarkan 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);
}
{
    // Urutkan hanya sub-baris di mana age=1 dan gunakan parameter mode untuk menentukan nilai mana yang digunakan untuk pengurutan.
    {
        // Jika Anda mengatur mode ke SortMode.MAX dan mengurutkan berdasarkan bidang name, hasilnya adalah doc2 (diurutkan berdasarkan "c") lalu doc1 (diurutkan berdasarkan "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);
    }
    {
        // Jika Anda mengatur mode ke SortMode.MIN dan mengurutkan berdasarkan bidang name, hasilnya adalah doc1 (diurutkan berdasarkan "b") lalu doc2 (diurutkan berdasarkan "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

Mengurutkan hasil berdasarkan jarak dari titik geografis.

SearchQuery searchQuery = new SearchQuery();
// Mengurutkan hasil berdasarkan jarak dari nilai kolom `geo` (Geopoint) ke titik "0,0".
Sort.Sorter sorter = new GeoDistanceSort("geo", Arrays.asList("0, 0"));
searchQuery.setSort(new Sort(Arrays.asList(sorter)));

Paging methods

Saat mengambil hasil, Anda dapat menggunakan parameter limit dan offset atau token untuk lamanisasi.

Limit and offset paging

Anda dapat menggunakan limit dan offset untuk paging, tetapi jumlah limit dan offset tidak boleh melebihi 100.000, dan nilai maksimum untuk limit adalah 100.

Catatan

Untuk mempelajari cara meningkatkan limit hingga 1.000, lihat Bagaimana cara meningkatkan batas hasil kueri Search API menjadi 1.000 untuk search index?.

Jika tidak diatur, limit default-nya adalah 10 dan offset default-nya adalah 0.

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

Token-based paging

Kami merekomendasikan penggunaan lamanisasi berbasis token untuk deep paging karena tidak memiliki batasan kedalaman.

Jika kueri masih memiliki hasil tambahan untuk dikembalikan, respons akan menyertakan nextToken. Gunakan token ini dalam permintaan berikutnya untuk mengambil halaman hasil berikutnya.

Secara default, lamanisasi berbasis token hanya memungkinkan Anda bergerak maju melalui hasil. Namun, karena token tetap valid selama sesi lamanisasi, Anda dapat menyimpan cache token sebelumnya untuk menerapkan lamanisasi mundur.

Penting

Untuk menyimpan nextToken secara persisten atau mengirimkannya ke aplikasi front-end, Anda harus melakukan encode Base64 terhadapnya. nextToken merupakan array byte, bukan string. Mengonversinya langsung dengan new String(nextToken) akan merusak token dan menyebabkan kehilangan data.

Token mempertahankan urutan pengurutan dari permintaan sebelumnya, baik itu index sort default maupun urutan pengurutan kustom. Oleh karena itu, Anda tidak dapat menentukan parameter Sort dalam permintaan berbasis token. Anda juga tidak dapat menggunakan parameter offset, karena token itu sendiri yang menentukan posisi awal.

Penting

Search index yang memiliki bidang bertipe nested tidak mendukung index sort. Untuk paginate hasil dari search index semacam itu, Anda harus menentukan urutan pengurutan dalam kueri Anda. Jika tidak, server tidak akan mengembalikan nextToken meskipun masih tersedia hasil tambahan.

private static void readMoreRowsWithToken(SyncClient client) {
    SearchQuery searchQuery = new SearchQuery();
    searchQuery.setQuery(new MatchAllQuery());
    searchQuery.setGetTotalCount(true);// Atur ke true untuk mengembalikan jumlah total baris yang sesuai.
    // Tentukan nama tabel (misalnya, sampleTable) dan nama search index (misalnya, sampleSearchIndex). Anda dapat menemukan nama search index di tab Indexes tabel Anda di Konsol Tablestore atau dengan mencantumkan search index menggunakan 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 berarti semua data telah diambil.
        // Dapatkan nextToken.
        byte[] nextToken = resp.getNextToken();

        {
            // Jika Anda perlu menyimpan nextToken secara persisten atau mengirimkannya ke aplikasi front-end, gunakan encoding Base64 untuk mengonversinya ke string.
            // Token itu sendiri bukan string. Mengonversinya langsung menggunakan new String(nextToken) akan merusak token.
            String tokenAsString = Base64.toBase64String(nextToken);
            // Dekode string kembali ke array byte.
            byte[] tokenAsByte = Base64.fromBase64String(tokenAsString);
        }

        // Atur token untuk permintaan berikutnya.
        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());// Mencetak jumlah total baris yang sesuai, bukan jumlah baris yang dikembalikan dalam respons ini.
}

FAQ

References