Pesan Protobuf

Versi 14.0.0 library klien Python memperkenalkan parameter konfigurasi baru yang diperlukan disebut use_proto_plus yang menentukan apakah Anda ingin library menampilkan pesan proto-plus atau pesan protobuf. Untuk mengetahui detail tentang cara menetapkan parameter ini, lihat dokumen konfigurasi.

Bagian ini menjelaskan implikasi performa saat memilih jenis pesan yang akan digunakan. Oleh karena itu, sebaiknya Anda membaca dan memahami opsi tersebut untuk membuat keputusan yang tepat. Namun, jika ingin mengupgrade ke versi 14.0.0 tanpa mengubah kode, Anda dapat menetapkan use_proto_plus ke True agar perubahan antarmuka tidak rusak.

Pesan Proto-plus versus protobuf

Pada versi 10.0.0, library klien Python bermigrasi ke pipeline generator kode baru yang mengintegrasikan proto-plus sebagai cara untuk meningkatkan ergonomi antarmuka pesan protobuf dengan membuatnya berperilaku lebih seperti objek Python native. Kompromi dari peningkatan ini adalah bahwa proto-plus memperkenalkan overhead performa.

Performa Proto-plus

Salah satu manfaat inti proto-plus adalah proto-plus mengonversi pesan protobuf dan jenis yang sudah dikenal menjadi jenis Python native melalui proses yang disebut marshaling jenis.

Marshaling terjadi saat sebuah kolom diakses pada instance pesan proto-plus, khususnya saat sebuah kolom dibaca atau disetel, misalnya, dalam definisi protobuf:

syntax = "proto3";

message Dog {
  string name = 1;
}

Jika definisi ini dikonversi ke class proto-plus, tampilannya akan terlihat seperti ini:

import proto

class Dog(proto.Message):
    name = proto.Field(proto.STRING, number=1)

Selanjutnya, Anda dapat melakukan inisialisasi class Dog dan mengakses kolom name-nya seperti pada objek Python lainnya:

dog = Dog()
dog.name = "Scruffy"
print(dog.name)

Saat membaca dan menetapkan kolom name, nilai akan dikonversi dari jenis str Python native menjadi jenis string sehingga nilai tersebut kompatibel dengan runtime protobuf.

Dalam analisis yang telah kami lakukan sejak rilis versi 10.0.0, kami menemukan bahwa waktu yang dihabiskan untuk melakukan konversi jenis ini memiliki dampak performa yang cukup besar sehingga penting untuk memberi pengguna opsi untuk menggunakan pesan protobuf.

Kasus penggunaan untuk pesan proto-plus dan protobuf

Kasus penggunaan pesan Proto-plus
Proto-plus menawarkan sejumlah peningkatan ergonomis dibandingkan pesan protobuf, sehingga ideal untuk menulis kode yang mudah dikelola dan dapat dibaca. Karena mengekspos objek Python native, objek ini lebih mudah digunakan dan dipahami.
Kasus penggunaan pesan protobuf
Gunakan protobuf untuk kasus penggunaan yang sensitif terhadap performa, khususnya dalam aplikasi yang perlu memproses laporan besar dengan cepat, atau yang membuat permintaan mutasi dengan sejumlah besar operasi, misalnya dengan BatchJobService atau OfflineUserDataJobService.

Mengubah jenis pesan secara dinamis

Setelah memilih jenis pesan yang sesuai untuk aplikasi, Anda mungkin perlu menggunakan jenis pesan lainnya untuk alur kerja tertentu. Dalam hal ini, mudah untuk beralih antara dua jenis tersebut secara dinamis menggunakan utilitas yang ditawarkan oleh library klien. Menggunakan class pesan Dog yang sama seperti di atas:

from google.ads.googleads import util

# Proto-plus message type
dog = Dog()

# Protobuf message type
dog = util.convert_proto_plus_to_protobuf(dog)

