مقدمه ای بر برنامه نویسی تابعی
Earth Engine از یک سیستم پردازش موازی برای انجام محاسبات در تعداد زیادی ماشین استفاده می کند. برای فعال کردن چنین پردازشی، Earth Engine از تکنیکهای استانداردی که معمولاً توسط زبانهای کاربردی استفاده میشود، مانند شفافیت ارجاعی و ارزیابی تنبل، برای بهینهسازی و بهرهوری قابل توجه استفاده میکند.
مفهوم اصلی که برنامه نویسی کاربردی را از برنامه نویسی رویه ای جدا می کند ، عدم وجود عوارض جانبی است. معنی آن این است که توابعی که می نویسید به داده هایی که خارج از تابع هستند تکیه یا به روز نمی کنند. همانطور که در مثال های زیر مشاهده خواهید کرد، می توان مشکل خود را مجدداً ساختار داد تا با استفاده از توابع بدون عوارض جانبی حل شود - که برای اجرای موازی بسیار مناسب تر هستند.
برای حلقه ها
استفاده از حلقههای for-loop در Earth Engine ممنوع است. نتایج مشابهی را می توان با استفاده از یک عملیات map()
به دست آورد که در آن تابعی را مشخص می کنید که می تواند به طور مستقل برای هر عنصر اعمال شود. این به سیستم اجازه می دهد تا پردازش را در ماشین های مختلف توزیع کند.
مثال زیر نشان می دهد که چگونه می توانید لیستی از اعداد را تهیه کنید و با استفاده از map()
لیست دیگری با مربع های هر عدد ایجاد کنید: ویرایشگر کد (جاوا اسکریپت)
// This generates a list of numbers from 1 to 10.
var myList = ee.List.sequence(1, 10);
// The map() operation takes a function that works on each element independently
// and returns a value. You define a function that can be applied to the input.
var computeSquares = function(number) {
// We define the operation using the EE API.
return ee.Number(number).pow(2);
};
// Apply your function to each item in the list by using the map() function.
var squares = myList.map(computeSquares);
print(squares); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
شرایط اگر/دیگر
یکی دیگر از مشکلات رایج کاربران جدیدی که به الگوی برنامهنویسی رویهای عادت کردهاند، استفاده صحیح از عملگرهای شرطی if/else در Earth Engine است. در حالی که API یک الگوریتم ee.Algorithms.If()
را ارائه می دهد، استفاده از آن به نفع رویکرد کاربردی تر با استفاده از map()
و فیلترها به شدت منع می شود. Earth Engine از اجرای معوق استفاده می کند، به این معنی که ارزیابی یک عبارت تا زمانی که مقدار واقعی آن مورد نیاز باشد به تأخیر می افتد. در برخی موارد، این نوع از مدل اجرا، هر دو گزینه درست و نادرست یک عبارت ee.Algorithms.If()
را ارزیابی می کند. این می تواند منجر به محاسبات اضافی و استفاده از حافظه شود، بسته به عبارات و منابع مورد نیاز برای اجرای آنها.
فرض کنید می خواهید یک نوع مثال بالا را حل کنید، که در آن وظیفه محاسبه مربع های تنها اعداد فرد است. یک رویکرد کاربردی برای حل این موضوع بدون شرایط if/else، در زیر نشان داده شده است:
ویرایشگر کد (جاوا اسکریپت)
// The following function determines if a number is even or odd. The mod(2) // function returns 0 if the number is even and 1 if it is odd (the remainder // after dividing by 2). The input is multiplied by this remainder so even // numbers get set to 0 and odd numbers are left unchanged. var getOddNumbers = function(number) { number = ee.Number(number); // Cast the input to a Number so we can use mod. var remainder = number.mod(2); return number.multiply(remainder); }; var newList = myList.map(getOddNumbers); // Remove the 0 values. var oddNumbers = newList.removeAll([0]); var squares = oddNumbers.map(computeSquares); print(squares); // [1, 9, 25, 49, 81]
این پارادایم به ویژه هنگام کار با مجموعه ها کاربرد دارد. اگر میخواهید الگوریتم متفاوتی را بر اساس برخی شرایط به مجموعه اعمال کنید، روش ترجیحی این است که ابتدا مجموعه را بر اساس شرط فیلتر کنید و سپس یک تابع متفاوت را به هر یک از زیرمجموعهها map()
. این به سیستم اجازه می دهد تا عملیات را موازی کند. به عنوان مثال: ویرایشگر کد (جاوا اسکریپت)
// Import Landsat 8 TOA collection and filter to 2018 images.
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
.filterDate('2018-01-01', '2019-01-01');
// Divide the collection into 2 subsets and apply a different algorithm on them.
var subset1 = collection.filter(ee.Filter.lt('SUN_ELEVATION', 40));
var subset2 = collection.filter(ee.Filter.gte('SUN_ELEVATION', 40));
// Multiply all images in subset1 collection by 2;
// do nothing to subset2 collection.
var processed1 = subset1.map(function(image) {
return image.multiply(2);
});
var processed2 = subset2;
// Merge the collections to get a single collection.
var final = processed1.merge(processed2);
print('Original collection size', collection.size());
print('Processed collection size', final.size());
تکرار تجمعی
ممکن است لازم باشد عملیات متوالی را انجام دهید، جایی که نتیجه هر تکرار توسط تکرار بعدی استفاده می شود. Earth Engine یک متد iterate()
برای چنین وظایفی ارائه می کند. به یاد داشته باشید که iterate()
به صورت متوالی اجرا می شود و بنابراین برای عملیات بزرگ کند خواهد بود. فقط زمانی از آن استفاده کنید که قادر به استفاده از map()
و فیلترها برای رسیدن به خروجی دلخواه نباشید.
یک نمایش خوب از iterate()
برای ایجاد دنباله اعداد فیبوناچی است. در اینجا، هر عدد در سری، مجموع 2 عدد قبلی است. تابع iterate()
2 آرگومان، یک تابع (الگوریتم) و یک مقدار شروع می گیرد. خود تابع به 2 مقدار منتقل می شود، مقدار فعلی در تکرار و نتیجه تکرار قبلی. مثال زیر نحوه پیاده سازی یک دنباله فیبوناچی در Earth Engine را نشان می دهد.
ویرایشگر کد (جاوا اسکریپت)
var algorithm = function(current, previous) { previous = ee.List(previous); var n1 = ee.Number(previous.get(-1)); var n2 = ee.Number(previous.get(-2)); return previous.add(n1.add(n2)); }; // Compute 10 iterations. var numIteration = ee.List.repeat(1, 10); var start = [0, 1]; var sequence = numIteration.iterate(algorithm, start); print(sequence); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
اکنون که درک خوبی از مفاهیم جاوا اسکریپت دارید، می توانید آموزش API را برای مقدمه ای بر عملکرد جغرافیایی Earth Engine API مشاهده کنید.