Topik ini menjelaskan cara menggunakan Bahasa Proses Terstruktur (SPL) dalam berbagai skenario.
Optimasi Pernyataan SPL
Pernyataan SPL dapat ditulis dengan beberapa cara untuk mencapai hasil pemrosesan data tertentu. Menulis pernyataan SPL yang ringkas dan efisien menyederhanakan pemeliharaan serta meningkatkan kinerja. Tabel berikut memberikan beberapa saran.
Saran | Sebelum optimasi | Setelah optimasi |
Gabungkan klausa `where` berturut-turut menjadi satu. | | |
Gabungkan klausa `extend` berturut-turut menjadi satu. | | |
Ganti `extend` dan `project-away` dengan `project-rename`. | | |
Ubah nilai bidang di tempatnya alih-alih menggunakan `extend` untuk membuat bidang baru, kecuali diperlukan. | | |
Menangani bidang khusus
Bidang waktu
Selama eksekusi SPL, tipe data dari bidang waktu log SLS selalu INTEGER atau BIGINT. Bidang log SLS mencakup bidang waktu data __time__ dan bagian nanodetik dari bidang waktu data __time_ns_part__.
Untuk memperbarui waktu data, gunakan instruksi `extend` dan pastikan nilai baru adalah INTEGER atau BIGINT. Instruksi lain tidak dapat beroperasi pada bidang waktu. Perilaku mereka adalah sebagai berikut:
`project`, `project-away`, dan `project-rename`: Instruksi ini secara default mempertahankan bidang waktu. Anda tidak dapat mengganti nama atau menimpanya.
`parse-regexp` dan `parse-json`: Jika hasil ekstraksi mencakup bidang waktu, mereka akan diabaikan.
Contoh
Ekstrak nilai bidang waktu dari string waktu yang ada.
Pernyataan SPL
* | parse-regexp time, '([\d\-\s:]+)\.(\d+)' as ts, ms | extend ts=date_parse(ts, '%Y-%m-%d %H:%i:%S') | extend __time__=cast(to_unixtime(ts) as INTEGER) | extend __time_ns_part__=cast(ms as INTEGER) * 1000000 | project-away ts, msData Masukan
time: '2023-11-11 01:23:45.678'Hasil Keluaran
__time__: 1699637025 __time_ns_part__: 678000000 time: '2023-11-11 01:23:45.678'
Nama bidang dengan karakter khusus
Jika nama bidang berisi spasi atau karakter khusus lainnya, apit dengan tanda kutip ganda (") saat merujuknya. Sebagai contoh, jika sebuah bidang bernama A B, yang berisi spasi, Anda dapat merujuknya sebagai "A B" dalam pernyataan SPL. Contoh berikut menunjukkan cara melakukannya:
* | where "A B" like '%error%'Nama bidang tanpa membedakan huruf besar/kecil
Dalam kueri pemindaian SLS, nama bidang yang dirujuk dalam instruksi SPL bersifat case-insensitive. Sebagai contoh, jika log berisi bidang bernama Method, Anda dapat merujuknya sebagai method atau METHOD dalam instruksi SPL.
Ini berlaku untuk fitur kueri pemindaian dari Simple Log Service. Untuk informasi selengkapnya, lihat Kueri Pemindaian.
Contoh
Gunakan nama bidang tanpa membedakan huruf besar/kecil dalam klausa `where`.
Pernyataan SPL
* | where METHOD like 'Post%'Data Masukan
Method: 'PostLogstoreLogs'Hasil Keluaran
Method: 'PostLogstoreLogs'
Tangani konflik nama bidang
Selama pengunggahan log atau eksekusi SPL, penanganan nama bidang tanpa membedakan huruf besar/kecil dapat menyebabkan konflik. Sebagai contoh, konflik terjadi jika log mentah berisi bidang `Method` dan `method`. SPL menyelesaikan konflik ini secara berbeda tergantung pada skenario.
Untuk menghindari situasi ini, standarisasikan nama bidang dalam log mentah Anda.
Konflik dalam data masukan
Jika log mentah berisi bidang dengan konflik nama tanpa membedakan huruf besar/kecil, seperti Status dan status, SPL secara acak memilih salah satu bidang untuk masukan dan membuang yang lain. Sebagai contoh:
Pernyataan SPL
* | extend status_cast = cast(status as bigint)Data Masukan
Status: '200' status: '404'Hasil Pemrosesan
Kemungkinan 1: Nilai bidang Status dipertahankan.
Status: '200' -- Kolom pertama dipertahankan, kolom kedua dibuang. status_cast: '200'Kemungkinan 2: Nilai bidang status dipertahankan.
status: '404' -- Kolom kedua dipertahankan, kolom pertama dibuang. Status_cast: '404'
Konflik dalam hasil keluaran
Skenario 1: Konflik Bidang Data Mentah
Selama eksekusi SPL, bidang dengan konflik nama tanpa membedakan huruf besar/kecil mungkin dihasilkan. Dalam hal ini, SPL secara acak memilih salah satu dari mereka untuk keluaran. Sebagai contoh, jika bidang log berisi string JSON, menggunakan instruksi parse-json mungkin membuat bidang dengan nama yang bertentangan. Sebagai contoh:
Pernyataan SPL
* | parse-json contentData Masukan
content: '{"Method": "PostLogs", "method": "GetLogs", "status": "200"}'Hasil Keluaran
Kemungkinan 1: Bidang Method dipertahankan.
content: '{"Method": "PostLogs", "method": "GetLogs", "status": "200"}' Method: 'PostLogs' -- Bidang Method dipertahankan. status: '200'Kemungkinan 2: Bidang method dipertahankan.
content: '{"Method": "PostLogs", "method": "GetLogs", "status": "200"}' method: 'GetLogs' -- Bidang method dipertahankan. status: '200'
Skenario 2: Konflik dengan Bidang Data Baru yang Dihasilkan
Untuk menghindari ambiguitas, SPL mempertahankan huruf besar/kecil dari nama bidang baru yang dihasilkan secara eksplisit oleh instruksi. Instruksi ini mencakup extend dan instruksi yang menggunakan as untuk menentukan nama bidang, seperti parse-regexp dan parse-csv.
Sebagai contoh, jika Anda menggunakan extend untuk membuat bidang baru bernama Method, nama bidang yang dihasilkan tetap Method.
Pernyataan SPL
* | extend Method = 'Post'Data Masukan
Status: '200'Hasil Keluaran
Status: '200' Method: 'Post'
Menangani konflik bidang cadangan SLS
Ini berlaku untuk fitur konsumsi real-time dan kueri pemindaian Layanan Log Sederhana.
Untuk daftar lengkap bidang yang dicadangkan, lihat Bidang yang Dicadangkan. SPL membaca data dari struktur LogGroup (lihat Pengodean Data untuk definisi LogGroup). Jika data mentah tidak sesuai dengan pengodean LogGroup standar, beberapa bidang yang dicadangkan mungkin berada di LogContent alih-alih di lokasi standarnya. SPL menangani konflik ini sebagai berikut:
Untuk bidang
__source__,__topic__,__time__, dan__time_ns_part__, SPL membaca nilai dari pengkodean LogGroup standar dan mengabaikan bidang LogContent apa pun dengan nama yang sama.Untuk bidang tag dengan awalan
__tag__:, SPL pertama-tama mencoba membaca nilai dari pengkodean LogGroup standar. Jika nilai tidak ditemukan, SPL membacanya dari LogContent. Sebagai contoh, untuk bidang__tag__:ip, SPL pertama-tama mencoba membaca bidang dengan kunciipdari daftar LogTag. Jika bidang tersebut tidak ada, SPL kemudian membaca bidang log dengan kunci__tag__:ipdari bidang log kustom di LogContent.
Bidang __line__ untuk pencarian teks penuh
Ini berlaku untuk fitur kueri pemindaian SLS.
Untuk memfilter log mentah di Konsol atau saat menggunakan operasi API GetLogstoreLogs, Anda dapat menggunakan bidang `__line__`.
Contoh
Cari kata kunci `error` dalam log.
* | where __line__ like '%error%'Jika log memiliki bidang bernama `__line__`, apit nama tersebut dengan backticks (`` ` ``) untuk merujuknya, seperti
`__line__`.* | where `__line__` ='20'
Kebijakan Penyimpanan dan Penimpaan Nilai
Saat instruksi SPL dieksekusi, jika bidang keluaran memiliki nama yang sama dengan bidang yang ada di data masukan, kebijakan untuk menentukan nilai bidang tersebut adalah sebagai berikut:
Kebijakan untuk mempertahankan dan menimpa nilai bidang tidak berlaku untuk instruksi `extend`. Untuk instruksi `extend`, jika terjadi konflik nama bidang, nilai baru selalu digunakan.
Tipe data tidak konsisten antara nilai lama dan baru
Nilai asli dari bidang masukan dipertahankan.
Contoh
Contoh 1: Bidang yang diubah namanya dari instruksi `project` memiliki nama yang bertentangan.
Pernyataan SPL
* | extend status=cast(status as BIGINT) -- Ubah tipe bidang status menjadi BIGINT. | project code=status -- Tipe nilai baru (BIGINT) berbeda dari tipe nilai lama (VARCHAR), jadi nilai lama dipertahankan.Data Masukan
status: '200' code: 'Success'Hasil Keluaran
code: 'Success'
Contoh 2: Bidang yang diekstraksi dari instruksi `parse-json` memiliki nama yang bertentangan.
Pernyataan SPL
* | extend status=cast(status as BIGINT) -- Ubah tipe bidang status menjadi BIGINT. | parse-json content -- Tipe lama status adalah BIGINT dan tipe baru adalah VARCHAR. Nilai lama dipertahankan.Data Masukan
status: '200' content: '{"status": "Success", "body": "this is test"}'Hasil Keluaran
content: '{"status": "Success", "body": "this is test"}' status: 200 body: 'this is test'
Tipe data konsisten antara nilai lama dan baru
Jika nilai masukan adalah null, nilai baru akan digunakan. Jika tidak, perilaku ditentukan oleh parameter mode dalam instruksi, sebagaimana didefinisikan dalam tabel berikut.
Jika parameter mode tidak didefinisikan dalam instruksi, nilai defaultnya adalah overwrite.
Mode | Deskripsi |
overwrite | Menimpa nilai lama dengan nilai baru. |
preserve | Mempertahankan nilai lama dan membuang nilai baru. |
Contoh
Contoh 1: Bidang yang diubah namanya dari instruksi `project` memiliki nama yang bertentangan dan tipe yang sama. Mode default adalah `overwrite`.
Pernyataan SPL
* | project code=status -- Tipe lama dan baru dari code keduanya adalah VARCHAR. Nilai baru digunakan berdasarkan mode overwrite.Data Masukan
status: '200' code: 'Success'Hasil Keluaran
code: '200'
Contoh 2: Bidang yang diekstraksi dari instruksi `parse-json` memiliki nama yang bertentangan dan tipe yang sama. Mode default adalah `overwrite`.
Pernyataan SPL
* | parse-json content -- Tipe lama dan baru dari status keduanya adalah VARCHAR. Nilai baru digunakan berdasarkan mode overwrite.Data Masukan
status: '200' content: '{"status": "Success", "body": "this is test"}'Hasil Keluaran
content: '{"status": "Success", "body": "this is test"}' status: 'Success' body: 'this is test'
Contoh 3: Bidang yang diekstraksi dari instruksi `parse-json` memiliki nama yang bertentangan dan tipe yang sama. Mode diatur ke `preserve`.
Pernyataan SPL
* | parse-json -mode='preserve' content -- Tipe lama dan baru dari status keduanya adalah VARCHAR. Nilai lama dipertahankan berdasarkan mode preserve.Data Masukan
status: '200' content: '{"status": "Success", "body": "this is test"}'Hasil Keluaran
content: '{"status": "Success", "body": "this is test"}' status: '200' body: 'this is test'
Konversi Tipe Data
Tipe awal
Untuk pemrosesan data dengan SPL, tipe data awal dari semua bidang masukan adalah VARCHAR, kecuali untuk bidang waktu log. Jika logika pemrosesan selanjutnya melibatkan tipe data yang berbeda, Anda harus melakukan konversi tipe data.
Contoh
Untuk menyaring log akses dengan kode status 5xx, Anda harus mengonversi bidang `status` ke tipe BIGINT sebelum perbandingan.
* -- Tipe awal dari bidang status adalah VARCHAR.
| where cast(status as BIGINT) >= 500 -- Konversikan tipe bidang status menjadi BIGINT, lalu lakukan perbandingan.Penyimpanan tipe
Selama pemrosesan data SPL, setelah Anda menggunakan instruksi `extend` untuk mengonversi tipe data suatu bidang, logika pemrosesan selanjutnya menggunakan tipe data yang dikonversi.
Contoh
* -- Logstore digunakan sebagai data masukan. Kecuali untuk bidang waktu, semua bidang awalnya bertipe VARCHAR.
| where __source__='127.0.0.1' -- Filter pada bidang __source__.
| extend status=cast(status as BIGINT) -- Konversikan tipe bidang status menjadi BIGINT.
| project status, content
| where status>=500 -- Tipe bidang status tetap BIGINT, sehingga dapat langsung dibandingkan dengan angka 500.Menangani Nilai Null dalam Ekspresi SPL
Menghasilkan Nilai Null
Selama pemrosesan data SPL, nilai null dihasilkan dalam dua skenario berikut:
Jika bidang yang digunakan dalam ekspresi SPL tidak ada dalam data masukan, nilainya dianggap null selama perhitungan.
Jika terjadi pengecualian selama perhitungan ekspresi SPL, hasilnya adalah null. Sebagai contoh, konversi tipe `cast` gagal atau indeks array di luar batas.
Contoh
Jika sebuah bidang tidak ada, nilainya dianggap null dalam perhitungan.
Pernyataan SPL
* | extend withoutStatus=(status is null)Data Masukan
# Entri 1 status: '200' code: 'Success' # Entri 2 code: 'Success'Hasil Keluaran
# Entri 1 status: '200' code: 'Success' withoutStatus: false # Entri 2 code: 'Success' withoutStatus: true
Jika terjadi pengecualian selama perhitungan, hasilnya adalah null.
Pernyataan SPL
* | extend code=cast(code as BIGINT) -- Gagal mengonversi bidang code menjadi BIGINT. | extend values=json_parse(values) | extend values=cast(values as ARRAY(BIGINT)) | extend last=arr[10] -- Indeks array di luar batas.Data Masukan
status: '200' code: 'Success' values: '[1,2,3]'Hasil Keluaran
status: '200' code: null values: [1, 2, 3] last: null
Menghilangkan Nilai Null
Untuk menghilangkan nilai null selama perhitungan, Anda dapat menggunakan ekspresi `COALESCE` untuk menggabungkan beberapa nilai berdasarkan prioritas dan mengambil nilai non-null pertama sebagai hasil akhir. Anda juga dapat menetapkan nilai default untuk digunakan jika semua hasil ekspresi adalah null.
Contoh
Baca elemen terakhir dari array. Jika array kosong, nilai defaultnya adalah 0.
Pernyataan SPL
* | extend values=json_parse(values) | extend values=cast(values as ARRAY(BIGINT)) | extend last=COALESCE(values[3], values[2], values[1], 0)Data Masukan
# Entri 1 values: '[1, 2, 3]' # Entri 2 values: '[]'Hasil Keluaran
# Entri 1 values: [1, 2, 3] last: 3 # Entri 2 values: [] last: 0
Pelarian Karakter
Tanda Kutip Tunggal
Tanda kutip tunggal digunakan untuk mengapit nilai bidang. Jika nilai bidang berisi tanda kutip tunggal, Anda harus menggunakan tanda kutip tunggal tambahan untuk melarikannya.
Contoh
Pernyataan SPL
* | extend user = 'Alice' | extend phone = 'Alice''s Phone'Hasil Keluaran
user: Alice phone: Alice's Phone
Tanda Kutip Ganda
Tanda kutip ganda digunakan untuk mengapit nama bidang. Jika nama bidang berisi tanda kutip ganda, Anda harus menggunakan tanda kutip ganda tambahan untuk melarikannya.
Contoh
Pernyataan SPL
* | extend user_name = 'Alice' | extend "user name" = 'Alice' | extend "user""name" = 'Alice'Hasil Keluaran
user_name: Alice user name: Alice user"name: Alice
Karakter Khusus Lainnya
Contoh 1
Dalam SPL, backslash (\) bukanlah karakter pelarian dan oleh karena itu disimpan apa adanya.
Pernyataan SPL
* | extend a = 'foo\tbar' | extend b = 'foo\nbar'Hasil Keluaran
a: foo\tbar b: foo\nbar
Contoh 2
Jika string harus mencakup karakter khusus, seperti karakter tab atau line feed, Anda dapat menggunakan fungsi chr untuk menggabungkan string.
Pernyataan SPL
* | extend a = concat('foo', chr(9), 'bar') | extend b = concat('foo', chr(10), 'bar')Hasil Keluaran
a: foo bar b: foo bar
Penanganan Kesalahan
Kesalahan sintaksis
Kesalahan sintaksis terjadi ketika pernyataan SPL salah bentuk, seperti nama instruksi yang salah, kesalahan referensi kata kunci, atau kesalahan pengaturan tipe. Saat terjadi kesalahan sintaksis, SPL tidak memproses data apa pun. Anda harus memodifikasi pernyataan berdasarkan pesan kesalahan.
Kesalahan data
Kesalahan data terjadi ketika fungsi atau konversi gagal selama eksekusi SPL. SPL menetapkan bidang hasil menjadi null. Karena kesalahan data dapat terjadi pada baris mana saja, SPL secara acak mengambil sampel dan hanya mengembalikan beberapa pesan kesalahan. Anda dapat mengabaikan kesalahan ini atau memodifikasi pernyataan SPL berdasarkan isi data.
Kesalahan data tidak menghentikan seluruh proses eksekusi. Pernyataan SPL tetap mengembalikan hasil, tetapi nilai bidang tempat kesalahan terjadi adalah null. Anda dapat mengabaikan kesalahan ini sesuai kebutuhan.
Waktu Eksekusi Habis
Pernyataan SPL mencakup berbagai instruksi, dan waktu eksekusi mereka bervariasi tergantung pada skenario data. Jika total waktu eksekusi pernyataan SPL melebihi periode timeout default, eksekusi berhenti dan kesalahan timeout dikembalikan. Dalam hal ini, hasil eksekusi kosong. Periode timeout default mungkin berbeda untuk kueri pemindaian, konsumsi real-time, dan pengumpulan Logtail.
Jika Anda mengalami kesalahan ini, Anda dapat menyesuaikan pernyataan SPL untuk mengurangi kompleksitasnya, misalnya, dengan menyederhanakan ekspresi reguler yang kompleks atau mengurangi jumlah alur kerja.
Batas Memori Terlampaui
Pernyataan SPL mencakup berbagai instruksi, dan konsumsi memori mereka bervariasi tergantung pada skenario data. Eksekusi SPL dibatasi pada kuota memori tertentu. Jika kuota ini terlampaui, eksekusi gagal dan kesalahan batas memori terlampaui dikembalikan. Dalam hal ini, hasil eksekusi kosong. Kuota memori default mungkin berbeda untuk kueri pemindaian, konsumsi real-time, dan pengumpulan Logtail.
Jika Anda mengalami kesalahan ini, Anda dapat menyesuaikan pernyataan SPL untuk mengurangi kompleksitasnya, mengurangi jumlah alur kerja, atau memeriksa apakah ukuran data mentah terlalu besar.