Thông báo Protobuf

Phiên bản 14.0.0 của thư viện ứng dụng Python giới thiệu một tham số cấu hình bắt buộc mới có tên là use_proto_plus. Tham số này chỉ định xem bạn muốn thư viện trả về thông báo proto+ hay thông báo protobuf. Để biết thông tin chi tiết về cách đặt tham số này, hãy xem tài liệu về cấu hình.

Phần này mô tả các hệ quả về hiệu suất của việc chọn loại thông báo mà bạn muốn sử dụng. Do đó, bạn nên đọc và tìm hiểu các tuỳ chọn để đưa ra quyết định sáng suốt. Tuy nhiên, nếu muốn nâng cấp lên phiên bản 14.0.0 mà không thay đổi mã, bạn có thể đặt use_proto_plus thành True để tránh làm hỏng các thay đổi về giao diện.

Thông báo Proto-plus so với protobuf

Trong phiên bản 10.0.0, thư viện ứng dụng Python đã chuyển sang một quy trình tạo mã mới tích hợp proto-plus như một cách để cải thiện tính hiệu quả của giao diện thông báo protobuf thông qua việc làm cho chúng hoạt động giống với các đối tượng Python gốc hơn. Sự đánh đổi của điểm cải tiến này là proto-plus dẫn đến mức hao tổn hiệu suất.

Hiệu suất Proto+

Một trong những lợi ích chính của proto-plus là chuyển đổi thông báo protobufcác kiểu phổ biến thành các kiểu Python gốc thông qua một quy trình có tên là marshaling.

Quá trình so khớp xảy ra khi một trường được truy cập trên thực thể thông báo proto+, cụ thể là khi một trường được đọc hoặc đặt, chẳng hạn như trong một định nghĩa protobuf:

syntax = "proto3";

message Dog {
  string name = 1;
}

Khi định nghĩa này được chuyển đổi thành một lớp proto-plus, lớp này sẽ có dạng như sau:

import proto

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

Sau đó, bạn có thể khởi tạo lớp Dog và truy cập vào trường name của lớp này như với bất kỳ đối tượng Python nào khác:

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

Khi đọc và đặt trường name, giá trị sẽ được chuyển đổi từ loại Python str gốc sang loại string để giá trị tương thích với thời gian chạy protobuf.

Trong quá trình phân tích kể từ khi phát hành phiên bản 10.0.0, chúng tôi đã xác định rằng thời gian dành cho việc thực hiện các lượt chuyển đổi loại này có tác động đủ lớn đến hiệu suất. Điều quan trọng là cung cấp cho người dùng lựa chọn sử dụng thông báo protobuf.

Các trường hợp sử dụng cho thông báo proto+ và protobuf

Các trường hợp sử dụng thông báo Proto+
Proto-plus cung cấp một số điểm cải tiến về hiệu quả sử dụng so với các thông báo protobuf, vì vậy, đây là những công cụ lý tưởng để viết mã dễ bảo trì và dễ đọc. Vì các đối tượng này hiển thị các đối tượng Python gốc, nên sẽ dễ sử dụng và dễ hiểu hơn.
Các trường hợp sử dụng thông báo Protobuf
Sử dụng protobuf cho các trường hợp sử dụng nhạy cảm về hiệu suất, đặc biệt là trong các ứng dụng cần xử lý các báo cáo lớn một cách nhanh chóng hoặc tạo các yêu cầu đột biến với số lượng lớn thao tác, chẳng hạn như với BatchJobService hoặc OfflineUserDataJobService.

Thay đổi linh động loại thông báo

Sau khi chọn loại thông báo thích hợp cho ứng dụng, có thể bạn sẽ thấy cần sử dụng loại còn lại cho một quy trình công việc cụ thể. Trong trường hợp này, bạn có thể dễ dàng chuyển đổi giữa hai loại một cách linh hoạt bằng cách sử dụng các tiện ích do thư viện ứng dụng cung cấp. Sử dụng cùng một lớp thông báo Dog ở trên:

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)

Sự khác biệt về giao diện thông báo Protobuf

Giao diện proto-plus được ghi lại chi tiết, nhưng ở đây, chúng tôi sẽ làm nổi bật một số điểm khác biệt chính ảnh hưởng đến các trường hợp sử dụng phổ biến của thư viện ứng dụng Google Ads.

Chuyển đổi tuần tự Bytes

Thông báo Proto+
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
Thông báo Protobuf
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

Chuyển đổi tuần tự JSON

Thông báo Proto+
serialized = type(campaign).to_json(campaign)
deserialized = type(campaign).from_json(serialized)
Thông báo Protobuf
from google.protobuf.json_format import MessageToJson, Parse

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

Mặt nạ cho trường (field mask)

Phương thức trình trợ giúp mặt nạ trường do api-core cung cấp được thiết kế để sử dụng các thực thể thông báo protobuf. Vì vậy, khi sử dụng thông báo proto-plus, hãy chuyển đổi các thông báo đó thành thông báo protobuf để sử dụng trình trợ giúp:

Thông báo Proto+
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)
Thông báo Protobuf
from google.api_core.protobuf_helpers import field_mask

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

Enum

Enum hiển thị trong các thông báo proto-plus là các phiên bản của loại enum gốc của Python và do đó kế thừa một số phương thức tiện lợi.

Truy xuất loại enum

Khi sử dụng phương thức GoogleAdsClient.get_type để truy xuất enum, các thông báo được trả về sẽ hơi khác nhau, tuỳ thuộc vào việc bạn sử dụng thông báo proto-plus hay protobuf. Ví dụ:

