رسائل Protobuf

باستخدام مَعلمة الضبط use_proto_plus، يمكنك تحديد ما إذا كنت تريد أن تعرض المكتبة رسائل proto-plus أو رسائل protobuf. للحصول على تفاصيل حول كيفية ضبط هذه المَعلمة، اطّلِع على مستندات الإعداد.

يوضّح هذا القسم الآثار المترتبة على الأداء عند اختيار أنواع الرسائل التي سيتم استخدامها، لذا ننصحك بقراءة الخيارات وفهمها لاتخاذ قرار مدروس.

الفرق بين رسائل Proto-plus ورسائل Protobuf

تدمج سلسلة معالجة مولّد الرموز proto-plus كطريقة لتحسين سهولة استخدام واجهة رسائل البروتوكول من خلال جعلها تتصرف بشكل مشابه لكائنات 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
تقدّم Proto-plus عددًا من التحسينات المريحة مقارنةً برسائل البروتوكول المخزَّن مؤقتًا، لذا فهي مثالية لكتابة رموز برمجية قابلة للصيانة وسهلة القراءة. وبما أنّها تعرض عناصر 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

تم توثيق واجهة proto-plus بالتفصيل، ولكن سنوضّح هنا بعض الاختلافات الرئيسية التي تؤثر في حالات الاستخدام الشائعة لمكتبة برامج "إعلانات Google" للعملاء.

تسلسل وحدات البايت

رسائل 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)

عمليات التعداد

إنّ التعدادات التي تعرضها رسائل proto-plus هي مثيلات من نوع enum الأصلي في Python، وبالتالي تتضمّن عددًا من طرق الاستخدام السهل.

استرداد نوع التعداد

عند استخدام طريقة GoogleAdsClient.get_type لاسترداد التعدادات، تختلف الرسائل التي يتم عرضها قليلاً حسب ما إذا كنت تستخدم رسائل proto-plus أو رسائل protobuf. على سبيل المثال:

رسائل Proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
رسائل Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

لتسهيل استرداد التعدادات، يتوفّر سمة ملائمة في مثيلات GoogleAdsClient تتضمّن واجهة متسقة بغض النظر عن نوع الرسالة المستخدَمة:

val = client.enums.CampaignStatusEnum.PAUSED

استرداد قيمة التعداد

في بعض الأحيان، يكون من المفيد معرفة قيمة أو رقم تعريف حقل تعداد معيّن، على سبيل المثال، 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))

استرداد اسم التعداد

في بعض الأحيان، يكون من المفيد معرفة اسم حقل تعداد. على سبيل المثال، عند قراءة عناصر من واجهة برمجة التطبيقات، قد تحتاج إلى معرفة حالة الحملة التي يتوافق معها العدد الصحيح 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. ويمكن الوصول إليه آليًا أيضًا.

أولاً، ثبِّت الوحدة:

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 protobuf على طريقة HasField تحدّد ما إذا تم ضبط الحقل في رسالة، حتى إذا تم ضبطه على قيمة تلقائية.

طُرق رسائل Protobuf

تتضمّن واجهة رسائل protobuf بعض الطرق المريحة التي لا تشكّل جزءًا من واجهة proto-plus، ولكن يسهل الوصول إليها من خلال تحويل رسالة 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())

أداة تتبّع المشاكل

إذا كانت لديك أي أسئلة حول هذه التغييرات أو أي مشاكل في نقل البيانات إلى أحدث إصدار من المكتبة، يمكنك تسجيل مشكلة في أداة تتبُّع المشاكل.