العميل مقابل الخادم

تُحوِّل مكتبات عملاء Earth Engine لبرمجيتَي Python و JavaScript التحليلات الجغرافية المكانية المعقدة إلى طلبات Earth Engine. قد يحتوي الرمز البرمجي الذي تكتبه لأجل مكتبة العميل على مزيج من الإشارات إلى الكائنات والمتغيّرات من جهة العميل التي تمثّل الكائنات من جهة الخادم.

من المهم التمييز بين عناصر Earth Engine وعناصر Python أو JavaScript أو العناصر الأساسية الأخرى التي قد تكون في الرمز البرمجي. يمكنك التلاعب بالعناصر على الخادم من خلال التلاعب بعناصر "الوكيل" من جهة العميل في النص البرمجي. يمكنك التعرّف على وكيل على أنّه أي شيء يبدأ بـ ee. لا تحتوي عناصر الوكيل هذه في Earth Engine على أي بيانات فعلية، بل هي مجرد أسماء معرِّفة للعناصر على الخادم. للبدء، ننصحك بالاطّلاع على العنصر "سلسلة" من جهة العميل (الذي ليس عنصرًا وكيلاً):

محرِّر الرموز البرمجية (JavaScript)

var clientString = 'I am a String';
print(typeof clientString);  // string

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

client_string = 'I am a String'
print(type(client_string))  # str

لاحظ من الإخراج أنّ العميل (متصفّح الويب أو دفتر الملاحظات) قد فسّر هذا الرمز ونفّذه، وحدّد أنّ المتغيّر هو من النوع string. لنفترض الآن أنّك تريد أن يتمكّن Earth Engine من تنفيذ إجراء باستخدام هذه السلسلة. لإجراء ذلك، عليك لفّ السلسلة في حاوية مناسبة وإرسالها إلى Google. هذه الحاوية هي العنصر الوكيل. وفي ما يلي مثال لذلك:

محرِّر الرموز البرمجية (JavaScript)

var serverString = ee.String('I am not a String!');
print(typeof serverString);  // object
print('Is this an EE object?',
    serverString instanceof ee.ComputedObject);  // true

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

server_string = ee.String('I am not a String!')
print(type(server_string))  # ee.ee_string.String
print(
    'Is this an EE object?', isinstance(server_string, ee.ee_string.String)
)  # True

يُرجى ملاحظة أنّ ee.String هو object، وليس string، وذلك من خلال الاطّلاع على الإخراج. وبشكل أكثر تحديدًا، هو ee.computedObject، ما يعني أنّه عنصر وكيل لشيء ما على الخادم. يمكنك اعتبار ee.Thing طريقة لوضع عنصر في حاوية لإرساله إلى Google. لا يعرف العميل ما هو موجود في الحاوية، ولكن يمكنك معرفة ما هو موجود فيها من خلال طباعتها:

محرِّر الرموز البرمجية (JavaScript)

print(serverString);  // I am not a String

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

print(server_string.getInfo())  # I am not a String

للاطّلاع على شكل الحاوية نفسها، اطبع تمثيل السلسلة للعنصر التالي:

محرِّر الرموز البرمجية (JavaScript)

print(serverString.toString());  // ee.String("I am not a String!")

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

print(server_string)  # ee.String({"constantValue": "I am not a String!"})

إذا كنت بحاجة لأي سبب إلى استخدام Python أو JavaScript في العميل للتلاعب بما في الحاوية، استخدِم getInfo() للحصول على محتوى الحاوية وتخصيصه لمتغيّر:

محرِّر الرموز البرمجية (JavaScript)

var someString = serverString.getInfo();
var strings = someString + '  Am I?';
print(strings);  // I am not a String!  Am I?

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

some_string = server_string.getInfo()
strings = some_string + '  Am I?'
print(strings)  # I am not a String!  Am I?

تكرار

وبما أنّ العميل لا يعرف ما هو موجود في عناصر ee.Thing من جهة الخادم، لا تعمل العمليات من جهة العميل، مثل الشروط والدوالّ الحلقية، معها. لهذا السبب، ولتجنُّب إجراء مكالمات متزامنة إلى getInfo()، استخدِم دوالّ الخادم إلى أقصى حدّ ممكن. على سبيل المثال، إليك الطريقتان التاليتان ل إنشاء قائمة:

إجراء غير مقترَح: حلقة for من جهة العميل

محرِّر الرموز البرمجية (JavaScript)

var clientList = [];
for(var i = 0; i < 8; i++) {
  clientList.push(i + 1);
}
print(clientList);

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

client_list = []
for i in range(8):
  client_list.append(i + 1)
print(client_list)

إجراء مقترَح: الربط من جهة الخادم

محرِّر الرموز البرمجية (JavaScript)

var serverList = ee.List.sequence(0, 7);
serverList = serverList.map(function(n) {
  return ee.Number(n).add(1);
});
print(serverList);

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

