ข้อความ Protobuf

เวอร์ชัน 14.0.0 ของไลบรารีของไคลเอ็นต์ Python มีพารามิเตอร์การกำหนดค่าใหม่ที่จำเป็นที่เรียกว่า use_proto_plus ซึ่งระบุว่าต้องการให้ไลบรารีแสดงผลข้อความ Proto-plus หรือข้อความ Protobuf โปรดดูรายละเอียดเกี่ยวกับวิธีตั้งค่าพารามิเตอร์นี้ที่เอกสารการกำหนดค่า

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

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

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

ประสิทธิภาพแบบ Proto Plus

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

การจัดรูปแบบดังกล่าวจะเกิดขึ้นเมื่อมีการเข้าถึงฟิลด์ในอินสแตนซ์ข้อความ 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 ระบบจะแปลงค่าจากประเภท Python str แบบดั้งเดิมเป็นประเภท string เพื่อให้ค่าเข้ากันได้กับรันไทม์ของ Protobuf

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

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

กรณีการใช้งานข้อความ Proto Plus
Protoplus มีการปรับปรุงด้านสรีรศาสตร์มากมายเหนือข้อความ Protobuf จึงเหมาะสำหรับการเขียนโค้ดที่ดูแลรักษาและอ่านได้ เนื่องจากจะแสดงออบเจ็กต์ Python แบบดั้งเดิม จึงใช้งานและเข้าใจได้ง่ายกว่า
กรณีการใช้งานข้อความ Protobuf
ใช้ Protobuf สำหรับ Use Case ที่คำนึงถึงประสิทธิภาพ โดยเฉพาะในแอปที่ต้องประมวลผลรายงานขนาดใหญ่อย่างรวดเร็ว หรือสร้างคำขอที่เปลี่ยนแปลงซึ่งมีการดำเนินการจำนวนมาก เช่น ด้วย 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 ระบุไว้อย่างละเอียด แต่เราจะไฮไลต์ความแตกต่างที่สำคัญบางอย่างซึ่งส่งผลต่อ Use Case ทั่วไปสำหรับไลบรารีไคลเอ็นต์ 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 ดึงข้อมูลได้ง่ายขึ้น เรามีแอตทริบิวต์ Convenum ในอินสแตนซ์ 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
# To read the value of campaign status
print(status_enum.CampaignStatus.Value(campaign.status))

การดึงข้อมูลชื่อแบบแจกแจง

บางครั้งการทราบชื่อของฟิลด์ enum ก็มีประโยชน์ เช่น เมื่ออ่านออบเจ็กต์จาก API คุณอาจต้องการทราบว่าสถานะแคมเปญใดที่ int 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
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 simply check the message for
# truthiness.
is_empty = bool(campaign)
is_empty = not 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:

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")

อินเทอร์เฟซคลาส Protobuf Message มีเมธอด HasField ที่กำหนดว่ามีการตั้งค่าช่องในข้อความหรือไม่ แม้ว่าจะตั้งค่าเป็นค่าเริ่มต้นก็ตาม

เมธอดสร้างข้อความ Protobuf

อินเทอร์เฟซข้อความ Protobuf มีวิธีอำนวยความสะดวกบางอย่างที่ไม่มีในอินเทอร์เฟซ Proto-plus แต่จะเข้าถึงได้ง่ายๆ โดยการแปลงข้อความ Protobuf เป็นข้อความ 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())

เครื่องมือติดตามปัญหา

หากมีข้อสงสัยเกี่ยวกับการเปลี่ยนแปลงเหล่านี้หรือปัญหาในการย้ายข้อมูลไปยังเวอร์ชัน 14.0.0 ของไลบรารี โปรดแจ้งปัญหาในตัวติดตามของเรา