اگر امروز با مجموعهدادههای حجیم روی سختافزارهای معمولی کار میکنید، احتمالاً با خطای Out-of-Memory دستوپنجه نرم کردهاید. اما با انتشار نسخه ۲.۰ کتابخانه Polars، این محدودیت با یک تغییر ساده در پیشفرضهای سیستم بهشدت کمرنگ شده است.
طبق اعلام تیم توسعه در وبسایت pola.rs، در نسخه Polars 2.0، موتور استریمینگ (Streaming Engine) بهطور پیشفرض برای تمام پرسوجوهای LazyFrame فعال است. این تغییر باعث میشود سرعت اجرا برای کاربر متوسط تا ۵ برابر افزایش یابد. توسعهدهندگان این نسخه را یک «تجربه خستهکننده» توصیف کردهاند؛ به این معنا که بهجای اضافه کردن ویژگیهای پرزرقوبرق، تمرکز روی حذف تصمیمات طراحی قدیمی که پیش از این مانع پیشرفت بودند و بهینهسازی تنظیمات برای طیف وسیعتری از کاربران بوده است.
برای سالها، مهندسان داده مجبور بودند بین سرعت پردازش در حافظه و ریسک کرش کردن سیستم هنگام مواجهه با دادههای حجیم موازنه کنند. Polars پیش از این موتور استریمینگ — که شبیه به یک نوار نقاله است و دادهها را تکهتکه پردازش میکند تا کل آنها یکباره در رم جای نگیرد — را ارائه داده بود، اما فعالسازی آن دستی بود. اکنون با پیشفرض شدن این قابلیت، سد ورود برای پردازش دادههای عظیم روی سختافزارهای متوسط شکسته شده است.
همانطور که در تحلیلهای قبلی ما درباره بهینهسازی زیرساختهای داده اشاره کردیم، جابهجایی پردازش از حالت تمامحافظه به حالت جریانی، کلید مقیاسپذیری در سیستمهای مدرن است. این رویکرد بهینهسازی عملکرد در ابزارهای تحلیل داده جدید رایج شده است؛ برای مثال، DuckDB نیز در نسخه ۲.۰ خود با تمرکز بر بهینهسازی موتور پرسوجو توانست سرعت اجرای عملیاتهای پیچیده را بهطور چشمگیری افزایش دهد.
چرخش به سمت استریمینگ
اکنون با فراخوانی متد .collect() روی یک LazyFrame، موتور استریمینگ بهطور خودکار فعال میشود. این تغییر بهبودهای چشمگیری در مصرف حافظه و عملکرد ایجاد میکند. با این حال، یک هزینه فنی وجود دارد: موتور استریمینگ برای عملیاتی مثل Join، group_by و unpivot ترتیب ردیفها را بهطور پیشفرض تضمین نمیکند.
کاربرانی که به ترتیب ردیفها نیاز دارند، باید صراحتاً maintain_order=True را تنظیم کنند. همچنین برای کسانی که رفتار قدیمی را ترجیح میدهند، امکان بازگشت به موتور در-حافظه (In-memory) از طریق تنظیمات pl.Config.set_engine_affinity("in-memory") در سطح کل فرآیند یا در سطح هر پرسوجو با استفاده از .collect(engine="in-memory") فراهم است.
چرا نسخه ۲.۰؟
تصمیم برای جهش به نسخه ۲.۰ به دلیل نیاز به شکستن سازگاری با نسخههای قبلی (Backward Compatibility) برای بهبود تجربه هسته سیستم بود. از آنجآی که موتور استریمینگ رفتار ترتیب ردیفها را در عملیاتهای حیاتی تغییر میدهد، یک بهروزرسانی نسخهی اصلی برای هشدار به کاربران ضروری بود تا متوجه شوند ترتیب خروجی آنها ممکن است تغییر کند.
تیم Polars برای تسهیل این انتقال و کمک به کاربران برای جابهجایی خط لولههای موجود به نسخه جدید بدون مواجهه با شکستهای غیرمنتظره، یک راهنمای جامع مهاجرت منتشر کرده است.
اعتبارسنجی سختگیرانهتر دادهها
نسخه ۲.۰ فلسفه «شکست سریع» (Fail Fast) را دنبال میکند تا باگها در خط لولههای (Pipelines) طولانی پنهان نمانند. هدف این است که خطاها در همان ابتدای مسیر ظاهر شوند، نه پس از ۲۰ دقیقه پردازش. در این نسخه، رفتارهای ضمنی در مواجهه با عدم تطابق دادهها، دیگر پیشفرض نیستند و باید بهصورت دستی فعال شوند، زیرا این عدم تطابقها اغلب باگهای بحرانی را پنهان میکنند.
این موضوع برای توسعههای مبتنی بر عامل (Agent) بسیار حیاتی است. عاملها اکنون میتوانند از collect_schema() برای تحلیل انواع داده و اعتبارسنجی ساختار پرسوجو استفاده کنند. این قابلیت اجازه میدهد تا عدم تطابقها در سطح اسکیما بدون نیاز به متریالیزه کردن (Materializing) یا پردازش واقعی دادهها شناسایی شوند و سرعت تکرار (Iteration) از طریق بازخوردهای فوری افزایش یابد.
برخی از بهبودهای سختگیرانه عبارتند از:
- تبدیل نوع بدون اتلاف: عبارت
is_inدیگر بهطور ضمنی انواع مختلف داده را به یک نوع مشترک (Supertype) تبدیل نمیکند. پیش از این، اگر کاربر یک Int64 را با لیستی از Float64 چک میکرد، Polars مقدار Int64 را به Float64 تبدیل میکرد. از آنجآ که Float64 نمیتواند اعداد صحیح بالای ۲ به توان ۵۳ (۹۰۰۷۱۹۹۲۵۴۷۴۰۹۹۲) را بهطور دقیق نمایش دهد، مقداری مثل ۹۰۰۷۱۹۹۲۵۴۷۴۰۹۹۳ بهطور ضمنی به ۹۰۰۷۱۹۹۲۵۴۷۴۰۹۹۲.۰ گرد میشد و یک مثبت کاذب (False Positive) ایجاد میکرد. اکنون این مورد خطایInvalidOperationErrorمیدهد و کاربر باید برای مدیریت تبدیلهای اتلافی، صراحتاً از Cast استفاده کند. - اتصال سختگیرانه: در اتصال افقی (Horizontal Concatenation)، طول دادهها بررسی میشود. پیش از این، اگر یک دیتافریم ۵ ردیفه با یک دیتافریم ۴ ردیفه ترکیب میشد، Polars بهطور ضمنی ردیف گمشده را با مقدار Null پر میکرد. برای مثال، ترکیب تعداد تراکنشهای روزانه با تعداد پرچمهای تقلب روزانه در حالی که یکی از جابها شکست خورده بود، منجر به یک Null خاموش میشد. اکنون در حالت strict، خطای
ShapeErrorصادر میشود. اگر کاربر قصد دارد از Padding استفاده کند، باید صراحتاً ازhow="horizontal_extend"استفاده کند. - متدهای پارسینگ اختصاصی: تبدیلهای مبهم حذف شدهاند تا تنها یک راه واضح برای پارس کردن دادهها وجود داشته باشد. کاربران دیگر نمیتوانند رشتهها را مستقیماً با استفاده از
.cast(pl.Date)به تاریخ تبدیل کنند؛ این کار اکنون خطایInvalidOperationErrorایجاد میکند. آنها باید از.str.to_date()یا.str.to_datetime()استفاده کنند که اجازه تعیین فرمتهای خاص پارسینگ و کنترل بیشتر را میدهد. - مدیریت Enum و Categorical: تبدیل
UInt32بهpl.Enumاز طریق.cast()دیگر پشتیبانی نمیشود و منجر بهComputeErrorمیگردد. کاربران باید برای تبدیل عدد به دستهبندی از.cat.to(dtype)و برای تبدیل دستهبندی به عدد از.cat.physical()استفاده کنند.
پاکسازی API و مدیریت خطا
برای تسهیل انتقال، دو استثنای تایپشده جدید یعنی polars.exceptions.AttributeRemovedError و polars.exceptions.ArgumentRemovedError معرفی شدهاند. این خطاها مستقیماً متدها و پارامترهای حذفشده را هدف قرار میدهند و اشارهگرهای مستقیمی به API جدید ارائه میدهند تا به کاربران و عاملهای هوش مصنوعی در ادامه کارشان کمک کنند.
برای مثال، متد melt جای خود را به unpivot داده است. اگر کاربر متد melt را فراخوانی کند، سیستم خطای AttributeRemovedError برمیگرداند و توضیح میدهد که باید از LazyFrame.unpivot استفاده شود، در حالی که index جایگزین id_vars و on جایگزین value_vars شده است. به همین ترتیب، آرگومان join_nulls در DataFrame.join — که در نسخه ۱.۲۴ منسوخ شده بود — در نسخه ۲.۰ حذف و به nulls_equal تغییر نام یافته است. استفاده از پارامتر قدیمی اکنون خطای ArgumentRemovedError ایجاد میکند.
مسیر پیشرو در سری ۲.x
با وجود اینکه نسخه ۲.۰ روی پایداری و پیشفرضها تمرکز دارد، اما توسعهدهندگان سیگنالهایی از تغییرات زیرساختی بزرگ دادهاند. Polars ویژگیهای جدید را پشت نسخههای اصلی محدود نمیکند و آنها را به محض آماده شدن عرضه میکند.
در چرخه ۲.x موارد زیر در راه است:
- بهبود موتور اصلی: پشتیبانی مناسب از Out-of-core برای موتور استریمینگ و یک برنامهریز جدید مبتنی بر هزینه (Cost-based Planner) با قابلیت بازآرایی Joinها.
- اتصالات و IO: طراحی جدید پلاگینهای IO و آنچه تیم معتقد است سریعترین خواننده S3 موجود خواهد بود.
- زبان و Async: بهبودهای گسترده در پوشش SQL و حذف
mmapکه باعث میشود خط لولهها از ابتدا تا انتها بهطور کامل ناهمگام (Asynchronous) شوند.
این حرکت به سمت سختگیرانهتر شدن و پیشفرضهای استریمینگ به این معناست که توسعهدهندگان دیگر نمیتوانند روی تبدیلهای ضمنی دادهها حساب کنند تا «بهسادگی کار کنند». اگرچه این تغییر ممکن است برخی خط لولههای قدیمی را مختل کند، اما تضمین میکند که سیستمهای تولیدی پیشبینیپذیرتر و بهمراتب سریعتر باشند.
کاربران میتوانند هماکنون با دستور pip install polars==2.0rc1 این تغییرات را آزمایش کنند. بازخوردهای کاربران از طریق Issues گیتهاب (https://github.com/pola-rs/polars/issues) و سرور دیسکورد Polars (https://discord.gg/4UfP5cfBE7) جمعآوری میشود.
گام بعدی شما
- اگر از Polars در محیط تولید استفاده میکنید، نسخه RC را روی دادههای تست اجرا کنید تا اثر تغییر ترتیب ردیفها در Joinها را بسنجید.
- متدهای
.cast()قدیمی را در کد خود شناسایی کرده و آنها را به متدهای اختصاصی.strیا.catمنتقل کنید. - در صورت مواجهه با خطاهای جدید، از مستندات مهاجرت نسخه ۲.۰ برای جایگزینی متدهای حذفشده استفاده کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما درباره بهینهسازیهای حافظه در پردازش دادههای حجیم مراجعه کنید.




گفتگو