Thông báo Proto+
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
Thông báo Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

Để việc truy xuất enum trở nên đơn giản hơn, có một thuộc tính tiện lợi trên các thực thể GoogleAdsClient có giao diện nhất quán, bất kể bạn đang sử dụng loại thông báo nào:

val = client.enums.CampaignStatusEnum.PAUSED

Truy xuất giá trị enum

Đôi khi, bạn nên biết giá trị hoặc mã trường của một enum nhất định, chẳng hạn như PAUSED trên CampaignStatusEnum tương ứng với 3:

Thông báo Proto+
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the value of campaign status
print(campaign.status.value)
Thông báo 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))

Truy xuất tên enum

Đôi khi, việc biết tên của trường enum sẽ rất hữu ích. Ví dụ: khi đọc các đối tượng từ API, bạn có thể muốn biết trạng thái chiến dịch tương ứng với số nguyên 3:

Thông báo Proto+
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the name of campaign status
print(campaign.status.name)
Thông báo 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)

Các trường lặp lại

Như đã mô tả trong tài liệu proto-plus, các trường lặp lại thường tương đương với danh sách đã nhập, nghĩa là các trường này hoạt động gần như giống với list.

Thêm vào các trường vô hướng lặp lại

Khi thêm giá trị vào các trường kiểu vô hướng lặp lại, ví dụ như các trường string hoặc int64, giao diện sẽ giống nhau bất kể loại thông báo:

Thông báo Proto+
ad.final_urls.append("https://www.example.com")
Thông báo Protobuf
ad.final_urls.append("https://www.example.com")

Phương thức này cũng bao gồm mọi phương thức list phổ biến khác, ví dụ: extend:

Thông báo Proto+
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
Thông báo Protobuf
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])

Thêm các loại thông báo vào các trường lặp lại

Nếu trường lặp lại không phải là một kiểu vô hướng, thì hành vi khi thêm các trường đó vào các trường lặp lại sẽ hơi khác nhau:

Thông báo Proto+
frequency_cap = client.get_type("FrequencyCapEntry")
frequency_cap.cap = 100
campaign.frequency_caps.append(frequency_cap)
Thông báo Protobuf
# The add method initializes a message and adds it to the repeated field
frequency_cap = campaign.frequency_caps.add()
frequency_cap.cap = 100

Chỉ định các trường lặp lại

Đối với cả trường lặp lại vô hướng và không vô hướng, bạn có thể chỉ định danh sách cho trường theo nhiều cách:

Thông báo Proto+
# In proto-plus it's possible to use assignment.
urls = ["https://www.example.com"]
ad.final_urls = urls
Thông báo 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

Thư không có nội dung

Đôi khi, việc biết liệu một thực thể thông báo có chứa thông tin nào hoặc đã đặt trường nào hay không sẽ rất hữu ích.

Thông báo Proto+
# When using proto-plus messages you can simply check the message for
# truthiness.
is_empty = bool(campaign)
is_empty = not campaign
Thông báo Protobuf
is_empty = campaign.ByteSize() == 0

Nội dung tin nhắn

Đối với cả thông báo proto-plus và protobuf, bạn nên sử dụng phương thức trợ giúp copy_from trên GoogleAdsClient:

client.copy_from(campaign, other_campaign)

Trường tin nhắn trống

Quy trình đặt các trường thông báo trống là như nhau bất kể bạn đang sử dụng loại thông báo nào. Bạn chỉ cần sao chép một thông báo trống vào trường đang được đề cập đến. Xem mục Nội dung thông báo cũng như hướng dẫn về Trường thông báo trống. Dưới đây là ví dụ về cách đặt một trường thông báo trống:

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

Tên trường là từ dành riêng

Khi sử dụng thông báo proto-plus, tên trường sẽ tự động xuất hiện kèm theo dấu gạch dưới ở cuối nếu tên đó cũng là một từ dành riêng trong Python. Dưới đây là ví dụ về cách làm việc với thực thể Asset:

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

Danh sách đầy đủ các tên dành riêng được tạo trong mô-đun trình tạo khoảng trống. Bạn cũng có thể truy cập tệp này theo phương thức lập trình.

Trước tiên, hãy cài đặt mô-đun:

python -m pip install gapic-generator

Sau đó, trong REPL hoặc tập lệnh Python:

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

Sự hiện diện của trường

Vì các trường trên thực thể thông báo protobuf có giá trị mặc định, nên việc biết một trường đã được đặt hay chưa không phải lúc nào cũng trực quan.

Thông báo Proto+
# Use the "in" operator.
has_field = "name" in campaign
Thông báo Protobuf
campaign = client.get_type("Campaign")
# Determines whether "name" is set and not just an empty string.
campaign.HasField("name")

Giao diện lớp Message protobuf có phương thức HasField xác định liệu trường trên thông báo đã được đặt hay chưa, ngay cả khi đã được đặt thành giá trị mặc định.

Phương thức thông báo Protobuf

Giao diện thông báo protobuf bao gồm một số phương thức tiện lợi không thuộc giao diện proto-plus. Tuy nhiên, bạn có thể dễ dàng truy cập các phương thức đó bằng cách chuyển đổi một thông báo proto-plus thành phiên bản protobuf:

# 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())

Công cụ theo dõi lỗi

Nếu bạn có thắc mắc về những thay đổi này hoặc bất kỳ vấn đề nào khi chuyển sang phiên bản 14.0.0 của thư viện, hãy báo cáo vấn đề trên công cụ theo dõi của chúng tôi.