הודעות 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 הוא ההמרה של הודעות protobuf וסוגים מוכרים לסוגי Python מקוריים, באמצעות תהליך שנקרא סידור סגנונות.

סידור מתבצע כשניגשים לשדה במופע של הודעת פרוטו פלוס, במיוחד כששדה נקרא או מוגדר, לדוגמה, בהגדרת פרוטובוב:

syntax = "proto3";

message Dog {
  string name = 1;
}

כשממירים את ההגדרה הזו למחלקה פרוטו-פלוס, היא תיראה בערך כך:

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 כדי שהערך יתאים לזמן הריצה של הפרוטובופון.

בניתוח שערכנו מאז הפרסום של הגרסה 10.0.0, הגענו למסקנה שמשך הזמן שנדרש לביצוע המרות מהסוג הזה הוא בעל השפעה גדולה מספיק על הביצועים, וחשוב לתת למשתמשים את האפשרות להשתמש בהודעות protobuf.

תרחישים לדוגמה להודעות proto-plus ו-protobuf

תרחישים לדוגמה מסוג Proto Plus Messages
Proto-plus מציע כמה שיפורים ארגונומיים בהשוואה להודעות protobuf, ולכן הן אידיאליות לכתיבת קוד קריא וקריא. מכיוון שהם חושפים אובייקטים מקוריים של Python, קל יותר להשתמש בהם ולהבין אותם.
תרחישים לדוגמה בהודעת Protobuf
השתמשו ב-protobuf לתרחישים לדוגמה שרגישים לביצועים, במיוחד באפליקציות שצריכים לעבד דוחות גדולים במהירות או שיוצרות בקשות לשינוי עם מספר גדול של פעולות, למשל באמצעות BatchJobService או OfflineUserDataJobService.

שינוי דינמי של סוגי הודעות

אחרי שתבחרו את סוג ההודעה המתאים לאפליקציה, יכול להיות שתגלו שאתם צריכים להשתמש בסוג השני בתהליך עבודה ספציפי. במקרה הזה, קל לעבור בין שני הסוגים בצורה דינמית באמצעות כלים שמוצעים על ידי ספריית הלקוח. באמצעות אותה סיווג הודעות (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

ממשק הפרוטו פלוס מתועד, אבל כאן נדגיש כמה הבדלים עיקריים שמשפיעים על תרחישים נפוצים של שימוש בספריית הלקוח של 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)

טיפוסים בני מנייה (enums)

ערכים שנחשפים על ידי הודעות פרוטו פלוס הם מופעים של סוג enum המקורי של Python ולכן יורשים כמה שיטות נוחות.

אחזור סוג הטיפוס בן המנייה (enum)

כשמשתמשים בשיטה GoogleAdsClient.get_type כדי לאחזר טיפוסים בני מנייה (enums), ההודעות שמוחזרות משתנות מעט בהתאם לאופן שבו משתמשים בהודעות פרוטו פלוס או פרוטובוף. למשל:

הודעות מסוג Proto Plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
הודעות Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

כדי להקל על אחזור מספרי טיפוסים בני מנייה (enum), יש מאפיין נוחות במכונות של GoogleAdsClient עם ממשק עקבי, בלי קשר לסוג ההודעה שבו משתמשים:

val = client.enums.CampaignStatusEnum.PAUSED

אחזור ערך של טיפוסים בני מנייה (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)

לפעמים כדאי לדעת את השם של שדה 'טיפוסים בני מנייה (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

תוכן ההודעה

גם בהודעות פרוטו פלוס וגם בהודעות protobuf, מומלץ להשתמש בשיטת העזרה copy_from ב-GoogleAdsClient:

client.copy_from(campaign, other_campaign)

השדות של ההודעה ריקים

התהליך של הגדרת שדות ריקים של הודעות הוא זהה, בלי קשר לסוג ההודעה שבו אתם משתמשים. צריך רק להעתיק הודעה ריקה לשדה הרלוונטי. עיינו בקטע תוכן הודעה וגם במדריך Empty Message Fields (שדות הודעה ריקים). דוגמה להגדרה של שדה הודעה ריק:

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

שמות שדות שהם מילים שמורות

כשמשתמשים בהודעות פרוטו פלוס, שמות השדות מופיעים באופן אוטומטי עם קו תחתון בסוף במקרה שהשם הוא גם מילה שמורה ב-Python. דוגמה לעבודה עם מופע של Asset:

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

הרשימה המלאה של השמות השמורים נוצרת במודול gapic. אפשר לגשת אליו גם באופן פרוגרמטי.

קודם כול, מתקינים את המודול:

python -m pip install gapic-generator

לאחר מכן, ב-REPL או בסקריפט של 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")

לממשק המחלקה Message יש שיטה HasField שקובעת אם השדה בהודעה הוגדר, גם אם הוא הוגדר לערך ברירת מחדל.

שיטות הודעת Protobuf

ממשק ההודעות של protobuf כולל כמה שיטות נוחות שאינן חלק מממשק proto-plus. עם זאת, אפשר לגשת אליהן בקלות באמצעות המרת הודעת פרוטו פלוס ל-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 של הספרייה, דווחו על בעיה במכשיר המעקב שלנו.