server_list = ee.List.sequence(0, 7)
server_list = server_list.map(lambda n: ee.Number(n).add(1))
print(server_list.getInfo())

مثال التعيين من جهة الخادم مضحك بعض الشيء لأنّه يمكنك إنشاء القائمة نفسها باستخدام ee.List.sequence(1, 8) ببساطة، ولكنه يوضّح بعض المفاهيم المهمة. المفهوم الأول هو map() الذي يطبّق ببساطة الدالة نفسها على كل العناصر في القائمة. وبما أنّ هذه الدالة يتم تنفيذها على الخادم، لن تعمل الدوالّ من جهة العميل، مثل getInfo() وprint()، في دالة تم ربطها. لهذا السبب، يجب استبدال الرمز i + 1 بالرمز المكافئ من جهة الخادم: ee.Number(n).add(1). من المهمّ معرفة أنّ n هو عنصر لا يظهر إلّا على الخادم. ولأنّ الدالة لا تعرف نوع وسيطتها، يجب تحويلها إلى ee.Number.

(اطّلِع على القسم الخاص بدوالّ العميل والخادم للحصول على وصف للدوالّ التي يتم تنفيذها على العميل).

تجدر الإشارة أيضًا إلى أنّ الوظائف من جهة العميل تكون ملائمة في بعض الأحيان. على سبيل المثال، يمكن استخدام حلقة for السابقة لإنشاء قائمة وتغليفها بأحد عناصر برمجة التطبيقات من جهة الخادم:

محرِّر الرموز البرمجية (JavaScript)

var toServerList = ee.List(clientList);

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

to_server_list = ee.List(client_list)

يُرجى العِلم أنّ المعالجة من جهة العميل تتم في دفتر ملاحظاتك أو المتصفّح، أي في وحدة المعالجة المركزية للجهاز المضيف، لذا قد تكون أقل فعالية من استخدام Earth Engine لتنفيذ العمل على الخادم. بالإضافة إلى ذلك، لتجنُّب النتائج غير المتوقّعة، من الممارسات الجيدة تجنُّب خلط وظائف العميل والخادم في النصوص البرمجية. يقدّم قسم الشروط مثالاً على العواقب غير المقصودة المحتملة.

الشروط

لا تعمل العناصر من جهة الخادم بالضرورة مع الوظائف من جهة العميل والعكس صحيح. على سبيل المثال، لنفترض أنّ لدينا متغيّرًا منطقيًا على خادم:

محرِّر الرموز البرمجية (JavaScript)

var myList = ee.List([1, 2, 3]);
var serverBoolean = myList.contains(5);
print(serverBoolean);  // false

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

my_list = ee.List([1, 2, 3])
server_boolean = my_list.contains(5)
print(server_boolean.getInfo())  # False

كما هو موضّح في المثال التالي، لا يتصرّف المتغيّر في شرط من جهة العميل لأنّه عنصر من جهة الخادم. للتحقّق بشكل صحيح من قيمة منطقية من جهة الخادم، استخدِم دالة من جهة الخادم:

غير مقترَح: الشروط على مستوى العميل

محرِّر الرموز البرمجية (JavaScript)

var clientConditional;
if (serverBoolean) {
  clientConditional = true;
} else {
  clientConditional = false;
}
print('Should be false:', clientConditional);  // True!

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

if server_boolean:
  client_conditional = True
else:
  client_conditional = False
print('Should be False:', client_conditional)  # True!

إجراء مقترَح: شرط من جهة الخادم

محرِّر الرموز البرمجية (JavaScript)

var serverConditional = ee.Algorithms.If(serverBoolean, 'True!', 'False!');
print('Should be false:', serverConditional);  // False!

إعداد لغة Python

اطّلِع على صفحة بيئة Python للحصول على معلومات عن واجهة برمجة التطبيقات Python API واستخدام IDE geemap لتطوير التطبيقات التفاعلي.

import ee
import geemap.core as geemap

Colab (Python)

server_conditional = ee.Algorithms.If(server_boolean, 'True!', 'False!')
print('Should be False:', server_conditional.getInfo())  # False!

وظائف العميل والخادم

توضّح الأقسام السابقة عدة أسباب لعدم كفاءة أو منطقية خلط عناصر ووظائف العميل والخادم. ما هي العناصر والدوالّ التي تعمل من جهة العميل وما هي العناصر والدوالّ التي تعمل من جهة الخادم؟ بشكل عام، أيّ عنصر تمّت إعداده على أنّه ee.Thing هو عنصر خادم وأيّ طريقة في هذا العنصر، ee.Thing.method()، هي دالة خادم. إنّ الكائنات والدوالّ التي تظهر في مرجع Python أو JavaScript تكون من جهة العميل. كما ذكرنا سابقًا، يمكنك استخدام وظائف من جهة العميل لإنشاء عنصر، ثم تغليفه من خلال تقديم العنصر من جهة العميل إلى دالة انشائية في Earth Engine، مثل ee.String().