ข้อความ Protobuf

พารามิเตอร์การกำหนดค่า use_proto_plus ช่วยให้คุณระบุได้ว่าต้องการให้ไลบรารีแสดงผลข้อความ proto-plus หรือข้อความ protobuf ดูรายละเอียดเกี่ยวกับวิธีตั้งค่าพารามิเตอร์นี้ได้ที่เอกสารการกำหนดค่า

ส่วนนี้จะอธิบายผลกระทบด้านประสิทธิภาพของแต่ละตัวเลือกเพื่อให้คุณเลือกแนวทางที่ดีที่สุดสำหรับแอปพลิเคชันได้

ข้อความ Proto-plus เทียบกับ Protobuf

ไปป์ไลน์โปรแกรมสร้างโค้ดจะผสานรวม proto-plus เพื่อปรับปรุงหลักสรีรศาสตร์ของอินเทอร์เฟซข้อความ protobuf โดยทำให้ทำงานเหมือนออบเจ็กต์ Python มาตรฐานมากขึ้น อย่างไรก็ตาม การใช้ proto-plus จะทำให้เกิดโอเวอร์เฮดด้านประสิทธิภาพ

ประสิทธิภาพของ Proto-plus

ประโยชน์หลักอย่างหนึ่งของ proto-plus คือการแปลงข้อความ protobuf และประเภทที่รู้จักกันดีเป็นประเภท Python ในตัวผ่านกระบวนการที่เรียกว่าการจัดระเบียบประเภท

การจัดระเบียบจะเกิดขึ้นเมื่อมีการเข้าถึงฟิลด์ในอินสแตนซ์ข้อความ proto-plus โดยเฉพาะเมื่อมีการอ่านหรือตั้งค่าฟิลด์ เช่น ในคำจำกัดความ protobuf

syntax = "proto3";

message Dog {
  string name = 1;
}

เมื่อแปลงคำจำกัดความนี้เป็นคลาส proto-plus จะมีลักษณะดังนี้

import proto


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

จากนั้นคุณจะเริ่มต้นคลาส Dog และเข้าถึงฟิลด์ name ได้เหมือนกับออบเจ็กต์ Python อื่นๆ ดังนี้

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

เมื่ออ่านและตั้งค่าช่อง name ระบบจะแปลงค่าจากประเภท str ของ Python ในตัวเป็นประเภท string เพื่อให้ค่าเข้ากันได้กับรันไทม์ protobuf

เวลาที่ใช้ในการแปลงประเภทเหล่านี้มีผลกระทบต่อประสิทธิภาพมากพอที่คุณควรตัดสินใจว่าจะใช้ข้อความ Proto-plus หรือ Protobuf โดยพิจารณาจากความต้องการของแอปพลิเคชัน

กรณีการใช้งานสำหรับข้อความ proto-plus และ protobuf

กรณีการใช้งานข้อความ Proto-plus
Proto-plus มีการปรับปรุงตามหลักสรีรศาสตร์หลายอย่างเหนือข้อความ protobuf จึงเหมาะอย่างยิ่งสำหรับการเขียนโค้ดที่ดูแลรักษาได้และอ่านง่าย เนื่องจากแสดงออบเจ็กต์ Python มาตรฐาน จึงใช้งานและทำความเข้าใจได้ง่ายกว่า
กรณีการใช้งานข้อความ Protobuf
ใช้ Protobuf สำหรับกรณีการใช้งานที่คำนึงถึงประสิทธิภาพ โดยเฉพาะในแอปที่ต้องประมวลผลรายงานขนาดใหญ่อย่างรวดเร็ว หรือสร้างคำขอเปลี่ยนแปลงข้อมูลในเซิร์ฟเวอร์ที่มีการดำเนินการจำนวนมาก เช่น BatchJobService หรือ OfflineUserDataJobService

เปลี่ยนประเภทข้อความแบบไดนามิก

หลังจากเลือกประเภทข้อความที่เหมาะสมสำหรับแอปแล้ว คุณอาจพบว่าต้องใช้ประเภทอื่นสำหรับเวิร์กโฟลว์ที่เฉพาะเจาะจง ในกรณีนี้ คุณสามารถสลับระหว่าง 2 ประเภทแบบไดนามิกโดยใช้ยูทิลิตีที่ไลบรารีของไคลเอ็นต์มีให้ การใช้คลาสข้อความ Dog เดียวกันจากก่อนหน้านี้

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)

ความแตกต่างของอินเทอร์เฟซข้อความ Protobuf

อินเทอร์เฟซ proto-plus มีเอกสารประกอบโดยละเอียด และส่วนต่อไปนี้จะไฮไลต์ความแตกต่างที่สำคัญซึ่งส่งผลต่อกรณีการใช้งานทั่วไปสำหรับไลบรารีของไคลเอ็นต์ Google Ads

