SelectObject memungkinkan Anda menjalankan kueri SQL langsung pada objek di Object Storage Service (OSS) dan hanya mengambil data yang sesuai—tanpa perlu mengunduh seluruh objek terlebih dahulu. Fitur ini mengurangi konsumsi bandwidth serta menurunkan penggunaan CPU dan memori di sisi klien, sehingga analitik data berbasis OSS menjadi lebih efisien.
Cara kerja
Saat menggunakan GetObject, aplikasi Anda mengunduh seluruh objek sebelum melakukan penyaringan. SelectObject memindahkan proses penyaringan ke dalam OSS itu sendiri: Anda mengirimkan kondisi dan proyeksi SQL, lalu OSS hanya mengembalikan baris-baris yang sesuai.
Alur kueri:
Kirim permintaan SelectObject dengan pernyataan SQL
SELECT ... FROM ... WHEREdan format output.OSS memindai objek dan menerapkan kondisi serta proyeksi Anda di sisi server.
OSS mengalirkan hanya catatan-catatan yang cocok kembali ke klien Anda.
Untuk objek besar, panggil CreateSelectObjectMeta terlebih dahulu untuk mendapatkan jumlah total split, lalu jalankan kueri paralel menggunakan
split-range.
Jenis objek yang didukung
| Type | Details |
|---|---|
| CSV (termasuk TSV dan format serupa) | Harus sesuai dengan RFC 4180. Mendukung pemisah baris dan kolom kustom serta karakter quote. |
| JSON (UTF-8 encoded) | Dua format: JSON DOCUMENT (satu objek JSON) dan JSON LINES (satu objek JSON per baris, dipisahkan oleh \n atau \r\n; tidak perlu konfigurasi delimiter). |
| Objek Standard dan Infrequent Access (IA) | Dapat dikueri secara langsung. Objek Archive, Cold Archive, dan Deep Cold Archive harus dipulihkan terlebih dahulu sebelum dikueri. |
| Objek terenkripsi | Objek yang dienkripsi menggunakan enkripsi yang dikelola OSS atau oleh customer master keys (CMKs) yang dikelola Key Management Service (KMS). |
Batasan
| Limit | Details |
|---|---|
| Jenis bucket tidak didukung | Bucket tanpa atribut zona (no-header-region) tidak mendukung SelectObject. |
| Batas data di Konsol | Konsol OSS mendukung pemilihan hingga 40 MB data dari objek berukuran maksimal 128 MB. |
| Dukungan SDK | Hanya OSS SDK for Java dan OSS SDK for Python yang mendukung SelectObject. |
| Kompresi | Hanya kompresi GZIP yang didukung saat mengkueri objek terkompresi. |
| Sensitivitas huruf pada LIKE | Pencocokan kabur berbasis LIKE bersifat case-sensitive. |
Penagihan
Biaya SelectObject didasarkan pada jumlah data yang dipindai:
Objek Standar: biaya pemindaian data.
Objek IA, Archive, Cold Archive, dan Deep Cold Archive: biaya pemindaian data ditambah biaya pengambilan data.
Untuk detail harga, lihat Biaya pemrosesan data.
Sintaks SQL yang didukung
| Category | Supported |
|---|---|
| Statement | SELECT ... FROM ossobject [WHERE ...] |
| Data types | string, int (64-bit), double (64-bit), decimal (128-bit), timestamp, bool |
| Logical operators | AND, OR, NOT |
| Arithmetic operators | +, -, *, /, % |
| Comparison operators | >, =, <, >=, <=, != |
| String operators | LIKE, || (concatenation) |
| Aggregate functions | COUNT, MAX, MIN, AVG, SUM |
| Type conversion | CAST function |
Tipe data dalam CSV vs. JSON
Data CSV secara default bertipe string. Gunakan CAST untuk mengonversi:
SELECT s.a FROM ossobject s WHERE CAST(s.a AS decimal) > 123456789.12345Objek JSON mempertahankan tipe aslinya (Null, Bool, Int64, Double, String). Untuk bilangan titik mengambang presisi tinggi, atur ParseJsonNumberAsString ke true lalu cast ke decimal:
SELECT s.a FROM ossobject s WHERE CAST(s.a AS decimal) > 123456789.12345Contoh SQL
Kueri CSV
Indeks kolom dimulai dari _1. Jika CSV memiliki baris header, Anda dapat mereferensikan kolom berdasarkan nama.
| Goal | SQL statement |
|---|---|
| Mengembalikan 10 baris pertama | SELECT * FROM ossobject LIMIT 10 |
| Mengembalikan baris di mana kolom 1 (int) > kolom 3 (int) | SELECT _1, _3 FROM ossobject WHERE CAST(_1 AS int) > CAST(_3 AS int) |
| Menghitung baris di mana kolom 1 diawali dengan X | SELECT COUNT(*) FROM ossobject WHERE _1 LIKE 'X%' |
| Mengembalikan baris di mana kolom 2 setelah timestamp tertentu dan kolom 3 > 200 | SELECT * FROM ossobject WHERE _2 > CAST('2018-08-09 11:30:25' AS timestamp) AND _3 > 200 |
| Fungsi agregat pada kolom 6 (double) | SELECT AVG(CAST(_6 AS double)), SUM(CAST(_6 AS double)), MAX(CAST(_6 AS double)), MIN(CAST(_6 AS double)) FROM ossobject |
| Kolom yang digabungkan dan cocok dengan pola tertentu | SELECT * FROM ossobject WHERE (_1 || _3) LIKE 'Tom%Anderson' |
| Baris di mana kolom 1 habis dibagi 3 | SELECT * FROM ossobject WHERE (_1 % 3) = 0 |
| Baris di mana kolom 1 berada di antara 1995 dan 2012 | SELECT * FROM ossobject WHERE _1 BETWEEN 1995 AND 2012 |
| Baris di mana kolom 5 adalah salah satu dari N, M, G, L | SELECT * FROM ossobject WHERE _5 IN ('N', 'M', 'G', 'L') |
| Baris di mana (kolom2 x kolom3) > (kolom5 + 100) | SELECT * FROM ossobject WHERE _2 * _3 > _5 + 100 |
Kueri JSON
Gunakan notasi titik dan wildcard array untuk menavigasi struktur bersarang. Mempersempit path di klausa FROM meningkatkan performa.
Diberikan objek contoh berikut:
{
"contacts": [
{
"firstName": "John",
"lastName": "Smith",
"age": 27,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{ "type": "home", "number": "212 555-1234" },
{ "type": "office", "number": "646 555-4567" },
{ "type": "mobile", "number": "123 456-7890" }
],
"children": [],
"spouse": null
}
]
}| Goal | SQL statement |
|---|---|
| Kontak dengan usia = 27 | SELECT * FROM ossobject.contacts[*] s WHERE s.age = 27 |
| Semua nomor telepon rumah | SELECT s.number FROM ossobject.contacts[*].phoneNumbers[*] s WHERE s.type = 'home' |
| Kontak dengan spouse bernilai null | SELECT * FROM ossobject s WHERE s.spouse IS NULL |
| Kontak dengan array children kosong | SELECT * FROM ossobject s WHERE s.children[0] IS NULL |
| Alamat jalan dengan kode pos yang diawali 10021 | SELECT s.streetAddress FROM ossobject.contacts[*].address s WHERE s.postalCode LIKE '10021%' |
Mempersempit path FROM (misalnya, ossobject.contacts[*].address) lebih efisien daripada menggunakan path luas lalu akses melalui notasi titik (misalnya, ossobject.contacts[*] lalu s.address.streetAddress).
Kueri objek menggunakan Konsol OSS
Konsol mendukung pemilihan hingga 40 MB data dari objek berukuran maksimal 128 MB.
Masuk ke Konsol OSS.
Pada panel navigasi kiri, klik Buckets. Temukan dan klik bucket target.
Pada pohon navigasi kiri, pilih Object Management > Objects.
Pada kolom Actions untuk objek target, pilih
> Select Content.Pada panel Select Content, konfigurasikan parameter berikut:
Parameter Description Object Type CSVatauJSONDelimiter Hanya untuk CSV. ,atau CustomTitle Row Hanya untuk CSV. Apakah baris pertama berisi header kolom JSON Display Mode Hanya untuk JSON. JSON_LINESatauJSON_DOCUMENTCompression Format Hanya GZIP Klik Preview untuk melihat pratinjau data yang dipilih.
PentingPratinjau objek Standard dikenai biaya pemindaian data. Pratinjau objek IA, Archive, Cold Archive, atau Deep Cold Archive dikenai biaya pemindaian data ditambah biaya pengambilan data. Untuk detailnya, lihat Biaya pemrosesan data.
Klik Next, lalu masukkan dan jalankan pernyataan SQL. Contoh: Objek CSV bernama
Peoplememiliki tiga kolom:Name,Company, danAge. Indeks kolomnya adalah_1(Name),_2(Company), dan_3(Age).Kueri orang berusia di atas 50 yang namanya diawali Lora:
SELECT * FROM ossobject WHERE _1 LIKE 'Lora*' AND _3 > 50Ambil jumlah baris, usia maksimum, dan usia minimum:
SELECT COUNT(*), MAX(CAST(_3 AS int)), MIN(CAST(_3 AS int)) FROM oss_object
Lihat hasilnya. Klik Download untuk menyimpan output ke mesin lokal Anda.
Kueri objek menggunakan OSS SDK
Hanya OSS SDK for Java dan OSS SDK for Python yang mendukung SelectObject.
Contoh Java
SDK Java menggunakan createSelectObjectMetadata untuk membuat metadata split dan selectObject untuk menjalankan kueri. Kredensial dimuat dari variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET.
import com.aliyun.oss.model.*;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
public class SelectObjectSample {
// Ganti dengan endpoint wilayah bucket Anda.
// Contoh: https://oss-cn-hangzhou.aliyuncs.com
private static String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
private static String bucketName = "examplebucket";
public static void main(String[] args) throws Exception {
// Muat kredensial dari variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET.
EnvironmentVariableCredentialsProvider credentialsProvider =
CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
String region = "cn-hangzhou";
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
// Kueri objek CSV.
selectCsvSample("test.csv", ossClient);
// Kueri objek JSON LINES.
selectJsonSample("test.json", ossClient);
ossClient.shutdown();
}
private static void selectCsvSample(String key, OSS ossClient) throws Exception {
// Unggah data CSV contoh dengan baris header.
String content = "name,school,company,age\r\n" +
"Lora Francis,School A,Staples Inc,27\r\n" +
"Eleanor Little,School B,\"Conectiv, Inc\",43\r\n" +
"Rosie Hughes,School C,Western Gas Resources Inc,44\r\n" +
"Lawrence Ross,School D,MetLife Inc.,24";
ossClient.putObject(bucketName, key, new ByteArrayInputStream(content.getBytes()));
// Buat metadata split untuk objek (disarankan sebelum kueri multipart).
SelectObjectMetadata selectObjectMetadata = ossClient.createSelectObjectMetadata(
new CreateSelectObjectMetadataRequest(bucketName, key)
.withInputSerialization(
new InputSerialization().withCsvInputFormat(
new CSVFormat()
.withHeaderInfo(CSVFormat.Header.Use)
.withRecordDelimiter("\r\n"))));
System.out.println("Total lines: " + selectObjectMetadata.getCsvObjectMetadata().getTotalLines());
System.out.println("Total splits: " + selectObjectMetadata.getCsvObjectMetadata().getSplits());
// Kueri baris di mana kolom ke-4 (usia) lebih besar dari 40.
SelectObjectRequest selectObjectRequest =
new SelectObjectRequest(bucketName, key)
.withInputSerialization(
new InputSerialization().withCsvInputFormat(
new CSVFormat()
.withHeaderInfo(CSVFormat.Header.Use)
.withRecordDelimiter("\r\n")))
.withOutputSerialization(new OutputSerialization().withCsvOutputFormat(new CSVFormat()));
selectObjectRequest.setExpression("SELECT * FROM ossobject WHERE _4 > 40");
OSSObject ossObject = ossClient.selectObject(selectObjectRequest);
BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
ossClient.deleteObject(bucketName, key);
}
private static void selectJsonSample(String key, OSS ossClient) throws Exception {
// Unggah data JSON LINES contoh (satu objek JSON per baris).
final String content = "{\"name\":\"Lora Francis\",\"age\":27,\"company\":\"Staples Inc\"}\n" +
"{\"name\":\"Eleanor Little\",\"age\":43,\"company\":\"Conectiv, Inc\"}\n" +
"{\"name\":\"Rosie Hughes\",\"age\":44,\"company\":\"Western Gas Resources Inc\"}\n" +
"{\"name\":\"Lawrence Ross\",\"age\":24,\"company\":\"MetLife Inc.\"}";
ossClient.putObject(bucketName, key, new ByteArrayInputStream(content.getBytes()));
// Kueri catatan di mana usia > 40.
SelectObjectRequest selectObjectRequest =
new SelectObjectRequest(bucketName, key)
.withInputSerialization(new InputSerialization()
.withCompressionType(CompressionType.NONE)
.withJsonInputFormat(new JsonFormat().withJsonType(JsonType.LINES)))
.withOutputSerialization(new OutputSerialization()
.withCrcEnabled(true)
.withJsonOutputFormat(new JsonFormat()))
.withExpression("SELECT * FROM ossobject AS s WHERE s.age > 40");
OSSObject ossObject = ossClient.selectObject(selectObjectRequest);
BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
ossClient.deleteObject(bucketName, key);
}
}Contoh Python
SDK Python menyediakan create_select_object_meta, select_object, dan select_object_to_file. Kredensial dimuat dari variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET.
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
def select_callback(consumed_bytes, total_bytes=None):
print(f"Consumed bytes: {consumed_bytes}")
# Muat kredensial dari variabel lingkungan.
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # Ganti dengan endpoint bucket Anda.
region = "cn-hangzhou" # Ganti dengan wilayah bucket Anda.
bucket = oss2.Bucket(auth, endpoint, "examplebucket", region=region)
# --- Kueri CSV ---
key = "python_select.csv"
content = "Tom Hanks,USA,45\r\n" * 1024
bucket.put_object(key, content)
# Buat metadata split.
csv_meta_params = {"RecordDelimiter": "\r\n"}
csv_header = bucket.create_select_object_meta(key, csv_meta_params)
print(f"Total rows: {csv_header.rows}, total splits: {csv_header.splits}")
# Kueri baris di mana kolom 3 > 44.
select_csv_params = {
"CsvHeaderInfo": "None",
"RecordDelimiter": "\r\n",
"LineRange": (500, 1000),
}
result = bucket.select_object(
key, "SELECT * FROM ossobject WHERE _3 > 44", select_callback, select_csv_params
)
print(result.read())
# Simpan hasil ke file lokal.
bucket.select_object_to_file(
key, "python_select.csv", "SELECT * FROM ossobject WHERE _3 > 44",
select_callback, select_csv_params
)
bucket.delete_object(key)
# --- Kueri JSON DOCUMENT ---
key = "python_select.json"
content = '{"contacts":[{"key1":1,"key2":"hello world1"},{"key1":2,"key2":"hello world2"}]}'
bucket.put_object(key, content)
select_json_params = {"Json_Type": "DOCUMENT"}
result = bucket.select_object(
key,
"SELECT s.key2 FROM ossobject.contacts[*] s WHERE s.key1 = 1",
None,
select_json_params,
)
print(result.read())
bucket.delete_object(key)
# --- Kueri JSON LINES ---
key = "python_select_lines.json"
content = '{"key1":1,"key2":"hello world1"}\n{"key1":2,"key2":"hello world2"}'
bucket.put_object(key, content)
select_json_params = {"Json_Type": "LINES"}
json_header = bucket.create_select_object_meta(key, select_json_params)
print(f"Total rows: {json_header.rows}, total splits: {json_header.splits}")
result = bucket.select_object(
key, "SELECT s.key2 FROM ossobject s WHERE s.key1 = 1", None, select_json_params
)
print(result.read())
bucket.delete_object(key)Kueri objek menggunakan API OSS
Untuk memanggil SelectObject langsung melalui RESTful API, sertakan perhitungan signature dalam kode Anda. Untuk detailnya, lihat SelectObject.
Jalankan kueri paralel pada objek besar
Untuk objek besar, bagi kueri ke beberapa permintaan konkuren menggunakan split-range.
Kapan menggunakan split vs. byte range:
| Method | When to use |
|---|---|
| By split (disarankan) | Satu split mencakup beberapa baris dengan ukuran yang kira-kira sama. Gunakan untuk objek JSON dan objek CSV yang nilai kolomnya mungkin mengandung line feed tersemat. |
| By byte range | Lebih sederhana; tidak memerlukan metadata. Gunakan hanya untuk objek CSV yang nilai kolomnya tidak mengandung line feed. |
Langkah-langkah untuk kueri paralel berbasis split:
Panggil CreateSelectObjectMeta untuk mendapatkan jumlah total split. Panggil secara asinkron sebelum kueri pertama untuk menghindari overhead pemindaian tambahan.
Pilih tingkat konkurensi
nberdasarkan sumber daya klien yang tersedia.Bagi jumlah total split dengan
nuntuk mendapatkan jumlah split per permintaan.Kirimkan
npermintaan SelectObject konkuren, masing-masing dengan parametersplit-range. Contoh:split-range=1-20.Gabungkan hasilnya secara berurutan.