Saat mengkueri data dari indeks pencarian, Anda dapat mengurutkan hasil dengan menentukan urutan sebelumnya atau saat kueri. Untuk set hasil yang besar, gunakan paging berbasis offset atau paging berbasis token untuk menemukan data yang Anda butuhkan dengan cepat.
Kasus penggunaan
Kategori | Metode | Fitur | Kasus penggunaan |
Pengurutan | Tentukan saat pembuatan | Secara default, Tablestore mengurutkan data dalam indeks pencarian menggunakan metode index presorting ( | |
Tentukan saat kueri | Mengurutkan hasil kueri berdasarkan skor relevansi, yang dihitung menggunakan algoritma BM25. Metode ini cocok untuk skenario berbasis relevansi, seperti pencarian teks lengkap. | ||
Mengurutkan hasil berdasarkan primary key. Ini berguna untuk mengurutkan item berdasarkan pengenal uniknya. | |||
Mengurutkan hasil berdasarkan nilai bidang. Ini berguna untuk skenario e-commerce atau media sosial di mana Anda mungkin mengurutkan berdasarkan atribut seperti volume penjualan atau jumlah tampilan halaman. Untuk bidang bernilai ganda, seperti bidang bertipe array atau nested, Anda dapat menggunakan parameter | |||
Mengurutkan hasil berdasarkan jarak dari titik geografis. Ini cocok untuk layanan berbasis lokasi seperti peta atau logistik, misalnya, mengurutkan restoran terdekat berdasarkan jarak. | |||
Paging | Tentukan saat kueri | Gunakan offset-based paging ketika jumlah total baris yang akan diambil kurang dari 100.000. | |
Gunakan token-based paging untuk mengambil set hasil besar secara berurutan. Secara default, Anda hanya dapat melakukan paging maju. Namun, karena token tetap valid selama proses kueri, Anda dapat menyimpan cache token sebelumnya untuk melakukan paging mundur. |
SDK
Anda dapat menerapkan pengurutan dan paging menggunakan SDK untuk bahasa-bahasa berikut.
Index presorting
Secara default, Tablestore mengurutkan data dalam indeks pencarian berdasarkan urutan pengurutan yang telah ditentukan sebelumnya, yang disebut IndexSort. Saat Anda mengkueri data, IndexSort menentukan urutan default hasil yang dikembalikan.
Saat membuat indeks pencarian, Anda dapat menyesuaikan IndexSort. Jika tidak ditentukan, indeks akan menggunakan PrimaryKeySort sebagai default.
Pengurutan awal indeks hanya mendukung
PrimaryKeySort(pengurutan kunci primer) danFieldSort(pengurutan bidang).IndexSort tidak dapat digunakan untuk indeks pencarian yang berisi bidang bertipe nested.
Setelah membuat indeks pencarian, fitur dynamic schema modification memungkinkan Anda memodifikasi pengaturan
IndexSort.
Urutkan saat kueri
Pengurutan hanya dapat dilakukan pada bidang yang properti enableSortAndAgg-nya diatur ke true.
Anda dapat menentukan metode pengurutan untuk setiap kueri. Indeks pencarian mendukung empat jenis sorter berikut. Beberapa sorter juga dapat digabungkan untuk mengurutkan hasil berdasarkan urutan kriteria tertentu.
ScoreSort
Mengurutkan hasil kueri berdasarkan skor relevansi, yang dihitung menggunakan algoritma BM25. Metode ini cocok untuk skenario berbasis relevansi, seperti pencarian teks lengkap.
Untuk mengurutkan berdasarkan skor relevansi, Anda harus secara eksplisit menentukan
ScoreSort. Jika tidak, Tablestore akan mengurutkan hasil sesuai dengan pengaturanIndexSortpada indeks.Saat menggunakan
ScoreSort, bidang bertipe FuzzyKeyword tidak termasuk dalam pengurutan, dan parameterweighttidak berpengaruh pada bidang tersebut.
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()))); // Dalam urutan ascending.
//searchQuery.setSort(new Sort(Arrays.asList(new PrimaryKeySort(SortOrder.DESC)))); // Dalam urutan descending.FieldSort
Mengurutkan hasil berdasarkan nilai bidang.
Pengurutan satu bidang
Mengurutkan hasil berdasarkan nilai dalam satu bidang.
SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new FieldSort("col", SortOrder.ASC))));Pengurutan multi-bidang
Mengurutkan hasil terlebih dahulu berdasarkan nilai dalam satu bidang, lalu berdasarkan nilai dalam bidang lainnya.
SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(
new FieldSort("col1", SortOrder.ASC), new FieldSort("col2", SortOrder.ASC))));Bidang fallback
Saat mengurutkan berdasarkan bidang bertipe Long, Double, atau Date, Anda dapat mengatur parameter missingField untuk menentukan bidang lain dengan tipe yang sama sebagai nilai fallback jika suatu baris tidak memiliki nilai pada bidang utama pengurutan.
/**
* Urutkan hasil dalam urutan descending berdasarkan nilai pada bidang Col_Long.
* Jika suatu baris tidak memiliki nilai pada bidang Col_Long (tipe Long),
* nilai dari bidang Col_Long_sec (tipe Long) digunakan sebagai gantinya untuk pengurutan.
*/
SearchQuery searchQuery = new SearchQuery();
FieldSort fieldSort = new FieldSort("Col_Long");
// Tentukan bidang Col_Long_sec sebagai fallback untuk pengurutan saat nilai pada bidang Col_Long tidak tersedia.
fieldSort.setMissingField("Col_Long_sec");
fieldSort.setOrder(SortOrder.DESC); Nilai yang hilang
Parameter missingValue menentukan posisi pengurutan untuk dokumen yang tidak memiliki bidang pengurutan. Anda dapat mengatur parameter ini untuk mengontrol di mana dokumen tersebut muncul dalam hasil.
Perilaku pengurutan adalah sebagai berikut:
Jika
missingValuediatur keFieldSort.FIRST_WHEN_MISSING, dokumen dengan nilai yang hilang selalu ditempatkan di awal hasil, terlepas dari urutan pengurutan (ascending atau descending).Jika
missingValuediatur keFieldSort.LAST_WHEN_MISSINGataunull, dokumen dengan nilai yang hilang selalu ditempatkan di akhir hasil, terlepas dari urutan pengurutan./** * Urutkan hasil dalam urutan descending berdasarkan nilai pada bidang Col_Long (tipe Long). * Jika suatu baris tidak memiliki nilai pada bidang Col_Long, tempatkan dokumen tersebut di awal hasil. */ SearchQuery searchQuery = new SearchQuery(); FieldSort fieldSort = new FieldSort("Col_Long"); // Tempatkan dokumen dengan nilai yang hilang di awal. fieldSort.setMissingValue(FieldSort.FIRST_WHEN_MISSING); fieldSort.setOrder(SortOrder.DESC); searchQuery.setSort(new Sort(Arrays.asList(fieldSort)));
Bidang bernilai ganda
Untuk bidang bernilai ganda, seperti bidang bertipe array atau nested, Anda dapat menggunakan parameter mode untuk menentukan elemen mana yang digunakan untuk pengurutan.
Urutkan berdasarkan nilai tertentu dalam array bernilai ganda.
// Asumsikan Anda memiliki dua baris, doc1 dan doc2. Keduanya memiliki field1 bertipe array.
// Nilai field1 pada doc1 adalah [2,3]. Nilai field1 pada doc2 adalah [1,3,4].
// Anda dapat mengatur parameter mode untuk menentukan nilai mana dalam array yang digunakan untuk pengurutan.
{
// Ketika mode diatur ke SortMode.MAX, urutan pengurutan adalah doc2 (diurutkan berdasarkan 4), lalu doc1 (diurutkan berdasarkan 3).
FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
fieldSort.setMode(SortMode.MAX);
}
{
// Ketika mode diatur ke SortMode.MIN, urutan pengurutan 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 sub-baris dari bidang bertipe nested.
// Asumsikan Anda memiliki dua baris, doc1 dan doc2. Keduanya memiliki field1 bertipe nested.
// Nilai field1 pada doc1 adalah [{"name":"b", "age":1},{"name":"a", "age":7}].
// Nilai field1 pada doc2 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.
// Ketika mode diatur ke SortMode.MAX dan Anda 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.
{
// Ketika mode diatur ke SortMode.MAX dan Anda 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);
}
{
// Ketika mode diatur ke SortMode.MIN dan Anda 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();
// Bidang 'geo' bertipe GeoPoint. Urutkan hasil berdasarkan jarak
// dari nilai dalam bidang ini ke titik "0,0".
Sort.Sorter sorter = new GeoDistanceSort("geo", Arrays.asList("0, 0"));
searchQuery.setSort(new Sort(Arrays.asList(sorter)));Metode paging
Untuk melakukan paging pada hasil kueri, Anda dapat menggunakan parameter limit dan offset atau token.
Offset-based paging
Gunakan offset-based paging ketika jumlah total baris yang akan diambil kurang dari 100.000. Jumlah dari limit dan offset harus kurang dari atau sama dengan 100.000, dan nilai maksimum untuk limit adalah 100.
Untuk meningkatkan ambang batas limit, lihat Bagaimana cara meningkatkan limit API Pencarian menjadi 1.000?.
Jika parameter limit dan offset tidak diatur, limit akan default ke 10 dan offset akan default ke 0.
SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setLimit(100);
searchQuery.setOffset(100);Token-based paging
Token-based paging direkomendasikan untuk deep paging karena tidak memiliki batas kedalaman.
Jika respons tidak berisi semua data yang cocok, server akan mengembalikan nextToken.
Secara default, token-based paging hanya memungkinkan Anda bergerak maju melalui hasil. Namun, karena token tetap valid selama proses kueri, Anda dapat menyimpan cache token sebelumnya untuk melakukan paging mundur.
Jika Anda perlu menyimpan nextToken secara persisten atau mengirimkannya ke aplikasi front-end, encode-kan token tersebut ke Base64 menjadi string. Token merupakan array byte, bukan string. Mengonversinya langsung ke string dengan new String(nextToken) menyebabkan kehilangan data.
Saat melakukan paging dengan token, urutan pengurutan mengikuti permintaan sebelumnya, baik menggunakan IndexSort default maupun pengurutan kustom. Oleh karena itu, Anda tidak dapat mengatur parameter Sort saat menggunakan token. Anda juga tidak dapat mengatur offset, karena data hanya dapat dibaca secara berurutan.
Indeks pencarian yang berisi bidang bertipe nested tidak mendukung IndexSort. Jika Anda perlu melakukan paging pada hasil dari indeks semacam itu, Anda harus menentukan urutan pengurutan dalam kueri. Jika tidak, server tidak akan mengembalikan nextToken meskipun masih ada data tambahan.
private static void readMoreRowsWithToken(SyncClient client) {
SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setGetTotalCount(true);// Atur agar mengembalikan jumlah total baris yang cocok.
// Tentukan nama tabel data (misalnya, sampleTable) dan nama indeks pencarian (misalnya, sampleSearchIndex).
// Anda dapat menemukan nama indeks pencarian di tab Manajemen Indeks untuk tabel di Konsol Tablestore, atau dengan mencantumkan indeks pencarian menggunakan SDK.
SearchRequest searchRequest = new SearchRequest("sampleTable", "sampleSearchIndex", 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 dibaca.
// Dapatkan nextToken.
byte[] nextToken = resp.getNextToken();
{
// Jika Anda perlu menyimpan nextToken secara persisten atau mengirimkannya ke aplikasi front-end,
// gunakan Base64 untuk mengencode nextToken menjadi string untuk penyimpanan dan transfer.
// Token merupakan array byte. Menggunakan new String(nextToken) secara langsung akan menyebabkan kehilangan data.
String tokenAsString = Base64.toBase64String(nextToken);
// Decode string kembali menjadi 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 cocok, bukan jumlah baris yang dikembalikan.
}