Dalam skenario kueri wildcard (*word*), Anda dapat menggabungkan tokenisasi fuzzy dan permintaan pencocokan frasa untuk menjalankan kueri fuzzy berkinerja tinggi.
Informasi latar belakang
Kueri fuzzy merupakan kebutuhan umum dalam operasi database, seperti menanyakan nama file atau nomor ponsel. Untuk menjalankan kueri fuzzy di Tablestore, Anda dapat menggunakan kueri wildcard pada indeks pencarian, yang mirip dengan fungsi LIKE di MySQL. Namun, kueri wildcard memiliki keterbatasan: panjang kueri pencarian tidak boleh melebihi 32 karakter, dan kinerjanya menurun seiring peningkatan volume data.
Untuk mengatasi masalah ini, indeks pencarian mendukung kueri wildcard berbasis token guna meningkatkan kinerja kueri fuzzy. Saat menggunakan kueri wildcard berbasis token, tidak ada batasan panjang kueri pencarian. Namun, konten asli dibatasi hingga maksimal 1.024 karakter. Konten yang melebihi batas ini akan dipotong, dan hanya 1.024 karakter pertama yang dipertahankan.
Skenario
Pilih metode yang sesuai untuk menjalankan kueri fuzzy berdasarkan skenario Anda.
-
Untuk skenario kueri wildcard yang menggunakan pola
*word*, Anda dapat menggunakan kueri wildcard berbasis token. Misalnya, metode ini dapat digunakan untuk mencari nomor ponsel yang mengandung123di posisi mana pun dengan melakukan pencarian"123".Dalam kebanyakan kasus, metode ini meningkatkan kinerja lebih dari 10 kali lipat dibandingkan kueri wildcard standar.
Asumsikan sebuah tabel data berisi kolom file_name. Di indeks pencarian, kolom ini bertipe Text, dan alat analisis (analyzer) diatur ke Fuzzy Analyzer. Untuk menemukan baris tempat nilai kolom file_name adalah
2021 woRK@Hangzhou, Anda harus menggunakan permintaan pencocokan frasa (MatchPhraseQuery). Kueri pencarian harus berupa substring berurutan dari teks asli.-
Jika kueri pencarian adalah
2021,20,21,work,WORK,@,Hang,zhou,Hangzhou, atau@Hangzhou, kueri tersebut akan cocok dengan baris tempat nilai kolom file_name adalah2021 woRK@Hangzhou. -
Jika kueri pencarian adalah
21work,2021Hangzhou,2120, atau#Hangzhou, kueri tersebut tidak akan cocok dengan baris tempat nilai kolom file_name adalah2021 woRK@Hangzhou.
-
-
Untuk skenario kueri kompleks lainnya, Anda dapat menggunakan kueri wildcard untuk menjalankan kueri fuzzy. Untuk informasi selengkapnya, lihat Wildcard query.
Penggunaan
Ikuti langkah-langkah berikut untuk menjalankan kueri fuzzy menggunakan metode berbasis token:
-
Saat membuat indeks pencarian, atur tipe kolom menjadi Text dan analyzer menjadi Fuzzy Analyzer. Anda dapat menggunakan konfigurasi default untuk parameter lainnya. Untuk informasi selengkapnya, lihat Create a search index.
CatatanJika indeks pencarian sudah ada, Anda dapat menggunakan fitur modifikasi skema dinamis untuk menambahkan kolom virtual pada kolom tertentu. Atur tipe kolom virtual menjadi Text dan analyzer menjadi Fuzzy Analyzer. Untuk informasi selengkapnya, lihat Dynamically modify a schema dan Virtual columns.
-
Saat menanyakan data menggunakan indeks pencarian, gunakan MatchPhraseQuery. Untuk informasi selengkapnya, lihat Match phrase query.
Lampiran: Studi kasus
Contoh berikut menunjukkan cara menggunakan kueri wildcard berbasis token untuk menjalankan kueri fuzzy.
import com.alicloud.openservices.tablestore.SyncClient;
import com.alicloud.openservices.tablestore.model.ColumnValue;
import com.alicloud.openservices.tablestore.model.PrimaryKey;
import com.alicloud.openservices.tablestore.model.PrimaryKeyBuilder;
import com.alicloud.openservices.tablestore.model.PrimaryKeyValue;
import com.alicloud.openservices.tablestore.model.PutRowRequest;
import com.alicloud.openservices.tablestore.model.RowPutChange;
import com.alicloud.openservices.tablestore.model.search.CreateSearchIndexRequest;
import com.alicloud.openservices.tablestore.model.search.CreateSearchIndexResponse;
import com.alicloud.openservices.tablestore.model.search.FieldSchema;
import com.alicloud.openservices.tablestore.model.search.FieldType;
import com.alicloud.openservices.tablestore.model.search.IndexSchema;
import com.alicloud.openservices.tablestore.model.search.SearchQuery;
import com.alicloud.openservices.tablestore.model.search.SearchRequest;
import com.alicloud.openservices.tablestore.model.search.SearchResponse;
import com.alicloud.openservices.tablestore.model.search.query.QueryBuilders;
import java.util.Arrays;
import java.util.Collections;
import static org.junit.Assert.assertEquals;
public class TestFuzzy {
private static final String tableName = "analysis_test";
private static final String indexName = "analysis_test_index";
public void testFuzzyMatchPhrase(SyncClient client) throws Exception {
// Definisikan skema tabel.
IndexSchema indexSchema = new IndexSchema();
indexSchema.setFieldSchemas(Collections.singletonList(
// Catatan: Jika bidang name awalnya bertipe Keyword, kueri mungkin gagal setelah Anda mengubah tipe bidang menjadi Text dan mengonfigurasi analyzer.
// Untuk mempertahankan kedua tipe Keyword dan Text, lihat contoh fitur kolom virtual. Jika Anda hanya perlu menggunakan bidang name untuk menjalankan kueri yang cocok dengan *abc*, cukup gunakan bidang bertipe Text saja. Tipe Keyword tidak diperlukan.
new FieldSchema("name", FieldType.TEXT).setAnalyzer(FieldSchema.Analyzer.Fuzzy)
));
// Buat indeks pencarian.
{
CreateSearchIndexRequest request = new CreateSearchIndexRequest();
request.setTableName(tableName);
request.setIndexName(indexName);
request.setIndexSchema(indexSchema);
CreateSearchIndexResponse response = client.createSearchIndex(request);
}
// Tulis satu baris data.
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("1"))
.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong(1))
.addPrimaryKeyColumn("pk3", PrimaryKeyValue.fromBinary(new byte[]{1, 2, 3}))
.build();
RowPutChange rowPutChange = new RowPutChange(tableName, primaryKey);
// Tulis kolom atribut.
rowPutChange.addColumn("name", ColumnValue.fromString("Tuner1024x768P.mp4"));
PutRowRequest request = new PutRowRequest(rowPutChange);
client.putRow(request);
// Tunggu hingga data disinkronkan ke indeks pencarian.
Thread.sleep(1000 * 180);
// Demonstrasi fitur kueri yang cocok dengan *abc*.
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tun", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tun er", 0);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner102", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner1024", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner1024x", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner1024x7", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner1024x768P.mp4", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "24x768P.mp4", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "24x76 8P.mp4", 0);
assertMatchPhraseQuery(client, tableName, indexName, "name", "24x7 P.mp4", 0);
}
// Gunakan kolom virtual.
public void testFuzzyMatchPhraseWithVirtualField(SyncClient client) throws Exception {
// Definisikan skema tabel.
IndexSchema indexSchema = new IndexSchema();
indexSchema.setFieldSchemas(Arrays.asList(
// Bidang sumber bertipe Keyword, yang memudahkan kueri pencocokan eksak.
new FieldSchema("name", FieldType.KEYWORD).setIndex(true).setStore(true),
// Buat kolom virtual bernama name_virtual_text. Atur tipe kolom virtual menjadi Text dan analyzer menjadi Fuzzy. Sumber kolom virtual ini adalah bidang name.
new FieldSchema("name_virtual_text", FieldType.TEXT).setIndex(true).setAnalyzer(FieldSchema.Analyzer.Fuzzy).setVirtualField(true).setSourceFieldName("name")
));
// Buat indeks pencarian.
{
CreateSearchIndexRequest request = new CreateSearchIndexRequest();
request.setTableName(tableName);
request.setIndexName(indexName);
request.setIndexSchema(indexSchema);
CreateSearchIndexResponse response = client.createSearchIndex(request);
}
// Tulis satu baris data.
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("1"))
.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong(1))
.addPrimaryKeyColumn("pk3", PrimaryKeyValue.fromBinary(new byte[]{1, 2, 3}))
.build();
RowPutChange rowPutChange = new RowPutChange(tableName, primaryKey);
// Tulis kolom atribut.
rowPutChange.addColumn("name", ColumnValue.fromString("Tuner1024x768P.mp4"));
PutRowRequest request = new PutRowRequest(rowPutChange);
client.putRow(request);
// Tunggu hingga data disinkronkan ke indeks pencarian.
Thread.sleep(1000 * 180);
// Demonstrasi skenario kueri yang cocok dengan *abc*.
// Perhatikan bahwa bidang kueri adalah kolom virtual name_virtual_text, bukan name.
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tun", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tun er", 0);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner102", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner1024", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner1024x", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner1024x7", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner1024x768P.mp4", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "24x768P.mp4", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "24x76 8P.mp4", 0);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "24x7 P.mp4", 0);
}
// Tunjukkan cara mengimplementasikan MatchPhraseQuery.
public static void assertMatchPhraseQuery(SyncClient client, String tableName, String indexName, String fieldName, String searchContent, long exceptCount) {
SearchRequest searchRequest = new SearchRequest();
searchRequest.setTableName(tableName);
searchRequest.setIndexName(indexName);
SearchQuery searchQuery = new SearchQuery();
// Gunakan MatchPhraseQuery untuk menanyakan bidang yang telah ditokenisasi.
searchQuery.setQuery(QueryBuilders.matchPhrase(fieldName, searchContent).build());
searchQuery.setLimit(0);
// Untuk mendemonstrasikan fitur ini, contoh ini mengembalikan jumlah total baris yang cocok. Jika Anda tidak memerlukan jumlah total, atur nilai ini ke false agar kinerja lebih baik.
searchQuery.setGetTotalCount(true);
searchRequest.setSearchQuery(searchQuery);
SearchResponse response = client.search(searchRequest);
assertEquals(String.format("field:[%s], searchContent:[%s]", fieldName, searchContent), exceptCount, response.getTotalCount());
}
}
FAQ
Referensi
Search Index mendukung berbagai jenis kueri untuk penanyakan data multidimensi, termasuk term query, terms query, match all query, match query, phrase match query, range query, prefix query, suffix query, wildcard query, token-based wildcard query, boolean query, geo query, nested query, vector search, dan exists query.
Saat menanyakan data, Anda dapat mengurutkan dan melakukan paginasi pada set hasil atau menjalankan collapsing (deduplikasi).
Untuk analisis data, seperti mencari nilai maksimum atau minimum, menghitung jumlah, atau menghitung baris, Anda dapat menggunakan fitur statistical aggregation atau SQL query.
Untuk mengekspor data secara cepat tanpa memperhatikan urutan set hasil, Anda dapat menggunakan fitur Parallel Scan.