# Back to proto-plus message type
dog = util.convert_protobuf_to_proto_plus(dog)

Perbedaan antarmuka pesan protobuf

Antarmuka proto-plus didokumentasikan secara detail, tetapi di sini kami akan menyoroti beberapa perbedaan utama yang memengaruhi kasus penggunaan umum untuk library klien Google Ads.

Serialisasi byte

Pesan Proto-plus
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
Pesan protobuf
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

Serialisasi JSON

Pesan Proto-plus
serialized = type(campaign).to_json(campaign)
deserialized = type(campaign).from_json(serialized)
Pesan protobuf
from google.protobuf.json_format import MessageToJson, Parse

serialized = MessageToJson(campaign)
deserialized = Parse(serialized, campaign)

Mask kolom

Metode helper field mask yang disediakan oleh api-core dirancang untuk menggunakan instance pesan protobuf. Jadi, saat menggunakan pesan proto-plus, konversikan pesan tersebut menjadi pesan protobuf untuk memanfaatkan helper:

Pesan Proto-plus
from google.api_core.protobuf_helpers import field_mask

campaign = client.get_type("Campaign")
protobuf_campaign = util.convert_proto_plus_to_protobuf(campaign)
mask = field_mask(None, protobuf_campaign)
Pesan protobuf
from google.api_core.protobuf_helpers import field_mask

campaign = client.get_type("Campaign")
mask = field_mask(None, campaign)

Enum

Enum yang diekspos oleh pesan proto-plus merupakan instance jenis enum native Python sehingga mewarisi sejumlah metode praktis.

Pengambilan jenis enum

Saat menggunakan metode GoogleAdsClient.get_type untuk mengambil enum, pesan yang ditampilkan akan sedikit berbeda bergantung pada apakah Anda menggunakan pesan proto-plus atau protobuf. Contoh:

Pesan Proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
Pesan protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

Untuk mempermudah pengambilan enum, ada atribut kemudahan pada instance GoogleAdsClient yang memiliki antarmuka konsisten, terlepas dari jenis pesan yang Anda gunakan:

val = client.enums.CampaignStatusEnum.PAUSED

Pengambilan nilai enum

Terkadang, sebaiknya ketahui nilai atau ID kolom dari enum tertentu, misalnya, PAUSED pada CampaignStatusEnum terkait dengan 3:

Pesan Proto-plus
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the value of campaign status
print(campaign.status.value)
Pesan protobuf
campaign = client.get_type("Campaign")
status_enum = client.enums.CampaignStatusEnum
campaign.status = status_enum.PAUSED
# To read the value of campaign status
print(status_enum.CampaignStatus.Value(campaign.status))

Pengambilan nama enum

Terkadang, mengetahui nama kolom enum adalah hal yang berguna. Misalnya, saat membaca objek dari API, Anda mungkin ingin mengetahui status kampanye mana yang terkait dengan int 3:

Pesan Proto-plus
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the name of campaign status
print(campaign.status.name)
Pesan protobuf
campaign = client.get_type("Campaign")
status_enum = client.enums.CampaignStatusEnum
# Sets the campaign status to the int value for PAUSED
campaign.status = status_enum.PAUSED
# To read the name of campaign status
status_enum.CampaignStatus.Name(campaign.status)

Kolom berulang

Seperti yang dijelaskan dalam dokumen proto-plus, kolom berulang umumnya setara dengan daftar yang diketik, yang berarti kolom tersebut berperilaku hampir sama dengan list.

Menambahkan ke kolom skalar berulang

Saat menambahkan nilai ke kolom jenis skalar berulang, misalnya kolom string atau int64, antarmukanya sama terlepas dari jenis pesannya:

Pesan Proto-plus
ad.final_urls.append("https://www.example.com")
Pesan protobuf
ad.final_urls.append("https://www.example.com")

Ini juga mencakup semua metode list umum lainnya, misalnya extend:

Pesan Proto-plus
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
Pesan protobuf
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])