การทำให้ไบต์เป็นอนุกรม

ข้อความ Proto-plus
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
ข้อความ Protobuf
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

การแปลงรูปแบบ JSON

ข้อความ Proto-plus
serialized = type(campaign).to_json(campaign)
deserialized = type(campaign).from_json(serialized)
ข้อความ Protobuf
from google.protobuf.json_format import MessageToJson, Parse

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

มาสก์ฟิลด์

เมธอดตัวช่วยมาสก์ฟิลด์ที่ api-core มีให้ได้รับการออกแบบมาเพื่อใช้อินสแตนซ์ข้อความ protobuf เมื่อใช้ข้อความ proto-plus ให้แปลงเป็นข้อความ protobuf เพื่อใช้ตัวช่วย ดังนี้

ข้อความ 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)
ข้อความ Protobuf
from google.api_core.protobuf_helpers import field_mask

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

Enum

Enum ที่แสดงโดยข้อความ proto-plus เป็นอินสแตนซ์ของประเภท enum ในตัวของ Python จึงรับค่าเมธอดที่อำนวยความสะดวกจำนวนหนึ่ง

การดึงข้อมูลประเภท Enum

เมื่อใช้เมธอด GoogleAdsClient.get_type เพื่อดึงข้อมูล Enum ข้อความที่แสดงผลจะแตกต่างกันเล็กน้อย โดยขึ้นอยู่กับว่าคุณใช้ข้อความ proto-plus หรือ protobuf เช่น

ข้อความ Proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
ข้อความ Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

เพื่อให้ดึงข้อมูล Enum ได้ง่ายขึ้น จึงมีแอตทริบิวต์อำนวยความสะดวกในอินสแตนซ์ GoogleAdsClient ที่มีอินเทอร์เฟซที่สอดคล้องกันไม่ว่าคุณจะใช้ข้อความประเภทใดก็ตาม ดังนี้

val = client.enums.CampaignStatusEnum.PAUSED

การดึงค่า enum

บางครั้งการทราบค่าหรือรหัสฟิลด์ของ enum หนึ่งๆ ก็มีประโยชน์ เช่น PAUSED ใน CampaignStatusEnum สอดคล้องกับ 3

ข้อความ Proto-plus
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the value of campaign status
print(campaign.status.value)
ข้อความ Protobuf
campaign = client.get_type("Campaign")
status_enum = client.enums.CampaignStatusEnum
campaign.status = status_enum.PAUSED
# Native protobuf enum fields already store the integer value (3):
print(campaign.status)
# Or look up the integer value from the enum name string:
print(status_enum.CampaignStatus.Value("PAUSED"))

การดึงข้อมูลชื่อ enum

บางครั้งการทราบชื่อของช่อง enum ก็มีประโยชน์ ตัวอย่างเช่น เมื่ออ่านออบเจ็กต์จาก API คุณอาจต้องการทราบว่าจำนวนเต็ม 3 สอดคล้องกับสถานะแคมเปญใด

ข้อความ Proto-plus
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the name of campaign status
print(campaign.status.name)
ข้อความ 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
print(status_enum.CampaignStatus.Name(campaign.status))

ฟิลด์ที่ซ้ำได้

ตามที่อธิบายไว้ในเอกสาร proto-plus ฟิลด์ที่ซ้ำได้โดยทั่วไปจะเทียบเท่ากับรายการที่พิมพ์ ซึ่งหมายความว่าฟิลด์ดังกล่าวทำงานเกือบจะเหมือนกับ list

เพิ่มค่าต่อท้ายช่องสเกลาร์ที่ซ้ำกัน

เมื่อเพิ่มค่าลงในช่องประเภทสเกลาร์ที่ซ้ำกัน เช่น ช่อง string หรือ int64 อินเทอร์เฟซจะเหมือนกันไม่ว่าจะเป็นข้อความประเภทใดก็ตาม ดังนี้

ข้อความ Proto-plus
ad.final_urls.append("https://www.example.com")
ข้อความ Protobuf
ad.final_urls.append("https://www.example.com")

ซึ่งรวมถึงวิธีการ list ทั่วไปอื่นๆ ทั้งหมดด้วย เช่น extend

ข้อความ Proto-plus
ad.final_urls.extend(
    ["https://www.example.com", "https://www.example.com/2"]
)
ข้อความ Protobuf
ad.final_urls.extend(
    ["https://www.example.com", "https://www.example.com/2"]
)

เพิ่มประเภทข้อความต่อท้ายฟิลด์ที่ซ้ำได้

หากฟิลด์ที่ซ้ำได้ไม่ใช่ประเภทสเกลาร์ ลักษณะการทำงานเมื่อเพิ่มฟิลด์ดังกล่าวลงในฟิลด์ที่ซ้ำได้จะแตกต่างกันเล็กน้อย ดังนี้