Menambahkan jenis pesan ke kolom berulang

Jika kolom berulang bukan merupakan jenis skalar, perilaku saat menambahkannya ke kolom berulang akan sedikit berbeda:

Pesan Proto-plus
frequency_cap = client.get_type("FrequencyCapEntry")
frequency_cap.cap = 100
campaign.frequency_caps.append(frequency_cap)
Pesan protobuf
# The add method initializes a message and adds it to the repeated field
frequency_cap = campaign.frequency_caps.add()
frequency_cap.cap = 100

Menetapkan kolom berulang

Untuk kolom berulang skalar dan non-skalar, Anda dapat menetapkan daftar ke kolom tersebut dengan cara yang berbeda:

Pesan Proto-plus
# In proto-plus it's possible to use assignment.
urls = ["https://www.example.com"]
ad.final_urls = urls
Pesan protobuf
# Protobuf messages do not allow assignment, but you can replace the
# existing list using slice syntax.
urls = ["https://www.example.com"]
ad.final_urls[:] = urls

Pesan kosong

Terkadang, penting untuk mengetahui apakah instance pesan berisi informasi, atau menyetel kolomnya.

Pesan Proto-plus
# When using proto-plus messages you can simply check the message for
# truthiness.
is_empty = bool(campaign)
is_empty = not campaign
Pesan protobuf
is_empty = campaign.ByteSize() == 0

Salinan pesan

Untuk pesan proto-plus dan protobuf, sebaiknya gunakan metode helper copy_from di GoogleAdsClient:

client.copy_from(campaign, other_campaign)

Kolom pesan kosong

Proses untuk menyetel kolom pesan kosong sama, terlepas dari jenis pesan yang Anda gunakan. Anda hanya perlu menyalin pesan kosong ke kolom yang dimaksud. Lihat bagian Salinan pesan serta panduan Kolom Pesan Kosong. Berikut adalah contoh cara menetapkan kolom pesan kosong:

client.copy_from(campaign.manual_cpm, client.get_type("ManualCpm"))

Nama kolom yang merupakan kata yang dicadangkan

Saat menggunakan pesan proto-plus, nama kolom akan otomatis muncul dengan garis bawah di belakangnya jika nama tersebut juga merupakan kata yang hanya boleh digunakan di Python. Berikut ini contoh penggunaan instance Asset:

asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE

Daftar lengkap nama yang dicadangkan dibuat di modul generator gapic. Kode ini juga dapat diakses secara terprogram.

Pertama, instal modul:

python -m pip install gapic-generator

Kemudian, di REPL atau skrip Python:

import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)

Kehadiran kolom

Karena kolom pada instance pesan protobuf memiliki nilai default, mengetahui apakah kolom telah ditetapkan atau belum secara intuitif tidak selalu terjadi.

Pesan Proto-plus
# Use the "in" operator.
has_field = "name" in campaign
Pesan protobuf
campaign = client.get_type("Campaign")
# Determines whether "name" is set and not just an empty string.
campaign.HasField("name")

Antarmuka class Message protobuf memiliki metode HasField yang menentukan apakah kolom pada pesan telah ditetapkan atau belum, meskipun telah ditetapkan ke nilai default.

Metode pesan protobuf

Antarmuka pesan protobuf mencakup beberapa metode praktis yang bukan bagian dari antarmuka proto-plus. Namun, mudah untuk mengaksesnya dengan mengonversi pesan proto-plus menjadi versi protobufnya:

# Accessing the ListFields method
protobuf_campaign = util.convert_protobuf_to_proto_plus(campaign)
print(campaign.ListFields())

# Accessing the Clear method
protobuf_campaign = util.convert_protobuf_to_proto_plus(campaign)
print(campaign.Clear())

Issue Tracker

Jika ada pertanyaan tentang perubahan ini atau masalah saat bermigrasi ke library versi 14.0.0, ajukan masalah di pelacak kami.