ข้อความ Proto-plus
frequency_cap = client.get_type("FrequencyCapEntry")
frequency_cap.cap = 100
campaign.frequency_caps.append(frequency_cap)
ข้อความ Protobuf
# The add method initializes a message and adds it to the repeated field
frequency_cap = campaign.frequency_caps.add()
frequency_cap.cap = 100

กำหนดฟิลด์ที่ซ้ำได้

สำหรับฟิลด์ที่ซ้ำได้ทั้งแบบสเกลาร์และไม่ใช่สเกลาร์ คุณสามารถกำหนดรายการให้กับฟิลด์ได้หลายวิธี ดังนี้

ข้อความ Proto-plus
# In proto-plus it's possible to use assignment.
urls = ["https://www.example.com"]
ad.final_urls = urls
ข้อความ 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

ข้อความว่างเปล่า

บางครั้งการทราบว่าอินสแตนซ์ข้อความมีข้อมูลใดๆ หรือมีการตั้งค่าฟิลด์ใดๆ หรือไม่ก็เป็นประโยชน์

ข้อความ Proto-plus
# When using proto-plus messages you can check the message for truthiness.
is_empty = not bool(campaign)
ข้อความ Protobuf
is_empty = campaign.ByteSize() == 0

ข้อความโฆษณา

สำหรับทั้งข้อความ proto-plus และ protobuf ให้ใช้เมธอดตัวช่วย copy_from ใน GoogleAdsClient ดังนี้

client.copy_from(campaign, other_campaign)

ช่องข้อความว่างเปล่า

ขั้นตอนการตั้งค่าช่องข้อความว่างจะเหมือนกันไม่ว่าคุณจะใช้ข้อความประเภทใดก็ตาม คุณคัดลอกข้อความว่างเปล่าลงในช่องที่เป็นปัญหา ดูส่วนข้อความที่ซ้ำกัน รวมถึงคำแนะนำเกี่ยวกับช่องข้อความว่างเปล่า ตัวอย่างต่อไปนี้แสดงวิธีตั้งค่าช่องข้อความว่างเปล่า

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

ชื่อฟิลด์ที่เป็นคำที่สงวนไว้

เมื่อใช้ข้อความ proto-plus ชื่อฟิลด์จะปรากฏพร้อมขีดล่างต่อท้ายโดยอัตโนมัติหากชื่อนั้นเป็นคำสงวนใน Python ด้วย ตัวอย่างต่อไปนี้แสดงวิธีทำงานกับอินสแตนซ์ Asset

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

รายการชื่อที่สงวนไว้ทั้งหมดจะสร้างขึ้นในโมดูล gapic generator นอกจากนี้ยังเข้าถึงได้แบบเป็นโปรแกรมด้วย

ก่อนอื่นให้ติดตั้งโมดูล โดยทำดังนี้

python -m pip install gapic-generator

จากนั้นใน Python REPL หรือสคริปต์ ให้ทำดังนี้

import gapic.utils

print(gapic.utils.reserved_names.RESERVED_NAMES)

การตรวจหาบุคคลในพื้นที่

เนื่องจากช่องในอินสแตนซ์ข้อความ protobuf มีค่าเริ่มต้น จึงอาจไม่ทราบได้เสมอไปว่ามีการตั้งค่าช่องหรือไม่

ข้อความ Proto-plus
# Use the "in" operator.
has_field = "name" in campaign
ข้อความ Protobuf
campaign = client.get_type("Campaign")
# Determines whether "name" is set and not just an empty string.
campaign.HasField("name")

อินเทอร์เฟซคลาส Message ของ protobuf มีเมธอด HasField ที่กำหนดว่ามีการตั้งค่าข้อความย่อย ช่อง oneof หรือช่องสเกลาร์ optional ในข้อความหรือไม่ แม้ว่าจะตั้งค่าเป็นค่าเริ่มต้นก็ตาม (การเรียก HasField ในฟิลด์สเกลาร์ที่ไม่บังคับใน proto3 จะทำให้เกิด ValueError)

เมธอดข้อความ Protobuf

อินเทอร์เฟซข้อความ protobuf มีเมธอดที่อำนวยความสะดวกบางอย่างซึ่งไม่ได้เป็นส่วนหนึ่งของอินเทอร์เฟซ proto-plus แต่คุณสามารถเข้าถึงได้โดยการแปลงข้อความ proto-plus เป็นข้อความ protobuf ที่เทียบเท่ากัน ดังนี้

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

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

Issue Tracker

หากมีคำถามเกี่ยวกับการเปลี่ยนแปลงเหล่านี้หรือปัญหาในการย้ายข้อมูลไปยังไลบรารีเวอร์ชันล่าสุด โปรดรายงานปัญหาใน Issue Tracker