<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>نوشته های ابوالفضل وکیلی</title><link>https://virgool.ir/feed/@vakily</link><description>instagram : @a_vakily7</description><language>fa</language><pubDate>2026-11-11 12:51:35</pubDate><image><url>https://files.virgool.ir/upload/users/56596/avatar/L2GV6I.jpg</url><title>ابوالفضل وکیلی</title><link>https://virgool.ir/@vakily</link></image><item><title>چرا برای حل مشکلات بزرگ به مغزهای پیچیده نیاز نداریم؟</title><link>https://virgool.ir/@vakily/چرا-برای-حل-مشکلات-بزرگ-به-مغزهای-پیچیده-نیاز-نداریم-b1j0aepxjhei</link><description>ما در عصری زندگی می‌کنیم که پیچیدگی را با هوش و سادگی را با ناآگاهی اشتباه می‌گیریم. وقتی با بحرانی مانند نرخ بالای مرگ‌ومیر در بیمارستان‌ها یا شکست پروژه‌های بزرگ صنعتی روبرو می‌شویم، غریزه ما بلافاصله به دنبال راه‌حل‌های گران‌قیمت، فناوری‌های فوق‌پیشرفته و الگوریتم‌های هوش مصنوعی می‌رود. اما حقیقت تکان‌دهنده این است که بسیاری از شکست‌های ما نه از «کمبود دانش»، بلکه از «ناتوانی در اجرای اصول اولیه» ناشی می‌شوند. آنچه که می خواهم بگویم این است که در دنیای اشباع شده از اطلاعات، «سادگی منسجم» (مانند یک چک‌لیست) ابزاری به‌مراتب قدرتمندتر و نجات‌بخش‌تر از «پیچیدگی گسسته» است.دانش کافی نیست، انضباط لازم استبزرگترین خطای منطقی ما این است که تصور می‌کنیم اگر کسی «می‌داند»، حتماً «انجام می‌دهد». شواهد علمی در حوزه پزشکی نشان می‌دهد که حتی مجرب‌ترین جراحان جهان نیز مستعد خطاهای ابتدایی هستند. تنها با اجباری کردن یک چک‌لیست ۵ مرحله‌ای ساده برای شستن دست‌ها و استریل کردن محل تزریق در بیمارستان‌های میشیگان، نرخ عفونت 66٪ کاهش یافت و جان ۱۵۰۰ نفر نجات یافت. (کتاب قدرت شروع ناقص)این نشان می‌دهد که قدرت واقعی در «استانداردسازی دانسته‌ها» نهفته است، نه در انباشتِ بی‌پایان اطلاعات جدید.بهره‌وری در بازگشت به اصولسادگی به معنای تنبلی نیست، بلکه به معنای حذف نویز برای تمرکز بر سیگنال‌های حیاتی است. همانطور که چک‌لیست آتول گوانده ثابت می‌کند که صرفه‌جویی ۷۵ میلیون دلاری در هزینه‌ها، نه از طریق خرید دستگاه‌های جدید، بلکه با تغییر در «رفتار» حاصل شد. (کتاب قدرت شروع ناقص) در هر سیستمی (چه یک سازمان بزرگ و چه زندگی شخصی)، 80٪ نتایج حاصل انجام درست 20٪ از کارهای بنیادی است. (اصل پارتو) وقتی مراحل ساده را به یک پروتکل غیرقابل مذاکره تبدیل می‌کنیم، مغز را از درگیری با جزئیات بدیهی آزاد کرده و ظرفیت آن را برای حل چالش‌های واقعاً پیچیده ذخیره می‌کنیم.آیا سادگی، خلاقیت و تخصص را نمی‌کشد؟برخی از متخصصان اغلب فکر می‌کنند که تقلیل دادن شغل پیچیده‌ی آن‌ها به چند مرحله‌ی ساده در یک چک‌لیست، توهین به تخصص آن‌هاست و روح خلاقیت را از بین می‌برد. آن‌ها می‌ترسند که تبدیل به روبات‌هایی شوند که فقط تیک می‌زنند. اما این یک برداشت نادرست است. پاسخ منطقی این است که چک‌لیست برای جایگزینی تفکر نیست، بلکه برای «آزاد کردن تفکر» است. وقتی یک خلبان یا پزشک خیالی آسوده از بابت چک کردن پیچ و مهره‌های اولیه دارد، می‌تواند تمام توان ذهنی خود را صرف مدیریت بحران‌های غیرمنتظره کند.لذا می توان استدلال نمود که سادگی، بستری است که خلاقیت ایمن روی آن بنا می‌شود.نتیجه‌زمان آن رسیده است که علیه «پیچیدگی» شورش کنیم. موفقیت در میشیگان ثابت کرد که گاهی یک تکه‌کاغذ ارزان‌قیمت از یک اتاق فکر میلیارد دلاری کارآمدتر است. گاهی ما به ابزارهای جدیدتر نیاز نداریم، بلکه به اراده‌ای برای انجام درست همان چیزهایی نیاز داریم که از قبل می‌دانیم. از خود بپرسید در زندگی حرفه‌ای یا شخصی شما، کدام «چک‌لیست ساده» وجود دارد که به دلیل پیش‌پاافتاده بودن، نادیده‌اش می‌گیرید؟ آیا می‌خواهید در هزارتوی پیچیدگی غرق شوید یا با سلاح سادگی، نتایج خیره‌کننده خلق کنید؟ قضاوت و تصمیم با شماست.</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Sat, 03 Jan 2026 01:59:37 +0330</pubDate></item><item><title>ایده‌های اولیه خود را به وب‌سایت‌های زنده تبدیل کنید</title><link>https://virgool.ir/@vakily/ایده-های-اولیه-خود-را-به-وب-سایت-های-زنده-تبدیل-کنید-yyvh7m8maalk</link><description>با استفاده از پلتفرم YouWare می‌توانید ایده‌های اولیه خود را بدون کد نویسی و با کمک هوش مصنوعی با زبان طبیعی به وب‌سایت‌های واقعی و قابل اشتراک تبدیل کنید. افزون بر این، امکان مرور و استفاده از ایده‌ها و پروژه‌های دیگران نیز فراهم است تا الهام بیشتری برای خلاقیت داشته باشید.خاستگاه ایدهایده شکل‌گیری YouWare زمانی به ذهن لئون مینگ، بنیان‌گذار و مدیرعامل این پلتفرم، خطور کرد که در حال مرور شبکه اجتماعی X بود. او مشاهده کرد که برنامه‌نویسان تکه‌کدهای تولیدشده با هوش مصنوعی را به اشتراک می‌گذارند، اما ابزار ساده و مستقیمی برای تبدیل این کدها به پروژه‌های زنده و تعاملی وجود ندارد. همان شب، مینگ بی‌وقفه دست به کار شد و تا ساعت دو بامداد نسخه اولیه را آماده و منتشر کرد. در کمتر از ۴۸ ساعت، بازدید پلتفرم از یک‌هزار نفر به بیش از یک‌میلیون کاربر رسید و خالقان محتوا در سراسر جهان شروع به ساخت و اشتراک‌گذاری پروژه‌های خود کردند.مأموریت و چشم‌اندازمینگ درباره فلسفه شکل‌گیری این محصول می‌گوید:«ما YouWare را ساختیم زیرا خلاقیت باید در دسترس همگان باشد، نه فقط نخبگان فنی. هوش مصنوعی قرار است خلاقیت انسانی را تقویت کند، نه جایگزین آن شود. هدف ما این است که هر فردی بتواند ایده‌های خود را آزادانه بیان کرده و با جهان به اشتراک بگذارد.»قابلیت‌های کلیدیYouWare امکان می‌دهد تنها با یک کلیک، کد تولیدشده توسط ابزارهای مختلف از جمله ChatGPT و Claude به یک وب‌سایت زنده و قابل اشتراک تبدیل شود. این پلتفرم از قابلیت‌هایی نظیر تبدیل مستقیم پرامپت به وب‌سایت، بهبود خودکار طراحی داخلی و سایر امکانات تعاملی بهره می‌برد. نتیجه آن است که فرآیند کدنویسی بیش از هر زمان دیگری شهودی و سریع شده است.رشد و دستاوردهااز آغاز فعالیت تاکنون، YouWare در دو مرحله جذب سرمایه توانسته ده‌ها میلیون دلار سرمایه جلب کند و ارزش فعلی آن به حدود ۸۰ میلیون دلار رسیده است. تاکنون کاربران از سراسر جهان بیش از ۲۰۰ هزار پروژه در این پلتفرم ایجاد کرده‌اند.جمع‌بندیYouWare را می‌توان نخستین پلتفرم کدنویسی هوش مصنوعی دانست که با محوریت خالقان محتوا (Creators) طراحی شده است. این سرویس با ترکیب ابزارهای هوش مصنوعی شهودی، پیش‌نمایش بلادرنگ و اکوسیستم اجتماعی قابل بازآفرینی (remixable) به نسل تازه‌ای از خالقان قدرت می‌دهد تا ایده‌های خود را به پروژه‌های زنده و تعاملی بدل کنند.با افتخار از:https://www.prnewswire.com/news-releases/youware-launches-as-the-first-ai-coding-platform-for-creators-302466538.html</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Sun, 14 Sep 2025 00:16:54 +0330</pubDate></item><item><title>معرفی Elasticsearch 9</title><link>https://virgool.ir/@vakily/معرفی-elasticsearch-9-huvvz5a1cju8</link><description>بالاخره Elasticsearch 9.0 به نسخه پایدار (GA) رسید؛ نسخه‌ای که پر از قابلیت‌های تازه و قدرتمند است و مرزهای جستجو، رصدپذیری (observability) و تحلیل داده مبتنی بر هوش مصنوعی (AI-driven analytics) را جابه‌جا می‌کند. چه بخواهید اپلیکیشن‌های جستجوی معنایی (semantic search) بسازید، چه حجم عظیمی از داده‌ها را مدیریت کنید، یا عملکرد مدل‌های زبانی بزرگ (LLM) را زیر نظر بگیرید، این نسخه مجموعه‌ای از نوآوری‌ها را ارائه می‌دهد که برای پاسخ‌گویی به چالش‌های روز دنیای داده طراحی شده‌اند.در ادامه، مهم‌ترین تغییرات و قابلیت‌های نسخه ۹.۰ از نگاه ما را مرور می‌کنیم.۱. Better Binary Quantization (BBQ) – حالا به‌صورت پایدار است.یکی از ستاره‌های این نسخه، انتشار پایدار فناوری اختصاصی Better Binary Quantization (به اختصار BBQ) است؛ تکنیکی ویژه‌ی فشرده‌سازی بردار که برای جستجوی معنایی فوق‌سریع ساخته شده است.دستاوردهای BBQ:تا ۵ برابر سرعت بیشتر در اجرای پرس‌وجو۳.۹ برابر توان عملیاتی بیشتر در تمام سطوح Recallبدون کاهش دقتبرخلاف روش‌های سنتی، BBQ با یک پیش‌بینی‌گر سبک (lightweight predictor vector) کل ایندکس را اسکن می‌کند، نتایج بالقوه را بیش‌نمونه‌برداری کرده (oversample) و سپس با بردار بزرگ‌تر دوباره رتبه‌بندی می‌کند و همه‌ی این‌ها با یک API ساده انجام می شود. حالا توسعه‌دهندگان می‌توانند نرخ oversampling را تنظیم کنند و باقی کار را به Elasticsearch بسپارند.۲. پشتیبانی از JOIN و بهبودهای بلادرنگ در ES|QLزبان پرس‌وجوی Elasticsearch یا همان ES|QL همچنان در حال تکامل است و حالا به قابلیتی رسیده که مدت‌ها لقب «جام مقدس» تحلیل داده را داشت: یعنی پشتیبانی از join.قابلیت‌های تازه در نسخه ۹.۰:LOOKUP JOIN برای پرس‌وجوهای بلادرنگ بین ایندکس‌ها و مجموعه‌داده‌های مختلفدریافت نتایج جزئی برای پرس‌وجوهای طولانی‌مدتتوابع پیشرفته گروه‌بندی متنفیلترهای KQL برای فیلترینگ انعطاف‌پذیر و گویااین تغییرات، ES|QL را به یک ابزار قدرتمند برای کاوش داده به‌صورت تعاملی و مقیاس‌پذیر تبدیل کرده است.۳. ارتقاء Lucene به نسخه ۱۰در پشت صحنه، Elasticsearch 9.0 حالا بر پایه Lucene 10 کار می‌کند؛ آخرین نسخه از کتابخانه متن‌باز جستجو که قلب تپنده Elasticsearch است.مزایای Lucene 10:بهبود عملکرد پرس‌وجو و کاهش تأخیراستفاده بهینه‌تر از منابع سخت‌افزاریAPIهای تازه برای ساده‌سازی مدیریت ایندکس و فرآیند ارتقاءنتیجه این ارتقاء، هم افزایش سرعت و هم روان‌تر شدن نگهداری عملیاتی است.۴. پشتیبانی بومی از OpenTelemetry: نسخه پایدار EDOTانتشار پایدار Elastic Distributions of OpenTelemetry یا همان EDOT، پشتیبانی بومی از استانداردهای OpenTelemetry را برای تمام سیگنال‌های تله‌متری (از جمله لاگ‌ها، متریک‌ها و تریس‌ها) به ارمغان می‌آورد.مزایا:رصدپذیری آماده‌به‌کار بدون قفل شدن به محصولات اختصاصی (proprietary lock-in) بهبود همبستگی داده‌ها بین سرویس‌هایکپارچگی روان با ابزارهای بومی OpenTelemetryاین قابلیت، Elasticsearch را به یک بازیگر کلیدی در اکوسیستم رصدپذیری متن‌باز تبدیل می‌کند.۵. رصدپذیری LLM برای اپلیکیشن‌های GenAIبا رشد هوش مصنوعی مولد (Generative AI)، رصدپذیری از یک انتخاب به یک ضرورت تبدیل شده است. Elasticsearch 9.0 ابزار بومی پایش مدل‌های زبانی بزرگ را معرفی کرده که شامل موارد زیر است:متریک‌های عملکرد و تحلیل تأخیرردیابی پرسش و پاسخگزارش‌گیری از مصرف و هزینهارزیابی امنیت و قابلیت اطمیناناین ویژگی از پلتفرم‌های محبوب میزبانی LLM مانند Amazon Bedrock، Google Vertex AI، Azure OpenAI و OpenAI پشتیبانی می‌کند تا نظارت و بهینه‌سازی بارهای کاری GenAI آسان‌تر شود.۶. بهبودهای امنیتی: کشف حمله و خودکارسازی قوانین تشخیصعملیات امنیتی در این نسخه یک جهش جدی دارد:انتشار پایدار Attack Discovery برای کشف خودکار تهدیدهاوارد کردن خودکار قوانین تشخیص برای مدیریت ساده‌تر قوانینقوانین تشخیص از پیش‌ساخته و قابل‌سفارشی‌سازیپیش‌نمایش مهاجرت خودکار از قوانین قدیمی SIEMاین قابلیت‌ها، تیم‌های امنیتی را در پیشگیری و واکنش سریع به تهدیدات نوظهور توانمندتر می‌کند.۷. موارد حذف و تغییرات ناسازگارمثل هر نسخه بزرگ دیگر، در این نسخه هم تغییراتی وجود دارد که باید به آن‌ها توجه کنید:حذف Enterprise Search Node، AppSearch و Workplace Search (اگر به این قابلیت‌ها وابسته‌اید، باید راهکار جایگزین بیابید)حذف پشتیبانی از رمزنگاری TLS_RSA در JDK 24توقف پشتیبانی از APIهای Behavioral Analytics CRUDحذف پشتیبانی از ایندکس‌های فریز شده (Frozen Indices)سایر حذف‌ها: تنظیم client.type، پشتیبانی از TLSv1.1 و چند API منسوخ دیگرپیش از ارتقاء، حتماً راهنمای کامل تغییرات و حذف‌ها را مطالعه کنید تا با قطعی یا ناسازگاری روبه‌رو نشوید.منبع:https://mcplusa.com/whats-new-in-elasticsearch-9-0/#:~:text=One%20of%20the%20standout%20features,to%205x%20faster%20query%20speed</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Wed, 13 Aug 2025 18:51:12 +0330</pubDate></item><item><title>الگوهای غلط در استفاده از Redis</title><link>https://virgool.ir/@vakily/الگوهای-غلط-در-استفاده-از-redis-bbc2pgf5ark1</link><description>توسعه‌دهندگان فقط از Redis استفاده نمی‌کنند؛ آن را واقعاً دوست دارند. طبق نظرسنجی سالانه Stack Overflow در سال ۲۰۲۱، Redis برای پنجمین سال پیاپی به عنوان «محبوب‌ترین پلتفرم پایگاه‌داده» شناخته شده است.با این حال، مهم است در نظر داشته باشیم که تنظیمات پیش‌فرض Redis لزوماً برای همه مناسب نیست. میلیون‌ها توسعه‌دهنده Redis را به خاطر سرعت و کارایی‌اش انتخاب می‌کنند، اما نکته حیاتی این است که اطمینان پیدا کنیم استفاده‌مان از آن درست و اصولی است.«الگوی اشتباه» یا Antipattern در واقع به روش‌ها و راه‌حل‌هایی گفته می‌شود که در نگاه اول مناسب به نظر می‌رسند، اما در مرحله اجرا باعث پیچیدگی بیشتر کد و کاهش کارایی می‌شوند. در ادامه به مهم‌ترین الگوهای غلط در استفاده از Redis می‌پردازیم:۱. اجرای پایگاه‌داده‌های بزرگ روی یک شارد یا یک نمونه Redisوقتی یک پایگاه‌داده بزرگ را روی یک شارد یا یک نمونه از Redis اجرا می‌کنید، عملیات‌هایی مانند failover (تغییر خودکار سرور در صورت خرابی)، پشتیبان‌گیری و بازیابی، همگی زمان بیشتری خواهند برد.بنابراین، همیشه توصیه می‌شود حجم هر شارد را در محدوده استاندارد نگه دارید. قاعده محافظه‌کارانه و رایج این است:حداکثر ۲۵ گیگابایت دادهیا ۲۵ هزار عملیات بر ثانیهدر Redis Cloud اگر داده‌های شما بیش از ۲۵ گیگابایت باشد و تعداد عملیات نیز بالا باشد، شارد کردن می‌تواند کارایی را افزایش دهد. حتی با حجم کمتر عملیات، Redis می‌تواند تا ۵۰ گیگابایت داده را نیز مدیریت کند.۱. استفاده از redis-pyکتابخانه redis-py از یک connection pool برای مدیریت اتصال‌ها به سرور Redis استفاده می‌کند. به‌طور پیش‌فرض، هر نمونه Redis که ایجاد کنید، یک connection pool اختصاصی خواهد داشت.شما می‌توانید این رفتار را تغییر دهید و از یک connection pool موجود استفاده کنید. این کار با ارسال نمونه connection pool به پارامتر connection_pool کلاس Redis انجام می‌شود. این روش زمانی کاربرد دارد که بخواهید شاردینگ سمت کلاینت پیاده‌سازی کنید یا کنترل دقیق‌تری روی مدیریت اتصال‌ها داشته باشید:pool = redis.ConnectionPool(host=&#39;localhost&#39;, port=6379, db=0)&#xA;r = redis.Redis(connection_pool=pool)&#xA;۲. اتصال مستقیم به نمونه‌های Redisوقتی تعداد زیادی کلاینت دارید، موجی از تلاش‌ها برای اتصال مجدد (Reconnect Flood) می‌تواند یک پردازش single threaded را از کار بیندازد و باعث failover شود.برای جلوگیری از این مشکل، باید از ابزاری مناسب برای کاهش تعداد اتصال‌های باز به سرور Redis استفاده کنید.به‌عنوان نمونه:Redis Enterprise DMC Proxy می‌تواند با نقش پروکسی، تعداد اتصال‌ها به سرور کش شما را کاهش دهد.Twemproxy یک پروکسی سبک و سریع است که با هدف کاهش تعداد اتصال‌های باز به سرورهای کش ساخته شده است. این ابزار همراه با ویژگی‌هایی مانند Protocol Pipelining و Sharding به شما کمک می‌کند معماری کش توزیع‌شده خود را به‌صورت افقی (Horizontal) مقیاس‌دهی کنید.۳. بیش از یک شارد ثانویه (Redis OSS)در Redis نسخه متن‌باز (Redis OSS) برای اجماع داده‌ها (Quorum) از مدل شاردبندی استفاده می‌شود. توصیه می‌شود حداقل ۳ نسخه از داده‌ها (دو شارد Replica برای هر شارد Master) داشته باشید تا از مشکل Split-Brain جلوگیری شود.به‌طور خلاصه، Redis OSS با داشتن تعداد فردی از شاردها (یک Primary + دو Replica) این چالش را حل می‌کند.در Redis Cloud این مشکل با تعداد فردی از نودها (Nodes) برطرف می‌شود و حتی با داشتن تنها دو نسخه از داده‌ها نیز از Split-Brain جلوگیری می‌کند که این کار از نظر هزینه به‌صرفه‌تر است. در صورت نیاز می‌توان از «Quorum-Only Node» استفاده کرد تا تعداد نودها فرد شود، بدون این که نود داده اضافه و پرهزینه‌ای ایجاد کنیم.۴. اجرای عملیات‌ها به‌صورت تک‌به‌تکاجرای چندین عملیات به‌صورت سری باعث افزایش سربار ارتباطی می‌شود. راه‌حل بهتر Pipelining است؛ یعنی ارسال چندین دستور پشت سر هم، بدون صبر کردن برای پاسخ هرکدام، و پردازش پاسخ‌ها در انتها.Pipelining کاملاً سمت کلاینت پیاده‌سازی می‌شود و برای کاهش تأخیر پاسخ در شبکه‌های با Latency بالا استفاده می‌گردد. این روش با Buffering زمان رفت‌و‌برگشت داده در شبکه را کاهش می‌دهد. در اتصال به localhost این روش می‌تواند سرعت را تا ۵ برابر افزایش دهد و در ارتباطات اینترنتی کند حتی بیش از ۱۰۰ برابر بهبود ایجاد کند.۵. کش‌کردن کلیدها بدون TTLRedis در اصل یک ذخیره‌ساز کلید-مقدار است و می‌توان برای هر کلید زمان انقضا (TTL) تعیین کرد. با رسیدن این زمان، کلید به‌طور خودکار حذف می‌شود. بدون TTL، کلیدها انباشته شده و در نهایت منجر به Eviction خواهند شد.پیشنهاد می‌شود برای تمام کلیدهای کش، TTL مشخص کنید. دستور TTL مدت زمان باقی‌مانده عمر یک کلید را برحسب ثانیه بازمی‌گرداند و به شما اجازه می‌دهد نظارت دقیقی روی چرخه عمر داده‌ها داشته باشید.۶. حلقه بی‌پایان Redis Replicationاگر بخواهید یک پایگاه‌داده فعال و بسیار بزرگ را روی یک لینک کند یا اشباع‌شده replicate کنید، فرآیند Replication هیچ‌وقت تمام نمی‌شود، چون داده‌ها دائماً در حال تغییرند.برای حل این مشکل باید بافرهای Slave و Client را برای replication کندتر بهینه‌سازی کنید.۷. کلیدهای داغ (Hot Keys)وقتی حجم زیادی از درخواست‌ها روی یک کلید خاص متمرکز می‌شود، همان نود یا شارد مسئول آن کلید زیر فشار شدیدی قرار می‌گیرد. به‌عنوان مثال، اگر خوشه Redis شما ۹۹ نود داشته باشد و یک کلید خاص در هر ثانیه یک میلیون بار درخواست شود، همه این یک میلیون درخواست به یک نود خواهند رفت، نه بین ۹۸ نود دیگر پخش شوند.Redis ابزاری برای شناسایی کلیدهای داغ دارد:redis-cli --hotkeys&#xA;بهترین راه‌حل، طراحی مناسب است تا این وضعیت اصلاً ایجاد نشود. می‌توانید داده را با کلیدهای مختلف و در شاردهای متفاوت ذخیره کنید یا از الگوریتم‌های هش برای توزیع درخواست‌ها استفاده کنید.۸. استفاده از دستور KEYSدستور KEYS تمام کلیدهای ذخیره‌شده را با یک الگو جستجو می‌کند و در پایگاه‌داده‌های بزرگ این کار بسیار کند و پرهزینه است (O(N) با N تعداد کلیدها). معادل این کار در SQL، اجرای SELECT * FROM ... بدون WHERE است.به‌جای آن از دستور SCAN استفاده کنید که جستجو را در چند مرحله انجام می‌دهد و کل سرور را متوقف نمی‌کند. برای جستجو بر اساس محتوا نیز می‌توانید از Redis Search استفاده کنید.۹. استفاده از Redis گذرا (Ephemeral Redis) به‌عنوان پایگاه‌داده اصلیوقتی Redis را به‌عنوان پایگاه‌داده اصلی استفاده می‌کنید (نه فقط کش)، باید دسترس‌پذیری بالا (High Availability) و دوام داده (Durability) را تضمین کنید. در نسخه متن‌باز این کار با Redis Sentinel انجام می‌شود. در Redis Cloud این قابلیت به‌صورت پیش‌فرض وجود دارد. همچنین برای دوام، می‌توانید از AOF یا Snapshotting استفاده کنید.۱۰. ذخیره JSON به‌صورت رشته (String)ذخیره JSON به‌صورت رشته باعث مشکلاتی در هماهنگی بین سرویس‌ها و افزایش هزینه پردازش می‌شود. به‌جای آن از ساختار داده HASH یا ماژول Redis JSON استفاده کنید.۱۱. نگاشت جدول یا JSON به HASH بدون توجه به الگوی کوئریاگر تنها روش پرس‌وجو SCAN باشد، فیلترگذاری محدودی خواهید داشت. بهتر است داده را به‌صورت رشته ذخیره کنید و ایندکس‌های معکوس را با SET یا SORTED SET بسازید و به کلید اصلی ارجاع دهید.همچنین استفاده از چند پایگاه‌داده در یک نمونه Redis (با دستور SELECT) یک ضدالگو است و بهتر است برای هر نیاز یک نمونه Redis اختصاصی داشته باشید.برای داده‌های سری زمانی (Time Series) اگر تنها بر اساس ترتیب کوئری دارید، استفاده از ماژول Redis Time Series پیچیدگی اضافی است؛ به‌جای آن از SORTED SET با امتیاز (Score) زمان استفاده کنید.با افتخار ترجمه شده ازhttps://redis.io/learn/howtos/antipatterns</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Mon, 11 Aug 2025 23:44:35 +0330</pubDate></item><item><title>۹ افسانه توسعه‌دهندگان که وقت شما را می‌گیرند</title><link>https://virgool.ir/@vakily/۹-افسانه-توسعه-دهندگان-که-وقت-شما-را-می-گیرند-owcev3kuatxu</link><description>«همیشه کد تمیز بنویس.»«با جدیدترین استک به‌روز باش.»«پوشش صددرصدی تست ها ضروری است.»همه‌مان این جملات را شنیده‌ایم. بعضی‌ها حتی آن‌ها را در جریان کار خود حک کرده‌اند.اما اگر این «بهترین روش‌ها» همیشه درست نباشند چه؟در دنیای واقعی، توسعه‌دهندگان تحت فشارند تا سریع نسخه بدهند، ایرادها را رفع کنند و مدام بهبود بدهند — نه این‌که دنبال کمال بگردند.خیلی از قوانینی که مثل وحی منزل دنبالشان می‌کنیم، در واقع افسانه‌هایی‌اند که در زرورق «نمایش بهره‌وری» پیچیده شده‌اند.این یک غر زدن نیست. یک تلنگر به واقعیت است.در ادامه ۹ افسانه‌ای را می‌خوانید که ظاهراً منطقی‌اند، اما پنهانی وقتتان را می‌خورند.افسانه ۱ — برای مرتبط ماندن باید از جدیدترین تکنولوژی استفاده کنیدوسوسه‌انگیز است، نه؟ یک فریم‌ورک تازه در Hacker News ترند شده، یک یوتیوبر با تیتر «Next.js 15 دیوانه‌کننده است» ویدیو گذاشته و ناگهان استک شما حس و حال عهد بوق پیدا می‌کند.اما حقیقت این است: بیشتر اینترنت هنوز روی تکنولوژی‌های کسل‌کننده می‌چرخد.WordPress روی ۴۳٪ وب سوار است. PHP هنوز زنده و فعال است. Java همچنان سلطان اینترپرایز است. بک‌اند اپلیکیشن محبوبتان شاید روی Flask، Rails یا حتی... Drupal باشد.دنبال کردن تکنولوژی‌های براق و تازه می‌تواند سرگرم‌کننده باشد، اما دنبال کردن پایداری است که قبض‌هایتان را پرداخت می‌کند.مگر شغلتان ایجاب کند که با ابزارهای جدید کار کنید، استفاده از فناوری‌های «خسته‌کننده» کاملاً اشکالی ندارد.جدید به معنای بهتر نیست؛ فقط یعنی تازه‌تر.نکته:تکنولوژی جدید را زمانی به کار ببرید که واقعاً مشکلی را حل کند، نه فقط چون در شبکه X (توییتر سابق) ترند شده است.افسانه ۲ — کد تمیز همیشه بهتر استنوشتن کد تمیز و خوانا چیز خوبی است… تا وقتی که تبدیل به سرگرمی تمام‌وقتتان نشود.اگر جلسه «refactoring» شما به یک مراسم ۴ ساعته برای انتخاب نام متغیر تبدیل شود، در حالی که ویژگی اصلی هنوز کار نمی‌کند، شما در حال بهینه‌سازی نیستید — فقط دارید تعلل را شیک و حرفه‌ای جلوه می‌دهید.فرق هست بین شفافیت و کمال‌گرایی. کد تمیز کمک می‌کند تیم‌ها راحت‌تر مقیاس بگیرند و اعضای جدید سریع‌تر جا بیفتند. اما وقتی موعد تحویل نزدیک است و قابلیت‌ها نصفه‌نیمه‌اند، وسواس روی این‌که اسم را بگذاریم userHandler یا userService کمکی نمی‌کند.نکته:اول کاری کنید که جواب بدهد، بعد آن را زیبا کنید. کد تمیز باید حامی سرعت باشد، نه قاتل آن.افسانه ۳ — «خودت را تکرار نکن» یا داری اشتباه می‌کنی (DRY)توصیه «خودت را تکرار نکن» تا وقتی خوب است که به هزارتویی از هِلپرهای انتزاعی تبدیل نشده باشد که هیچ‌کس سر درنیاورد.اپلیکیشن‌های در مراحل ابتدایی معمولاً از کمی تکرار سود می‌برند. تکرار یک تابع سه‌خطی بسیار ساده‌تر از این است که آن را در یک ابزار کلی (generic util) بیندازید که شش تیم بعدی مجبور شوند با کامنت‌هایی مثل // به این دست نزنید، همه‌چیز را خراب می‌کند، آن را مهندسی معکوس کنند.افراط در انتزاع، تله بهره‌وری است. شما کد را «یک‌بار» می‌نویسید اما برای همیشه دیباگش می‌کنید.نکته:با آگاهی تکرار کنید. اگر امروز کپی‌پیست کار را شفاف‌تر می‌کند، انجامش دهید. refactor را زمانی انجام دهید که تکرار واقعاً دردسر ایجاد کند، نه قبل از آن.افسانه ۴ — پوشش تست یعنی کد شما امن استنشان «۱۰۰٪ پوشش تست» در README فوق‌العاده به نظر می‌رسد، اما این سپری در برابر باگ‌ها نیست. اغلب فقط یک حس امنیت کاذب ایجاد می‌کند.چرا؟ چون همه تست‌ها یکسان نیستند. شما می‌توانید با تست‌هایی که فقط مسیر اجرای کد را طی می‌کنند (نه رفتار واقعی را)، به پوشش صددرصد برسید، در حالی که سناریوهای واقعی بی‌خبر رها می‌شوند.نکته:تست‌هایی بنویسید که استفاده واقعی را شبیه‌سازی کنند، نه فقط آمار را پر کنند. به دنبال پوشش معنادار باشید، نه اعداد تزئینی.افسانه ۵ — باید یک پارادایم برنامه‌نویسی «واقعی» را انتخاب کنیدبعضی توسعه‌دهندگان به برنامه‌نویسی شی‌ءگرا (OOP) سوگند خورده‌اند. بعضی دیگر با برنامه‌نویسی تابعی (FP) نفس می‌کشند. انجمن‌ها این را به جنگ مذهبی تبدیل می‌کنند، انگار استفاده از هر دو باعث خطای segmentation fault می‌شود.واقعیت؟ بیشتر کدهای واقعی ترکیبی از پارادایم‌ها هستند و این اشکالی ندارد.نکته:وسواس «پاکی» را کنار بگذارید. طوری بنویسید که فهم، نگهداری و دیباگ کد آسان‌تر شود. عمل‌گرایی همیشه بر کمال‌گرایی برتری دارد.افسانه ۶ — همیشه باید از ابتدا برای عملکرد (Performance) بهینه کنیدافسانه این است: اپ شما باید از روز اول سرعت آتشین، کش لبه‌ای (edge caching)، یک شبکه CDN و مقیاس‌پذیری (serverless auto-scaling) داشته باشد، وگرنه کارتان اشتباه است.اما مگر این‌که تعداد کاربران شما از اعتیاد به قهوه‌تان بیشتر باشد، بهینه‌سازی زودهنگام فقط اتلاف وقت است.یک اپ to-do برای پنج کاربر به Redis، Kafka و سه Lambda نیاز ندارد. شما هنوز Netflix نیستید.نکته:ساده بسازید. استفاده واقعی را اندازه بگیرید. بعد بهینه‌سازی کنید. تنظیم عملکرد واکنشی به مقیاس است، نه پیش‌نیازی برای انتشار.افسانه ۷ — هرگز بیرون از ساعات کاری کدنویسی نکنید (فرهنگ کار بیش‌ازحد بد است)بعضی‌ها در اینترنت داد می‌زنند: «بعد از ساعات کاری کدنویسی نکن، این همون فرهنگ مسموم کار بیش‌ازحده!» درست است، فرسودگی شغلی واقعی است و مرزگذاری اهمیت دارد.اما خب، بیرون از ساعات کاری کدنویسی کردن همیشه به معنای «جان کندن» نیست.گاهی شبیه یک بازی است. گاهی هم زمین بازی شخصی خودت.پروژه‌های جانبی چیزهایی به شما یاد می‌دهند که هیچ شغل رسمی نمی‌تواند: مالکیت واقعی کار، کنجکاوی، باگ‌های عجیب و غریب، و آن حس لذت وقتی که اپلیکیشن‌تان ساعت ۲:۴۷ صبح بالاخره درست کار می‌کند.نکته:اگر لذت می‌برید، انجامش بدهید. نه برای کف‌زدن‌های LinkedIn. نه برای رؤیای استارتاپ. فقط چون ساختن چیزها سرگرم‌کننده است. اشتیاق، کار بیش‌ازحد نیست — بازی است.افسانه ۸ — ابزارها از اصول مهم‌ترندوسوسه‌انگیز است که فکر کنیم مسلط شدن به آخرین framework شما را به یک توسعه‌دهنده ۱۰برابری تبدیل می‌کند. اما حقیقت این است: ابزارها تغییر می‌کنند، اصول باقی می‌مانند.React تغییر خواهد کرد. Python ترفندهای تازه پیدا می‌کند. شاید کتابخانه محبوب شما هفته بعد کنار گذاشته شود.اما حل مسئله، ساختمان داده‌ها، الگوریتم‌ها و تفکر منطقی این‌ها همان قدرت‌های واقعی‌اند.نکته:ابزارها را یاد بگیرید تا محصول بسازید، اما اصول را بیاموزید تا رشد کنید. توسعه‌دهنده‌ای که بازگشت (recursion) را می‌فهمد، همیشه از کسی که فقط قطعات آماده را کپی‌پیست می‌کند جلوتر است.افسانه ۹ — هوش مصنوعی همه برنامه‌نویس‌ها را جایگزین خواهد کرداین یکی از پر سر و صداترین افسانه‌هاست. بله، هوش مصنوعی کد می‌نویسد. گاهی درست، گاهی هم کاملاً پرت.می‌تواند کدهای تکراری بسازد، کامپوننت طراحی کند، حتی تست بنویسد. اما در عین حال:متغیرهایی می‌سازد که وجود ندارند.توابعی می‌نویسد که اصلاً اجرا نمی‌شوند.مثل یک توسعه‌دهنده تازه‌کار در روز اول، نیاز به مراقبت دائمی دارد.هوش مصنوعی یک ابزار است، نه جایگزین شما. برای سرعت‌بخشیدن به کار، نمونه‌سازی سریع، یا سپردن کارهای تکراری عالی است. اما فاقد همان درک، قضاوت و غریزه حل مسئله واقعی است که شما دارید.نکته:اگر با هوش مصنوعی مثل یک هم‌تیمی در بازی رفتار کنید مفید است، اما شما همچنان بازیکن اصلی هستید. کارها را به او بسپارید، اما مسئولیت را واگذار نکنید.جمع‌بندی: بنویسید، تست کنید، منتشر کنید، تکرار کنیددر دنیایی پر از نظرهای تند، اصطلاحات پرزرق‌وبرق و میم‌های ترندی برنامه‌نویسی، خیلی راحت می‌توان احساس کرد که عقب افتاده‌اید اگر از آخرین چارچوب استفاده نمی‌کنید، پوشش تست ۱۰۰٪ ندارید، یا طبق یک قانون نانوشته بهره‌وری زندگی نمی‌کنید.اما حقیقت این است: بیشتر این افسانه‌ها فقط سروصدا هستند.تنها معیار واقعی که اهمیت دارد این‌ است که در حال یادگیری باشید. در حال ساختن. در حال حل مسائل واقعی.پس اگر کد شلخته مشکل را حل می‌کند، بنویسید. اصول را بیاموزید. منتشر کنید. بازسازی کنید. دوباره تکرار کنید.با افتخار ترجمه شده ازhttps://medium.com/@dev_tips/dev-myths-debunked-9-rules-you-were-told-to-follow-that-might-just-slow-you-down-a54872b9846b</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Sun, 10 Aug 2025 22:39:02 +0330</pubDate></item><item><title>نکته هایی درباره Git - قسمت اول</title><link>https://virgool.ir/@vakily/نکته-هایی-درباره-git-قسمت-اول-qge6xj1bfaef</link><description>سلام به همه!امروز می‌خواهم چند نکتهٔ کاربردی برای استفادهٔ مؤثرتر از Git با شما به اشتراک بگذارم. همان Git معروف که احتمالاً همین حالا هم با آن کار می‌کنید؛ همان یار همیشگی کدنویسی که همکاری در پروژه را برای ما مثل آب خوردن می‌کند.وقتی یک توسعه‌دهنده بعد از شش تا هشت ماه برمی‌گردد و به یک commit نگاه می‌کند، اغلب یادش نمی‌آید چرا اصلاً آن تغییر را ثبت کرده بود. علت؟ معمولاً پیام کامیت شفاف و گویا نبوده. رعایت استانداردهای نوشتن پیام کامیت، کلید حل این مشکل است. اگر این اصول را رعایت کنید، کامیت‌های شما برای خودتان و هر کسی که بعداً آن را بررسی کند، واضح و قابل‌فهم خواهد بود.یک پیام کامیت خوش‌ساخت، بهترین راه برای انتقال منظور تغییرات به دیگر توسعه‌دهندگان است. علاوه بر این، تیم باید روی یک الگوی مشخص برای پیام‌های کامیت توافق کند تا تاریخچهٔ کنترل نسخهٔ پروژه/محصول به‌روشنی مستند شود.من بخش‌های مربوط به «قواعد نام‌گذاری شاخه‌ها» و «قواعد نوشتن پیام کامیت» را در سه سطح پایه، متوسط و پیشرفته دسته‌بندی کرده‌ام.می‌توانید تا هر سطحی که نیاز دارید پیش بروید، اما توصیه می‌کنم دست‌کم سطح متوسط را رعایت کنید تا بهترین نتیجه را بگیرید.آیا پیش آمده بی‌هدف شاخه بسازید، یا وسط کار متوجه شوید خودتان هم معنی یک commit را نمی‌فهمید، یا برای فهم یک تغییر مجبور شوید بین فایل‌ها جست‌وجوی پرزحمت انجام دهید؟ اگر این تصویر برایتان آشناست، نگران نباشید؛ این نکته‌ها مسیر را برایتان روشن‌تر می‌کند.چرا باید استانداردها را رعایت کنیم؟وضوح و فهم بهتر: تا حالا شده به یک کامیت چند ماه قبل نگاه کنید و با خودتان بگویید «آن موقع چی توی سرم بود؟» پیام واضح باعث می‌شود حتی بعد از مدت‌ها هدف تغییر را بفهمید.همکاری و کار تیمی: پیام‌های دقیق باعث می‌شوند همهٔ اعضای تیم روی یک خط باشند و کار گروهی روان‌تر پیش برود.سهولت پیمایش و نگهداشت: رعایت استانداردها جابه‌جایی در کد و نگهداری پروژه را راحت‌تر و کم‌دردسرتر می‌کند.مستندسازی و انتقال دانش: یک پیام کامیت خوب مثل یک یادداشت کوچک است که تازه‌واردها را سریع با تاریخچهٔ پروژه آشنا می‌کند.کیفیت پروژه: شیوه‌های یکپارچه باعث می‌شود کیفیت و پایداری پروژه بالاتر برود.گزارش تغییرات خودکار: با رعایت الگوها، می‌توانید گزارش تغییرات (Changelog) را به‌صورت خودکار تولید کنید و کار مدیریت انتشار را ساده کنید.بهینه‌سازی CI/CD: پیام‌های روشن می‌توانند فرایندهای «یکپارچه‌سازی» و «استقرار مداوم» را بهبود دهند و زمینهٔ لازم برای ابزارهای خودکار را فراهم کنند.اشکال‌زدایی و حل مشکلات: وقتی مشکل پیش می‌آید، پیام‌های استاندارد کمک می‌کنند سریع علت پیدا شود و رفع اشکال آسان‌تر شود.مسئولیت‌پذیری: پیام شفاف مشخص می‌کند چه کسی چه تغییری داده و چرا، و این یک لایهٔ مسئولیت‌پذیری به پروژه اضافه می‌کند.یکپارچگی بین پروژه‌ها: رعایت الگوهای ثابت باعث می‌شود جابه‌جایی بین پروژه‌ها آسان باشد و تاریخچهٔ آنها سریع درک شود.قواعد نام‌گذاری شاخه‌ها (Branch Naming Conventions)نام‌های توصیفی: یک شاخه با نام درست و دقیق، فوراً هدف خود را به مخاطب منتقل می‌کند. به‌جای نام‌های کلی و مبهم، نامی انتخاب کنید که شفافیت داشته باشد.مثال:feature/login&#xA;bugfix/navbar-overflow&#xA;استفاده از خط تیره (Hyphen): برای جدا کردن کلمات در نام شاخه‌ها از خط تیره استفاده کنید (فرمت kebab-case). این کار خوانایی را افزایش می‌دهد.مثال:bugfix/fix-login-issue&#xA;این روش بسیار خواناتر از نمونه‌های زیر است:bugfix/fixLoginIssue&#xA;bugfix/fix_login_issue&#xA;حروف کوچک و کاراکترهای الفبایی-عددی: تنها از حروف کوچک انگلیسی (a-z)، اعداد (0-9) و خط تیره استفاده کنید. از نشانه‌گذاری‌ها، فاصله، آندرلاین یا کاراکترهای خاص تا حد امکان پرهیز کنید.پرهیز از خط تیرهٔ اضافی: خط تیره‌های پشت‌سرهم یا در ابتدا/انتهای نام شاخه، غیرضروری و نادرست‌اند.مثال بد:feat/new--login--&#xA;کوتاه و مؤثر: نام شاخه باید ساده و در عین حال گویا باشد؛ به‌گونه‌ای که هدف آن با یک نگاه مشخص شود.پیش‌وند یا نوع شاخه‌ها (Prefix or Type)استفاده از پیش‌وند برای شاخه‌ها کمک می‌کند تا بر اساس هدف و ماهیتشان دسته‌بندی شوند. این کار نه‌تنها وضوح را افزایش می‌دهد، بلکه در اتوماسیون فرایندها نیز مؤثر است.در ادامه، پیش‌وندهای رایج شاخه‌ها و کاربرد هر یک آمده است:feature/: برای توسعه قابلیت‌های جدید.مثال:feature/new-dashboard  &#xA;feature/user-profile-page  &#xA;feature/new-feature  &#xA;bugfix/: برای رفع اشکالات کد که معمولاً به یک issue مرتبط هستند.مثال:bugfix/login-error  &#xA;bugfix/incorrect-calculation  &#xA;hotfix/: برای رفع فوری و حیاتی اشکالات در محیط تولید (Production).مثال:hotfix/memory-leak  &#xA;hotfix/urgent-security-patch  &#xA;release/: برای آماده‌سازی نسخه‌های جدید، معمولاً برای اصلاحات نهایی و بازبینی‌ها.مثال:release/version-1.0.0  &#xA;release/2.1.0-final  &#xA;docs/: برای نوشتن، ویرایش یا اصلاح مستندات.مثال:docs/update-api-docs  &#xA;docs/installation-guide  &#xA;chore/: برای وظایف روزمره و نگهداری که عملکرد کد را تغییر نمی‌دهند، مانند به‌روزرسانی وابستگی‌ها.مثال:chore/dependency-update  &#xA;chore/refactor-build-scripts  &#xA;chore/update-dependencies  &#xA;test/: برای افزودن یا به‌روزرسانی تست‌ها.مثال:test/add-unit-tests  &#xA;test/fix-integration-tests  &#xA;style/: برای تغییراتی که عملکرد کد را تحت تأثیر قرار نمی‌دهند ولی قالب‌بندی و استایل کد را بهبود می‌بخشند، مثل اصلاح تورفتگی‌ها یا قواعد نگارشی.مثال:style/code-cleanup  &#xA;style/fix-indentation  &#xA;perf/: برای بهبودهای عملکردی.مثال:perf/optimize-loading-time  &#xA;perf/reduce-memory-usage  &#xA;revert/: برای بازگرداندن تغییرات قبلی.مثال:revert/feature-branch-name  &#xA;revert/hotfix-issue-123  &#xA;refactor/: برای بازسازی کد بدون تغییر عملکرد، با هدف بهبود ساختار یا خوانایی.مثال:refactor/optimize-helpers  &#xA;experiment/: برای قابلیت‌ها یا تغییرات آزمایشی که هنوز در مرحله تست هستند.مثال:experiment/new-algorithm-test  &#xA;build/: برای تغییرات در فرایند ساخت یا پیکربندی پروژه.مثال:build/update-webpack-config  &#xA;افزودن شماره تیکت‌هااگر پروژهٔ شما از سیستم‌های پیگیری مسائل مانند Jira، GitHub Issues یا ابزارهای مشابه استفاده می‌کند، بهتر است شماره تیکت مربوطه را در نام شاخه وارد کنید. این کار دنبال کردن و ارجاع به تسک‌های مرتبط را ساده‌تر می‌کند.مثال:feature/PROJ-123-footer-links&#xA;نتیجه گیریرعایت یک الگوی ثابت برای نام‌گذاری شاخه‌ها باعث می‌شود همه اعضای تیم به‌سرعت هدف هر شاخه را بفهمند و روند توسعه روان‌تر شود. همچنین، این کار یکپارچگی با فرایندهای CI/CD و ابزارهای خودکار را آسان‌تر کرده و به نگهداری یک مخزن مرتب و سازمان‌یافته کمک می‌کند.پایان قسمت اول ...با افتخار ترجمه شده ازhttps://substack.com/home/post/p-146876210?utm_campaign=post&amp;utm_medium=web</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Sat, 09 Aug 2025 23:48:50 +0330</pubDate></item><item><title>راهنمای ساده مفهوم Proxy ها</title><link>https://virgool.ir/@vakily/راهنمای-ساده-مفهوم-proxy-ها-tl6rqtox6dyg</link><description>این راهنما به زبان ساده توضیح می‌دهد که پروکسی سرور چیست، چطور به‌عنوان واسطه بین کاربر و اینترنت عمل می‌کند، چرا برای حفظ حریم خصوصی و افزایش سرعت کاربرد دارد و تفاوت پروکسی‌های Forward و Reverse در چیست.تا حالا به این فکر کرده‌اید که چطور می‌شود ناشناس در اینترنت گشت‌وگذار کرد؟پاسخ این معما اغلب در یک چیز نهفته است: پروکسی سرورها.پروکسی‌ها نقش واسطه را بین دستگاه شما و وب‌سایت‌هایی که بازدید می‌کنید ایفا می‌کنند و از حریم خصوصی گرفته تا بهبود سرعت اینترنت، کاربردهای متنوعی دارند.اما دقیقاً چطور کار می‌کنند؟در این مقاله، قرار است به زبان ساده اصول اولیه پروکسی‌ها را توضیح بدهیم، نحوه عملکرد آن‌ها را شرح دهیم و تفاوت پروکسی‌های Forward و Reverse را روشن کنیم.پروکسی سرور چیست؟پروکسی سرور، یک واسطه بین کلاینت (مثل کامپیوتر شما) و اینترنت است.به‌جای اینکه دستگاه شما مستقیماً به یک وب‌سایت متصل شود، پروکسی وسط ماجرا قرار می‌گیرد و ارتباط را به نیابت از شما برقرار می‌کند.مثل این است که شما به جای خودتان، یک دوست را بفرستید تا از کسی سؤالی بپرسد و او جواب را برایتان بیاورد.از نگاه وب‌سایت، این دوست (پروکسی) درخواست‌دهنده واقعی به نظر می‌رسد و شما پشت صحنه پنهان می‌مانید.به زبان فنی، پروکسی سرور یک IP مخصوص به خودش دارد و به‌جای IP شما، با وب‌سایت‌ها ارتباط برقرار می‌کند.وقتی از پروکسی استفاده می‌کنید، وب‌سایت‌ها IP پروکسی را می‌بینند، نه IP واقعی شما.این یعنی هویت شما محفوظ می‌ماند و می‌توانید ناشناس در اینترنت بچرخید.اما این تمام ماجرا نیست؛ پروکسی‌ها می‌توانند محتوای مزاحم را فیلتر کنند یا داده‌های پرکاربرد را در حافظه خود ذخیره کنند تا در مراجعه‌های بعدی سریع‌تر تحویل دهند.پروکسی سرور چطور کار می‌کند؟بیایید فرآیند کار پروکسی را قدم‌به‌قدم مرور کنیم:۱. ارسال درخواست: شما (کلاینت) می‌خواهید به یک وب‌سایت دسترسی پیدا کنید. به‌جای ارتباط مستقیم، این درخواست ابتدا به پروکسی ارسال می‌شود (براساس تنظیماتی که در مرورگر یا دستگاه‌تان انجام شده).۲. بررسی کش (Cache): پروکسی بررسی می‌کند که آیا قبلاً نسخه‌ای از صفحه یا داده در حافظه محلی خود ذخیره کرده یا خیر. اگر داشته باشد، همان را به شما تحویل می‌دهد و دیگر نیازی به مراجعه به سایت اصلی نیست.۳. ارسال درخواست به سایت مقصد: اگر داده در کش موجود نباشد، پروکسی درخواست را به سایت هدف ارسال می‌کند و از IP خودش برای دریافت داده استفاده می‌کند.۴. دریافت پاسخ از سایت: وب‌سایت فکر می‌کند این درخواست از سوی پروکسی آمده و پاسخ را برای او ارسال می‌کند.۵. ارسال پاسخ به شما: پروکسی داده دریافتی را به شما تحویل می‌دهد و ارتباط کامل می‌شود.تفاوت پروکسی Forward و Reverseهمه پروکسی‌ها یکسان نیستند.دو نوع پرکاربرد آن‌ها عبارتند از:پروکسی Forward (سمت کاربر)این نوع پروکسی در سمت کاربر قرار می‌گیرد.شرکت‌ها معمولاً از پروکسی‌های Forward استفاده می‌کنند تا تمام ترافیک اینترنتی کارکنانشان از یک مسیر مشخص عبور کند.کاربردهایش شامل:مسدود کردن سایت‌های خاصکش کردن محتوای پرتکرارپنهان کردن IP شبکه داخلی از دنیای بیروناگر تا به حال از یک وب‌سایت پروکسی برای دور زدن محدودیت‌ها استفاده کرده‌اید، در واقع با یک پروکسی Forward کار کرده‌اید.پروکسی Reverse (سمت سرور)این نوع پروکسی در سمت سرور قرار می‌گیرد و در جلوی یک یا چند وب‌سرور مستقر می‌شود.کاربردهایش شامل:توزیع درخواست‌ها بین چندین سرور (Load Balancing)ارائه سریع‌تر محتوا از طریق کشافزایش امنیت با پنهان کردن سرورهای واقعیبسیاری از شبکه‌های تحویل محتوا (CDNها) مثل Cloudflare در واقع Reverse Proxy هستند که محتوا را به شکل گسترده کش می‌کنند و سرورهای مبدا را از حملات محافظت می‌کنند.شناخت تفاوت این دو نوع پروکسی بسیار مهم است؛ چون یکی از مباحث پرکاربرد در مصاحبه‌های طراحی سیستم محسوب می‌شود!چرا باید از پروکسی استفاده کنیم؟شاید به نظر برسد استفاده از پروکسی فقط دردسر اضافه است، اما در واقع مزایای زیادی برای کاربران عادی و سازمان‌های بزرگ دارد:حریم خصوصی و ناشناس ماندن: پنهان کردن IP شما باعث می‌شود هویتتان محفوظ بماند.امنیت و فیلترینگ: پروکسی‌ها می‌توانند نقش فایروال یا فیلتر را ایفا کنند و دسترسی به سایت‌های مخرب یا نامطلوب را مسدود کنند. همچنین، چون بین شبکه شما و اینترنت قرار دارند، جلوی حملات مستقیم به سرورهای داخلی را می‌گیرند.کش و بهبود عملکرد: پروکسی‌ها محتوای پرتکرار را کش می‌کنند. این باعث کاهش مصرف پهنای باند و افزایش سرعت پاسخ‌دهی می‌شود.تعادل بار و مقیاس‌پذیری: در سیستم‌های بزرگ، Reverse Proxy کمک می‌کند تا بار ترافیک بین چندین سرور تقسیم شود و از فشار بیش‌ازحد روی یک سرور جلوگیری شود. اگر یکی از سرورها از کار بیفتد، ترافیک به سایر سرورها هدایت می‌شود.همین مزایا باعث شده‌اند پروکسی‌ها به بخشی جدایی‌ناپذیر از زیرساخت‌های شبکه‌های امروزی تبدیل شوند.جمع‌بندیشاید پروکسی‌ها پشت صحنه کار کنند، اما حالا می‌دانید که آن‌ها واسطه‌های باهوشی هستند که ارتباطات اینترنتی را امن‌تر، سریع‌تر و خصوصی‌تر می‌کنند.از پروکسی Forward که به شما اجازه می‌دهد ناشناس وب‌گردی کنید تا Reverse Proxy که سایت‌های بزرگ را قادر می‌سازد میلیون‌ها درخواست را پاسخ دهند، این ابزارها در قلب طراحی سیستم‌های مدرن جای دارند.با افتخار ازhttps://substack.com/@arslandg/p-170015267?utm_source=profile&amp;utm_medium=reader2</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Thu, 07 Aug 2025 00:30:25 +0330</pubDate></item><item><title>چگونه API ها را نسخه بندی کنیم؟</title><link>https://virgool.ir/@vakily/چگونه-api-ها-را-نسخه-بندی-کنیم-segib3sfzfyj</link><description>این روزها APIها در همه‌جا حضور دارند و اگر بخواهید سیستمی بسازید، بی‌تردید به موفقیت شما گره خورده‌اند. اما وقتی API تغییر می‌کند یا یکی از مصرف‌کنندگان درخواست افزودن قابلیت جدیدی را مطرح می‌کند چه اتفاقی می‌افتد؟ اینجاست که موضوع نسخه‌بندی (Versioning) به میان می‌آید.سرفصل‌ها به این شرح‌اند:چرا و چه زمانی باید APIهایتان را نسخه‌بندی کنید؟استراتژی‌های نسخه‌بندیروش‌های پیاده‌سازینسخه‌بندی معنایی (Semantic Versioning)مدیریت چرخه عمر APIابزارهاچرا و چه زمانی باید APIهایتان را نسخه‌بندی کنید؟با رشد و تکامل یک نرم‌افزار، ناگزیر نیاز خواهید داشت تغییراتی در APIهای خود ایجاد کنید؛ افزودن قابلیت‌های جدید، رفع باگ‌ها، یا بهبود عملکرد. اما به‌محض اینکه توسعه‌دهندگان دیگر شروع به ساختن اپلیکیشن‌هایی کنند که به API شما وابسته است، هر تغییری ممکن است کدهای آن‌ها را مختل کند. اینجاست که نسخه‌بندی API اهمیت حیاتی پیدا می‌کند.تصور کنید API‌ای ساخته‌اید که بسیاری از وب‌سایت‌ها برای نمایش داده‌های مالی روی داشبوردهایشان از آن استفاده می‌کنند. فعلاً مقادیر را به دلار (USD) بازمی‌گرداند، اما تصمیم گرفته‌اید واحد یورو (EUR) را هم اضافه کنید. اگر بدون نسخه‌بندی، فرمت پاسخ را تغییر دهید، ممکن است اپلیکیشن‌هایی که به فرمت قبلی وابسته‌اند دچار مشکل شوند.البته، لازم نیست با هر تغییر کوچک، یک نسخه جدید از API ارائه دهید. اما برای تغییرات مخربی که می‌تواند اپلیکیشن‌های موجود را بشکند، حتماً باید نسخه جدیدی تعریف کنید. نمونه‌هایی از این تغییرات عبارت‌اند از: حذف یا تغییر نام فیلدهای پاسخ، اضافه کردن پارامترهای اجباری جدید، یا تغییر نحوه عملکرد اساسی یک endpoint.از سوی دیگر، تغییراتی که باعث شکستن API نمی‌شوند، نیازمند نسخه‌بندی نیستند؛ مثل اضافه کردن فیلدهای اختیاری به پاسخ یا بهینه‌سازی عملکرد API بدون تغییر در نحوه استفاده کلاینت‌ها.در مثال API مالی، اضافه کردن یک فیلد اختیاری برای یورو (EUR) آسیبی به اپلیکیشن‌های موجود که فقط از دلار استفاده می‌کنند نمی‌زند. اما اگر فیلد Dollars را به «currency» تغییر دهید، اپلیکیشن‌هایی که به نام قبلی وابسته‌اند دچار مشکل خواهند شد.البته نسخه‌بندی بی‌رویه هم دردسرساز است. نگهداری هر نسخه جدید هزینه‌های توسعه و تست را افزایش می‌دهد و تعدد نسخه‌ها ممکن است توسعه‌دهندگان را در انتخاب نسخه مناسب سردرگم کند.پس باید رویکرد نسخه‌بندی دقیقی داشته باشید؛ رویکردی که تعادل میان ثبات و قابلیت‌های جدید را برقرار کند. هدف این است که API خود را ارتقاء دهید بدون آنکه کاربران را در این مسیر به دردسر بیندازید.استراتژی‌های نسخه‌بندیبرای مدیریت تغییرات در APIها معمولاً دو رویکرد اصلی وجود دارد: استراتژی تغییرات افزایشی (Additive Change) و استراتژی نسخه‌بندی صریح (Explicit Versioning).استراتژی تغییرات افزایشی:در این روش، شما صرفاً ویژگی‌ها و فیلدهای جدیدی به API اضافه می‌کنید، بدون آنکه به ساختار فعلی آسیبی وارد شود. تغییراتی که باعث ناسازگاری با نسخه‌های قبلی می‌شود (مثل حذف یا تغییر نام فیلدها، تغییر نوع داده‌ها یا کدهای خطا، یا تغییر اساسی در رفتار endpointها) ممنوع است.کارهایی که مجاز هستند شامل موارد زیر می‌شود:افزودن فیلدهای جدید (مشروط به اینکه اختیاری باشند)اضافه کردن endpointهای جدیدافزودن پارامترهای opt-in برای فعال کردن قابلیت‌های جدیدبیایید با یک مثال ببینیم چطور این روش عمل می‌کند. فرض کنید API مالی شما چنین پاسخی برمی‌گرداند:{&#xA;  &#34;stock&#34;: &#34;AAPL&#34;,&#xA;  &#34;price&#34;: ۱۵۰.۲۵,&#xA;  &#34;currency&#34;: &#34;USD&#34;,&#xA;  &#34;market_cap&#34;: ۲۵۰۰۰۰۰۰۰۰&#xA;}&#xA;بعد از مدتی متوجه می‌شوید که برخی کاربران به اطلاعات ارزش بازار (market_cap) نیازی ندارند و این فیلد باعث بار اضافه روی شبکه آن‌ها می‌شود. طبق استراتژی افزایشی نمی‌توانید این فیلد را حذف کنید، چون برخی کلاینت‌ها به آن وابسته‌اند.اما می‌توانید یک پارامتر اختیاری مثل exclude_market_cap=true اضافه کنید. در این حالت، کلاینت‌هایی که می‌خواهند بار شبکه را کاهش دهند می‌توانند از این پارامتر استفاده کنند و دیگران لازم نیست تغییری بدهند.استراتژی افزایشی برای APIهای کوچک که تغییرات زیادی ندارند مناسب است. اما هرچه API بزرگ‌تر و پیچیده‌تر شود، حفظ سازگاری به این روش سخت‌تر خواهد شد.استراتژی نسخه‌بندی صریح:در این رویکرد، شما نسخه‌های مختلفی از API را به‌طور هم‌زمان نگهداری می‌کنید. هرگاه نیاز به ایجاد تغییرات مخرب داشتید، نسخه جدیدی منتشر می‌کنید. این روش آزادی عمل بیشتری برای توسعه API به شما می‌دهد.نسخه‌بندی صریح برای اپلیکیشن‌های سازمانی و محصولاتی که نیاز به تکامل گسترده در طول زمان دارند، بسیار مناسب است. شرکت‌هایی مانند Stripe و Slack از این رویکرد استفاده می‌کنند، چون انعطاف‌پذیری لازم برای بهبودهای اساسی را در اختیارشان می‌گذارد و در عین حال، کاربران نسخه‌های قبلی را نیز پشتیبانی می‌کنند.در بخش بعدی، به روش‌های پیاده‌سازی نسخه‌بندی صریح خواهیم پرداخت.روش‌های پیاده‌سازی نسخه‌بندیسه روش اصلی وجود دارد که کاربران می‌توانند از طریق آن‌ها مشخص کنند می‌خواهند از کدام نسخه API استفاده کنند.رایج‌ترین روش، نسخه‌بندی در مسیر URL (URL Path Versioning) است. در این روش، نسخه را به مسیر URL اضافه می‌کنید، مانند مثال‌های زیر:https://api.example.com/v1/stocks&#xA;https://api.example.com/v2/stocks&#xA;در اینجا شناسه نسخه (مثل v1 یا v2) قبل از نام منبع (resource name) قرار می‌گیرد. این کار باعث می‌شود نسخه مشخص‌شده به همه منابع و متدهای آن نسخه اعمال شود. مزیت این روش در سادگی و وضوح آن است. هنگام دیباگ کردن، بلافاصله نسخه API را در هر درخواست می‌بینید. همچنین با ابزارهای مستندسازی و تست API نیز به‌خوبی سازگار است.اما ایرادی که دارد این است که با هر تغییر نسخه، آدرس URL منبع تغییر می‌کند. این موضوع وقتی مشکل‌ساز می‌شود که بخواهید URLها به‌عنوان لینک‌های دائمی (permalinks) استفاده شوند. با وجود این، بسیاری از APIهای معروف مثل GitHub و Stripe همین روش را به‌کار می‌گیرند.روش دوم، استفاده از هدر سفارشی HTTP (Custom HTTP Header) برای مشخص کردن نسخه است. در این روش، به‌جای تغییر URL، نسخه را در هدر درخواست تعریف می‌کنید:GET /stocks HTTP/1.1&#xA;Host: api.example.com&#xA;Api-Version: 2&#xA;این رویکرد باعث می‌شود URLها تمیز و ثابت باقی بمانند و با این ایده هم‌راستا است که URL باید هویت منبع را مشخص کند، نه نحوه نمایش آن را. با این حال، استفاده از هدر سفارشی پیاده‌سازی پیچیده‌تری برای مصرف‌کنندگان API دارد و اگر به‌درستی مدیریت نشود، ممکن است مشکلاتی در کشینگ (Caching) ایجاد کند.سومین روش، استفاده از پارامترهای پرس‌وجو (Query Parameters) برای تعیین نسخه است. در این حالت نسخه به‌عنوان یک پارامتر در URL نوشته می‌شود. این روش راه‌اندازی ساده‌ای دارد و ساختار پایه URL را تغییر نمی‌دهد. اما مشکلش این است که پارامترهای پرس‌وجو معمولاً برای فیلتر کردن استفاده می‌شوند، نه نسخه‌بندی. همین موضوع ممکن است باعث شود که مستندات API به آن‌ها اشاره نکند یا با پارامترهای دیگر تداخل پیدا کند. این روش کمتر رایج است، اما برخی APIها (مثل بعضی از سرویس‌های Google) از آن استفاده می‌کنند.هر یک از این روش‌ها مزایا و معایب خود را دارند، اما مهم‌ترین نکته، یکدستی و ثبات در انتخاب روش است. بیشتر APIهای بزرگ از نسخه‌بندی در مسیر URL استفاده می‌کنند چون روشی شفاف و ساده است. با این وجود، برخی سرویس‌ها برای پوشش سناریوهای مختلف، چندین روش نسخه‌بندی را به کاربران پیشنهاد می‌دهند.نسخه‌بندی معنایی (Semantic Versioning)هنگام نسخه‌بندی APIها، نیاز به یک سیستم شفاف برای نام‌گذاری نسخه‌ها دارید. یکی از رویکردهای محبوب در این زمینه، نسخه‌بندی معنایی (Semantic Versioning یا SemVer) است که از یک فرمت عددی سه‌قسمتی استفاده می‌کند: نسخه اصلی (Major)، نسخه فرعی (Minor) و وصله (Patch).فرض کنید API شما در نسخه ۲.۰.۰ قرار دارد. معنای هر بخش به این صورت است:نسخه اصلی (Major Version) – عدد اول (۲): زمانی تغییر می‌کند که تغییراتی ناسازگار با نسخه‌های قبلی ایجاد کنید؛ مثل حذف یا تغییر نام فیلدها یا تغییر رفتار یک endpoint. وقتی یک توسعه‌دهنده می‌بیند API از ۲.۰.۰ به ۳.۰.۰ رسیده، می‌داند که باید در کد خود تغییراتی بدهد.نسخه فرعی (Minor Version) – عدد دوم (۰): زمانی افزایش پیدا می‌کند که قابلیت‌های جدیدی به API اضافه می‌کنید که همچنان با نسخه‌های قبلی سازگارند. مثلاً افزودن یک endpoint جدید یا یک فیلد اختیاری. حرکت از ۲.۰.۰ به ۲.۱.۰ به توسعه‌دهندگان اجازه می‌دهد از ویژگی‌های جدید بهره‌مند شوند بدون اینکه نیاز به تغییر کدهای قبلی داشته باشند.وصله (Patch Version) – عدد سوم (۰): برای رفع باگ‌ها و تغییرات جزئی که قابلیت جدیدی اضافه نمی‌کنند اما مشکلات موجود را برطرف می‌کنند. ارتقاء از ۲.۱.۰ به ۲.۱.۱ باید برای تمام کاربران بی‌خطر باشد و نیازی به تغییر در کدهای کلاینت نباشد.استفاده از نسخه‌بندی معنایی باعث می‌شود توسعه‌دهندگان دقیقاً بدانند چه نوع تغییراتی در API رخ داده است. افزایش نسخه اصلی نشانه نیاز به تغییرات در کد است، در حالی که نسخه‌های فرعی و وصله‌ها (Minor و Patch) باید بدون ایجاد مشکل قابل استفاده باشند.مدیریت چرخه عمر APIبا تغییرات مداوم در API و انتشار نسخه‌های جدید، در نهایت باید نسخه‌های قدیمی‌تر را کنار بگذارید. زمانی که یک نسخه اصلی (Major Version) جدید منتشر می‌کنید، باید برای پشتیبانی از نسخه‌های قبلی یک بازه زمانی مشخص تعریف کنید. مثلاً وقتی نسخه ۴ را ارائه می‌دهید، اعلام می‌کنید که نسخه ۱ به‌زودی از پشتیبانی خارج خواهد شد.به طور معمول، اگر به توسعه‌دهندگان ۶ تا ۱۲ ماه زمان برای مهاجرت به نسخه‌های جدید بدهید، فرصت کافی برای برنامه‌ریزی و پیاده‌سازی تغییرات را خواهند داشت، بدون آنکه در فشار و عجله قرار بگیرند.یکی از روش‌های عملی و مؤثر برای اطلاع‌رسانی توقف پشتیبانی (Deprecation) استفاده از هدر Sunset در پاسخ‌های API است. این هدر به توسعه‌دهندگان می‌گوید که یک نسخه یا endpoint خاص تا چه زمانی در دسترس خواهد بود:Sunset: Sat, 31 Dec 2025 23:59:59 GMT&#xA;به‌محض اینکه یک توسعه‌دهنده این هدر را در پاسخ API ببیند، متوجه می‌شود که باید رابط کاربری خود را به‌روزرسانی کند. پس از رسیدن به تاریخ sunset، درخواست‌هایی که به آن نسخه ارسال می‌شوند یا باید پیغام خطا دریافت کنند، یا به نسخه جدید ریدایرکت شوند.ابزارهامدیریت نسخه‌های API به صورت دستی، خیلی زود تبدیل به کاری پیچیده و پرخطا می‌شود. خوشبختانه ابزارها و کتابخانه‌هایی وجود دارند که دقیقاً برای همین منظور طراحی شده‌اند و به کمک شما می‌آیند.OpenAPI Specification که قبلاً با نام Swagger شناخته می‌شد، یکی از بهترین روش‌ها برای توصیف و طراحی APIهاست. این استاندارد مزایای بسیاری در زمینه نسخه‌بندی دارد:به‌راحتی می‌توانید تغییرات هر نسخه را در فایل‌های تعریف جداگانه مستندسازی و ردیابی کنید.مستندات تعاملی (Interactive Documentation) به توسعه‌دهندگان کمک می‌کند تا به‌سرعت تفاوت‌های هر نسخه را ببینند.ابزارهایی وجود دارند که می‌توانید با آن‌ها نسخه‌های مختلف API خود را با یکدیگر مقایسه کرده و تغییرات مخربی (Breaking Changes) که ممکن است باعث بروز خطا شوند را شناسایی کنید.برای مثال، ابزار openapi-diff به شما این امکان را می‌دهد که دو مشخصات API (Specification) را با هم مقایسه کنید و بفهمید کجاها ناسازگاری ایجاد شده است:openapi-diff original.json updated.json&#xA;خروجی ممکن است چیزی شبیه به این باشد:GET /stocks&#xA;&#xA;Return Type:&#xA;&#xA;- Changed 200 OK&#xA;&#xA;Media types:&#xA;&#xA;- Changed application/json&#xA;&#xA;Schema: Broken compatibility&#xA;&#xA;Missing property: price (number)&#xA;این گزارش به شما می‌گوید که حذف فیلد &#34;price&#34; یک تغییر ناسازگار است که نیازمند انتشار یک نسخه اصلی جدید می‌باشد.علاوه بر مقایسه مشخصات (Specification Comparison)، ابزارهای دیگری نیز وجود دارند که به مدیریت نسخه‌بندی کمک می‌کنند. مثلاً API Gatewayهایی مثل Amazon API Gateway، Azure API Management یا Kong می‌توانند نسخه‌بندی را به‌صورت خودکار برای شما مدیریت کنند. این ابزارها با توجه به اطلاعات نسخه در URL یا هدرها، درخواست‌ها را به backend مناسب هدایت می‌کنند.ممکن است نسخه‌بندی API در ابتدا کاری زمان‌بر و پرزحمت به نظر برسد، اما در واقع یک سرمایه‌گذاری بلندمدت برای موفقیت API و رضایت کاربران است. رویکردی دقیق و ثابت در طول زمان به توسعه‌دهندگان نشان می‌دهد که برای کار آن‌ها ارزش قائلید و این اعتماد را حفظ می‌کند؛ حتی زمانی که API شما تغییر می‌کند.با افتخار ازhttps://newsletter.francofernando.com/p/apis-versioning?utm_source=%2Fsearch%2FElasticsearch&amp;utm_medium=reader2&amp;hide_intro_popup=true</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Mon, 04 Aug 2025 18:35:48 +0330</pubDate></item><item><title>آشنایی با شبکه none در Docker</title><link>https://virgool.ir/codenevis/آشنایی-با-شبکه-none-در-docker-oltcpbmmbhaf</link><description>در این مقاله کوتاه قصد دارم درباره شبکه none در داکر صحبت کنم. شبکه none یکی از انواع شبکه‌هایی است که داکر برای ایزوله‌سازی کانتینرها ارائه می‌دهد. این شبکه به‌طور خاص طراحی شده است تا کانتینر را از هرگونه دسترسی به اینترنت یا دیگر شبکه‌ها کاملاً ایزوله کند.زمانی که یک کانتینر با استفاده از شبکه none اجرا می‌شود:تنها یک رابط loopback داخلی (localhost) در کانتینر فعال است.کانتینر نمی‌تواند به هیچ منبع خارجی (مانند وب‌سرویس‌ها، دیتابیس‌ها، یا حتی دیگر کانتینرها) متصل شود.بنابراین این ویژگی باعث می‌شود شبکه none گزینه‌ای ایده‌آل برای سناریوهایی باشد که امنیت و ایزوله‌سازی کامل داده‌ها اهمیت بالایی دارند.بیایید با هم سناریو زیر را در نظر بگیرم:به عنوان مدیر تیم مهندسی داده، تصمیم گرفتم از محمد، که یک عضو تازه‌کار و مشتاق است، برای انجام بخش کوچکی از یک پروژه از جنس ETL استفاده کنم. هدف من این است که مهارت‌های محمد را در یک محیط کنترل‌شده محک بزنم و در عین حال نشان دهم که او می‌تواند در شرکت تأثیرگذار باشد. با این حال، به دلیل تازه‌کار بودن محمد و مسائل مربوط به امنیت داده‌ها، او اجازه دسترسی به داده‌های محرمانه را ندارد.شرح تسکی که برای محمد تعریف کردم به این صورت بود:محمد باید کدی بنویسد که مادامی که هر فایل ورودی CSV را از یک دایرکتوری قرار داده شد، پردازش خود را شروع کند. لذا من چند فایل CSV به‌عنوان نمونه طراحی کردم که شامل داده‌هایی مشابه داده‌های واقعی است اما هیچ‌گونه اطلاعات حساس ندارد. این فایل در اختیار محمد قرار دادم. محمد باید در این فایل، تغییراتی ایجاد کند که شامل تغییر نام و نوع ستون‌ها است و همچنین از ستون متنی، تمامی کد ملی ها به همراه نام و نام خانوادگی افراد استخراج شوند و در دو ستون جدید، با جداکننده کاما (,) ذخیره شوند. پس از اعمال این تغییرات، فایل پردازش‌شده باید در یک دایرکتوری مشخص به نام output ذخیره شود. حالا من می توانم خروجی‌های پردازش‌شده را به‌راحتی به یک دیتابیس منتقل کنم تا برای تحلیل‌های بیشتر، گزارش‌گیری، یا ذخیره بلندمدت مورد استفاده قرار گیرند یا آن ها را می‌توانم به‌عنوان ورودی در یک سیستم یا Pipeline دیگر قرار دهم. به‌این‌ترتیب، می‌توانم این داده‌ها را به مراحل بعدی پردازش یا تحلیل‌های پیچیده‌تر انتقال دهم.اما مشکل چیست؟مشکل اینجاست که من فرصت بررسی کد محمد را ندارم و فقط خروجی کار او برایم مهم است. بنابراین ممکن است او در کد خود عملیاتی خرابکارانه انجام دهد، مثلاً ارسال داده‌ها به یک وب‌سرویس خارجی یا ذخیره آن‌ها در محلی دیگر.برای جلوگیری از این موضوع:من از محمد خواستم که پس از تکمیل توسعه، کد خود را در گیت (Git) پوش کند تا بتوانم بعدا سر فرصت به تاریخچه تغییرات کد و جزئیات آن دسترسی داشته باشم.به محمد دسترسی به داده‌های اصلی و محرمانه داده نشده است، و تنها می‌تواند با فایل نمونه کار کند.من تصمیم گرفتم که برای اجرای کدهای محمد از شبکه none داکر استفاده کنم. این تصمیم به این دلیل گرفته شد که این نوع شبکه، کانتینر را به‌صورت کامل از هرگونه دسترسی به اینترنت یا شبکه داخلی ایزوله می‌کند. با این کار، مطمئن می‌شوم پس از دیپلوی کدهای محمد نمی‌توانند داده‌های اصلی را به هیچ وب‌سرویس یا مقصد خارجی ارسال کنند.با این روش، با خیال راحت هر تعداد دسته از داده‌های اصلی را که به‌صورت فایل‌های CSV هستند، به عنوان ورودی در مسیر پردازش ETL محمد قرار دهم. هر فایل ورودی توسط کد محمد پردازش می‌شود و خروجی آن، پس از طی مراحل ETL، در مسیر مشخص‌شده (دایرکتوری output) ذخیره می‌شود.از آنجا که شبکه none داکر جلوی هرگونه دسترسی غیرمجاز به شبکه را می‌گیرد، مطمئن هستم که داده‌های اصلی در این فرآیند کاملاً ایمن هستند.</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Fri, 17 Jan 2025 13:36:08 +0330</pubDate></item><item><title>بررسی سرعت مدل lang_ident_model_1</title><link>https://virgool.ir/@vakily/بررسی-سرعت-مدل-langidentmodel1-pxarm1mpoeky</link><description>اگر بخواهیم شناسایی زبان را در داده‌های متنی بررسی کنیم، اولین سوالی که پیش می‌آید این است که چگونه می‌توانیم به راحتی زبان یک متن را شناسایی کنیم؟ برای این کار، ابزارها و تکنیک های متنوعی وجود دارد که یکی از آن‌ها استفاده از امکانات موجود دیتابیس Elasticsearch است. در این مقاله، قصد داریم با استفاده از مدل lang_ident_model_1 در Elasticsearch، سرعت شناسایی زبان بر روی یک دیتاست فارسی به صورت ساده و مقدماتی انجام دهیم.فرض کنید شما یک فروشگاه اینترنتی دارید که مشتریان به زبان‌های مختلف نظرات خود را می‌نویسند. شما می‌خواهید تمام این نظرات را به صورت خودکار شناسایی زبان کرده و سپس تحلیل‌های بیشتری بر اساس زبان انجام دهید.ما یک دیتاست فارسی داریم که شامل نظرات کاربران در زمینه هتل و تلفن همراه است. دیتاست دارای دو بخش اصلی است: نظرات و درصد درستی آن‌ها. درصد درستی، همان امتیازی است که خود کاربر هنگام نوشتن نظر داده است.گام اول: آماده‌سازی دیتاستابتدا فایل داده‌ها را از اینجا بارگذاری کرده و سپس نظرات را استخراج می‌کنیم:import pandas as pd &#xA;df = pd.read_csv(&#34;Hotel.csv&#34;, encoding=&#39;utf-16&#39;)&#xA;reviews = df[&#34;review&#34;].values.tolist()در اینجا، نظرات به صورت لیستی از رشته‌ها استخراج می‌شوند. حالا که داده‌ها آماده شدند، وقت آن است که این نظرات را به Elasticsearch ارسال کنیم.گام دوم: ایجاد پایپ‌لاین شناسایی زباندر این قسمت باید پایپ‌لاین شناسایی زبان را در Elasticsearch ایجاد کنیم. این کار با استفاده از دستور PUT _ingest/pipeline/language_detection_pipeline انجام می‌شود. پایپ‌لاین شناسایی زبان به مدل lang_ident_model_1 برای شناسایی زبان نیاز دارد و متن‌های هر نظر را به این مدل ارسال می‌کند.PUT _ingest/pipeline/language_detection_pipeline&#xA;{&#xA;   &#34;processors&#34;: [&#xA;      {&#xA;         &#34;inference&#34;: {&#xA;            &#34;model_id&#34;: &#34;lang_ident_model_1&#34;,&#xA;            &#34;inference_config&#34;: {&#xA;               &#34;classification&#34;: {&#xA;                  &#34;num_top_classes&#34;: 1&#xA;               }&#xA;            },&#xA;            &#34;field_map&#34;: {&#xA;               &#34;content&#34;: &#34;text&#34;&#xA;            }&#xA;         }&#xA;      }&#xA;   ]&#xA;}در اینجا، این پایپ‌لاین با استفاده از مدل lang_ident_model_1 زبان متن‌هایی که در فیلد content قرار دارند را شناسایی می‌کند. مدل به طور پیش‌فرض، عمل دسته‌بندی را انجام می‌دهد و به بالاترین دسته (که همان زبان شناسایی شده است) توجه می‌کند.گام سوم: ارسال داده‌ها به Elasticsearch با استفاده از پردازش موازیحالا که داده‌ها آماده‌اند، می‌خواهیم این داده‌ها را به Elasticsearch ارسال کنیم. از آنجایی که تعداد نظرات به 6432 رکورد است، ارسال آن‌ها به صورت یکجا می‌تواند زمان زیادی ببرد. برای حل این مشکل، از پردازش موازی استفاده می‌کنیم تا به صورت همزمان چندین بخش از داده‌ها را ارسال کنیم و عملکرد مدل را در بهترین حالت ممکن انجام دهیم. این کار با استفاده از ThreadPoolExecutor در پایتون انجام می‌شود. کد زیر نشان می‌دهد که چگونه می‌توانیم داده‌ها را به بخش‌های کوچک تقسیم کرده و به صورت موازی ارسال کنیم:from concurrent.futures import ThreadPoolExecutor&#xA;from elasticsearch import Elasticsearch, helpers&#xA;&#xA;def send_chunk(chunk):&#xA;    _chunk = [&#xA;        {&#34;_index&#34;: &#34;hotel&#34;, &#34;_source&#34;: {&#34;content&#34;: doc}, &#34;pipeline&#34;: &#34;language_detection_pipeline&#34;}&#xA;        for doc in chunk&#xA;    ]&#xA;    helpers.bulk(es, _chunk)&#xA;&#xA;es = Elasticsearch([{&#39;host&#39;: &#39;localhost&#39;, &#39;port&#39;: 9200}])&#xA;&#xA;chunk_size = 500&#xA;def chunk_list(data, chunk_size):&#xA;    for i in range(0, len(data), chunk_size):&#xA;        yield data[i:i + chunk_size]&#xA;&#xA;with ThreadPoolExecutor(max_workers=8) as executor:&#xA;    executor.map(send_chunk, chunk_list(reviews, chunk_size))&#xA;&#xA;es.close()در این کد، داده‌ها به دسته‌های 500 تایی تقسیم می‌شوند و هر دسته به صورت موازی به Elasticsearch ارسال می‌شود. استفاده از 8 ترد در اینجا به این معنی است که 8 بخش از داده‌ها به صورت همزمان پردازش خواهند شد.گام چهارم: محاسبه زمان اجرادر نهایت، زمان اجرای این عملیات به صورت زیر است:CPU times: total: 156 ms&#xA;Wall time: 9.54 sاز آنجایی که تعداد رکورد های مجموعه داده ما 6432 است، هر ثانیه حدودا 674 داده را پردازش و به دیتابیس وارد کرده است.نمونه ای از یک دادهنتیجه گیریدر این مقاله سعی شد بررسی مقدماتی و ساده ای از میزان سرعت مدل تشخیص زبان دیتابیس Elasticsearch داشته باشیم. با استفاده از مدل lang_ident_model_1، می‌توانیم به راحتی زبان متن‌های مختلف را شناسایی کرده و بر اساس آن تحلیل‌های دقیق‌تری انجام دهیم. از طرفی، استفاده از پردازش موازی باعث شد که سرعت پردازش داده‌ها به شکل قابل توجهی افزایش یابد. با استفاده از پردازش موازی، این عملیات در کمتر از 10 ثانیه انجام شد که زمان مناسبی برای حجم داده‌های متوسط محسوب می‌شود.</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Thu, 02 Jan 2025 14:50:35 +0330</pubDate></item><item><title>آشنایی با Best Practice های ElasticSearch</title><link>https://virgool.ir/@vakily/آشنایی-با-best-practices-های-elasticsearch-qnylj7ndthny</link><description>در این نوشته قصد دارم در مورد best practice های استفاده از ElasticSearch بنویسم. این روش‌ها توصیه‌های عمومی هستند و می‌توانند در هر مورد کاربردی اعمال شوند. آشنایی با Bulk Requestsمفهوم API Bulk امکان انجام بسیاری از عملیات‌های index/delete را در یک فراخوانی API فراهم می‌کند. این می‌تواند سرعت index کردن را به طور قابل توجهی افزایش دهد. هر subrequest به صورت مستقل اجرا می‌شود، بنابراین failure یک subrequest تاثیری بر success دیگران نخواهد داشت. اگر هر یک از request ها faile شود، top-level error flag به true تنظیم می‌شود و جزئیات خطا گزارش خواهد شد.آشنایی با Multithread clients to Index Dataیک single thread که request های bulk را ارسال می‌کند، احتمالاً قادر به استفاده کامل از ظرفیت indexing ElasticSearch cluster نخواهد بود. برای استفاده از تمام منابع cluster، شما باید داده‌ها را از چندین thread یا processe ارسال کنید. علاوه بر استفاده بهتر از منابع cluster، این باید کمک کند تا هزینه هر fsync را کاهش دهد. هر دو داده index و transaction log به طور دوره‌ای به دیسک flush می‌شوند. اگر داده‌های بیشتری با multithread وجود داشته باشند، داده‌های بیشتری به دیسک sync می‌شود تا I/O را برای بهبود performance کاهش دهد.درباره index.refresh_intervalبه طور پیش فرض، ElasticSearch به طور دوره‌ای هر ثانیه index ها را refresh می‌کند، اما درصورتی که تنها بر روی index هایی که در 30 ثانیه گذشته حداقل یک request از نوع جستجو دریافت کرده باشند. اگر شما ترافیک جستجوی کم یا اصلاً ندارید (به عنوان مثال، کمتر از یک request جستجو در هر 5 دقیقه) و می‌خواهید برای سرعت indexing بهینه‌سازی کنید، این config بهینه است. این رفتار در پیکربندی پیش فرض هنگامی که جستجویی انجام نمی‌شود، به بهینه‌سازی خودکار bulk indexing کمک می‌کند. برای انصراف از این رفتار، می توانید interval refresh را به صورت صریح تنظیم کنید. از طرف دیگر، اگر index شما request های جستجوی منظمی را تجربه کند، این رفتار پیش فرض به این معنی است که ElasticSearch هر 1 ثانیه index شما را refresh خواهد کرد. اگر بین زمانی که یک document ایندکس می‌شود و زمانی که قابل مشاهده می‌شود را افزایش دهید، افزایش index.refresh_interval به یک مقدار بزرگتر، به عنوان مثال 30s، ممکن است به بهبود سرعت indexing کمک کند.آشنایی با Auto generated IDsهنگام index کردن یک document که دارای یک id مشخص است، ElasticSearch نیاز دارد تا بررسی کند که آیا document ای با همان id در همان shard وجود دارد یا خیر، که این یک عملیات هزینه‌بر است و همین هزینه با رشد index بیشتر می‌شود. با استفاده از id های خودکار، ElasticSearch می‌تواند این بررسی را از بین ببرد، که باعث می‌شود index کردن سریع‌تر انجام شود.آشنایی با index.translog.sync_intervalاین پارامتر تعیین می‌کند که بدون توجه به عملیات write، چه مقداری translog به دیسک fsync شده و commit می‌شود. به طور پیش فرض برابر با 5 ثانیه است. مقادیر کمتر از 100 میلی‌ثانیه مجاز نیستند.آشنایی با index.translog.flush_threshold_sizeمفهوم translog تمام عملیات‌هایی را که هنوز به طور safe در Lucene ذخیره نشده‌اند را ذخیره می‌کند. اگرچه این عملیات‌ها برای خواندن در دسترس هستند، اما اگر shard متوقف شد و نیاز به recovery داشت، باید دوباره replay شوند. این تنظیمات maximum اندازه کلی این عملیات‌ها را کنترل می‌کند، تا از اینکه recovery ها زمان زیادی بگیرند جلوگیری شود. هنگامی که به maximum رسیده باشد، یک flush اتفاق خواهد افتاد، که یک Lucene commit point جدید تولید می‌کند. به طور پیش فرض برابر با 512 مگابایت است.آشنایی با Large Documentsتمامی large document ها بر network، مموری و دیسک فشار و stress بیشتری می آورند. index کردن large document ها می تواند مقدار حافظه ای را استفاده کند که ضریبی از اندازه اصلی document است. همچنین Proximity search ها (به عنوان نمونه phrase query ها) و highlighting نیز گران تر می شود زیرا هزینه آنها به طور مستقیم به اندازه document اصلی بستگی دارد.تنظیم Index Mapping Explicitlyدیتابیس ElasticSearch می تواند mapping را به صورت dynamic ایجاد کند، اما ممکن است برای تمام سناریوها مناسب نباشد. به عنوان مثال، فیلد های string پیش فرض در ElasticSearch هر دو از انواع &#34;keyword&#34; و &#34;text&#34; هستند. در بسیاری از سناریوها غیر ضروری است.آشنایی با Index Mapping — Nested Typesهمانطور که می دانید query در فیلدهای nested نسبت به فیلدهای parent document کندتر است. بازیابی فیلدهای match شده nested سرعت را کاهش می دهد. هرگاه شما فیلدی از یک document حاوی فیلدهای nested را به روز کنید، بستگی به اینکه آیا یک فیلد nested را به روز کردید یا خیر، تمام داكيومنت های Lucene باید به عنوان &#34;حذف شده&#34; علامت گذاری شوند و دوباره نوشته شوند.علاوه بر کاهش سرعت به روزرسانی ها، چنین عملیاتی garbage ای ایجاد می کند که باید توسط segment merging بعداً پاک شود.آشنایی با Index Mappingبا استفاده از فیلد _all، مقادیر تمام فیلدها به یک string تبدیل می شوند. این نسبت به سایر فیلدها نیاز به فضای بیشتر CPU و دیسک دارد. بیشتر use case ها نیازی به فیلد _all ندارند. شما می توانید چندین فیلد را با استفاده از پارامتر copy_to عمل concatenate را انجام دهید. فیلد _all به طور پیش فرض در نسخه های 6.0 و بالاتر ElasticSearch غیرفعال است.آشنایی با Leverage Index Templatesبا Index template ها تنظیماتی مانند تعداد shard ها، replica ها و mappings ها را تعریف می کنند که می توانید به صورت خودکار هنگام ایجاد index های جدید اعمال کنید. الستیک template ها را بر اساس pattern ایندکسی که با نام ایندکس مطابقت دارد به ایندکس های جدید اعمال می کند.استفاده از replica ها به منظور مقیاس پذیری و انعطاف پذیریالستیک سرچ به صورت available و scalable با نیازهای شما ساخته شده است. شما می توانید node ها را به cluster اضافه کنید تا ظرفیت آن را افزایش دهید و ElasticSearch به طور خودکار load داده ها و query شما را بین تمام node های موجود توزیع می کند. برای اینکه ElasticSearch همیشه در دسترس باشد، index های آن باید fault tolerance داشته باشند. این می تواند با استفاده از replica shard ها انجام شود.یک replica shard کپی از یک primary shard است. replica ها نسخه های اضافی از داده های شما را برای محافظت در برابر خرابی سخت افزار و افزایش ظرفیت برای ارائه request های خواندن مانند جستجو یا بازیابی یک document فراهم می کنند.آشنایی با مفهوم Shard Sizingیک shard که در ایندکس Lucene است، از file handle ها، مموری و CPU cycle ها استفاده می کند. هدف از انتخاب تعداد shard ها توزیع یکنواخت index در سراسر تمام node های داده در cluster است. با این حال، این shard ها نباید خیلی بزرگ یا خیلی زیاد باشند. یک قاعده خوب این است که سعی کنید اندازه شارد را بین 10-50 گیگابایت نگه دارید. شاردهای بزرگ می توانند باعث سختی ElasticSearch در بازیابی از خرابی شوند، اما چون هر شارد مقداری از CPU و حافظه را استفاده می کند، داشتن shard های کوچک خیلی زیاد می تواند باعث خطا های performance و out of memory شود.آشنایی با Index State Managementمفهوم ISM به شما اجازه می دهد تا policy های custom management را برای خودکار کردن task های روتین تعریف کنید و آنها را روی index ها و index pattern ها اعمال کنید. دیگر نیازی به راه اندازی و مدیریت فرآیندهای خارجی برای اجرای عملیات index نیست. یک policy شامل یک state پیش فرض و یک لیست از state ها برای انتقال بین index ها است. در هر state ای، شما می توانید یک لیست از action ها و شرایطی که این trigger را فعال می کنند تعریف کنید. یک use case معمول این است که به طور دوره ای index های قدیمی را پس از یک دوره معین حذف کنید.باتشکر ازhttps://lazypro.medium.com/best-practices-of-using-elasticsearch-2a2485a289c7</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Sun, 12 May 2024 15:37:56 +0330</pubDate></item><item><title>ترکیب vector search و filtering در ElasticSearch</title><link>https://virgool.ir/@vakily/ترکیب-vector-search-و-filtering-در-elasticsearch-l7604aisu0tx</link><description>مدل‌های زبانی بزرگ (LLM) هر روز در حال تکامل هستند و این وضعیت به گسترش جستجوی معنایی یا semantic search کمک می‌کند. LLM ها در تجزیه و تحلیل متون و آشکارسازی شباهت‌های معنایی برتری دارند. این وضعیت همچنین در موتورهای جستجو منعکس می‌شود زیرا موتورهای جستجوی معنایی می‌توانند نتایج بیشتری را برای کاربران ارائه دهند.با اینکه مدل‌های زبانی بزرگ می‌توانند نتایج نزدیک به معنا را دریافت کنند، پیاده‌سازی filter ها در نتایج جستجو برای بهبود تجربه کاربر ضروری است. به عنوان مثال، اضافه کردن filter های مبتنی بر تاریخ یا دسته‌بندی‌ها می‌تواند به تجربه جستجوی بیشتری کمک کند. بنابراین، چگونه می‌توانیم به طور موثر جستجوی معنایی را با filtering ترکیب کنیم؟بیایید ابتدا با اتصال ElasticSearch و query های اولیه جستجو شروع کنیم:from elasticsearch import Elasticsearch&#xA;import config as cfg&#xA;client = Elasticsearch(&#xA;&#39;https://localhost:9200&#39;,&#xA;ssl_assert_fingerprint=cfg.ES_FINGERPRINT,&#xA;basic_auth=(&#39;elastic&#39;, cfg.ES_PASSWORD)&#xA;)من اطلاعات لازم برای connection را از یک config file می‌خوانم، و این جزئیات به صورت خودکار زمانی که Elasticsearch برای اولین بار راه‌اندازی می‌شود، ارائه می‌شوند.[&#xA; {&#xA; &#34;title&#34;: &#34;Data Structures and Algorithms&#34;,&#xA; &#34;date&#34;: &#34;2023-08-02&#34;,&#xA; &#34;author&#34;: &#34;Emily Johnson&#34;&#xA; },&#xA; {&#xA; &#34;title&#34;: &#34;Artificial Intelligence Trends&#34;,&#xA; &#34;date&#34;: &#34;2023-08-01&#34;,&#xA; &#34;author&#34;: &#34;William Smith&#34;&#xA; },&#xA;    ...&#xA; ]مجموعه داده‌ای که در این پست استفاده خواهم کرد توسط ChatGPT تولید شده و format ای را که در بالا توضیح داده شده است، رعایت می‌کند.بیایید داده‌هایمان را با استفاده از این فایل JSON بخوانیم و یک ایندکس Elasticsearch را بر اساس این format ایجاد کنیم، سپس داده‌ها را به آن اضافه کنیم. book_mappings = {&#xA; &#34;mappings&#34;: {&#xA; &#34;properties&#34;: {&#xA; &#34;title&#34;: {&#34;type&#34;: &#34;text&#34;},&#xA; &#34;author&#34;: {&#34;type&#34;: &#34;text&#34;},&#xA; &#34;date&#34;: {&#34;type&#34;: &#34;date&#34;}&#xA;        }&#xA;    }&#xA;}&#xA;&#xA;client.indices.create(index = &#34;book_index&#34;, body=book_mappings)&#xA;&#xA;import json&#xA;with open(&#39;data.json&#39;, &#39;r&#39;) as f:&#xA;    data = json.load(f)&#xA;&#xA;for each in data:&#xA;    client.index(index=&#39;book_index&#39;, document=each)&#xA;client.indices.refresh()در مجموعه داده‌ای که ایجاد کرده‌ایم، سه فیلد وجود دارد، دو تای آنها به صورت متن و یکی به صورت تاریخ format شده‌اند. سپس، از این mapping برای ایجاد یک index استفاده می‌کنیم، که آن را “book_index” می‌نامیم. از آنجا که داده‌ها و index ما در یک format هستند، در این مرحله نیازی به پردازش اضافی نیست.بیایید با یک query شروع کنیم که تمام document های داخل index را بازیابی می‌کند:برای اعمال filtering به document های داخل index، باید پارامتر “query” را تغییر دهیم. برای جستجوی کلمات درون متن، از “match” استفاده خواهیم کرد:ما document هایی را در index لیست کردیم که کلمه “Data” در فیلد “title” آنها وجود دارد.اگر می‌خواهید filtering را بر روی چندین فیلد اعمال کنید، می‌توانید با استفاده از “bool” این کار را انجام دهید.حالا، بیایید همان index را با document vector ها ایجاد کنیم. برای این پست، من از کتابخانه Sentence-Transformers و مدل ‘all-mpnet-base-v2’ استفاده خواهم کرد. محدودیتی در استفاده از مدل وجود ندارد بنابراین می‌توانید هر مدلی که می‌خواهید را انتخاب کنید.vector_mapping = {&#xA; &#34;mappings&#34;: {&#xA; &#34;properties&#34;: {&#xA; &#34;title&#34;: {&#34;type&#34;: &#34;text&#34;},&#xA; &#34;author&#34;: {&#34;type&#34;: &#34;text&#34;},&#xA; &#34;date&#34;: {&#34;type&#34;: &#34;date&#34;},&#xA; &#34;vector&#34;: {&#xA; &#34;type&#34;: &#34;dense_vector&#34;,&#xA; &#34;dims&#34;: 768,&#xA; &#34;index&#34;: True,&#xA; &#34;similarity&#34;: &#34;dot_product&#34;&#xA;            }&#xA;        }&#xA;    }&#xA;}&#xA;&#xA;client.indices.create(index=&#39;vector_index&#39;, body= vector_mapping)در حالی که این بار “vector_index” را ایجاد می‌کنیم، یک فیلد اضافی از نوع “dense_vector” اضافه می‌کنیم و پارامترهای vector search را مشخص می‌کنیم:پارامتر “dims” بُعد بردار تولید شده به عنوان خروجی توسط مدل استفاده شده را نشان می‌دهد. پارامتر “Similarity” روش اندازه‌گیری vector similarity را تعیین می‌کند.from sentence_transformers import SentenceTransformer&#xA;model = SentenceTransformer(&#39;all-mpnet-base-v2&#39;)&#xA;&#xA;for each in data:&#xA;    each[&#39;vector&#39;] = model.encode(each[&#39;title&#39;])&#xA;    client.index(index=&#39;vector_index&#39;, document=each)&#xA;client.indices.refresh()بیایید مدل را با استفاده از کتابخانه Sentence-Transformers بارگذاری کنیم و vector ها را از بخش‌های &#34;title&#34; مجموعه داده استخراج کنیم. سپس این vector ها را به هر ورودی داده اضافه کرده و ادامه می‌دهیم تا این داده‌ها را به ایندکس &#34;vector_index&#34; اضافه کنیم.برای انجام vector search در Elasticsearch، ابتدا به یک متن query و سپس نمایش برداری متناظر آن نیاز داریم.توجه مهم: مدلی که برای به دست آوردن بردار query استفاده می‌شود باید همان مدل باشد که هنگام index کردن document ها استفاده شده است.برای انجام vector search، تابع Elasticsearch.search() از پارامتر &#34;knn&#34; استفاده می‌کند. یک نمونه از query برای &#34;knn&#34; در تصویر زیر نشان داده شده است. مقدار &#34;k&#34; نشان می‌دهد که چه تعداد نتیجه می‌خواهید بازیابی کنید، در حالی که &#34;num_candidates&#34; مشخص می‌کند که چند document برای محاسبات در pool گرفته می‌شوند. &#34;query_vector&#34; نمایش برداری از متن query است (در مورد ما &#34;HTML and CSS programming&#34;). نتایج برای query نمونه در تصویر بالا قابل مشاهده است. با اینکه هیچ یک از نتایج بازگشتی دقیقاً همان کلمات را در بر ندارند، اما با موفقیت نتایج مشابه از نظر معنایی را جمع‌آوری کرده‌اند.پس، اگر ما هم می‌خواهیم از این نتایج جستجوی معنایی به همراه filtering استفاده کنیم، چگونه باید کوئری “knn” را آماده کنیم؟ هر filter ای که اعمال می‌کنیم به عنوان یک “filter” درون پارامتر “knn” ارائه می‌شود. شما می‌توانید در اینجا هر تعداد filter ای که می‌خواهید اضافه کنید و نتایج را بر اساس این filter ها ترکیب کنید.توجه مهم: Elasticsearch پس از فرآیند vector search، عمل filtering را انجام می‌دهد، بنابراین ممکن است مواردی وجود داشته باشد که نتواند دقیقاً تعداد “k” نتایج را برگرداند. در تصویر بالا، با اینکه مقدار “k” به 5 تنظیم شده است، query تعداد 3 سند یا document را به عنوان نتیجه برگردانده است. این بخاطر آن است که در مجموعه داده‌ای که به عنوان مثال آماده شده است، فقط 3 سند معیارهای مشخص شده را برآورده می‌کنند.باتشکر ازhttps://medium.com/@fatihsati/how-to-combine-vector-search-with-filtering-in-elasticsearch-b938ec78d179</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Sun, 12 May 2024 00:33:55 +0330</pubDate></item><item><title>10 پروژه برتر NLP که باید در سال 2024 بدانید</title><link>https://virgool.ir/@vakily/10-پروژه-برتر-nlp-که-باید-در-سال-2024-بدانید-fzkqwgrkodhm</link><description>پردازش زبان طبیعی (NLP) بخشی از هوش مصنوعی پیشرفته است که به کامپیوترها یاد می دهد زبان انسان را درک کنند. در این مقاله، ما برترین ایده های پروژه های NLP را برای تمام سطوح به اشتراک خواهیم گذاشت که افراد مبتدی و متخصصان با تجربه داده می توانند از آنها برای درک بهتر و کار با زبان استفاده کنند. این پروژه ها طیف گسترده ای از تشخیص موجودیت های نامگذاری شده (NER) تا ایجاد نقل قول‌های الهام‌بخش (inspiring quotes) را پوشش می دهند. با کار بر روی این پروژه ها، می توانید از NLP برای تأثیرگذاری بر تجزیه و تحلیل و پردازش داده استفاده کنید.10 ایده برتر پروژه NLPاین پروژه‌ها طیف گسترده‌ای از برنامه‌های NLP را پوشش می‌دهند و می‌توانند به شما کمک کنند تا مهارت‌های خود را در درک و پردازش زبان انسانی با استفاده از تکنیک‌های یادگیری ماشین افزایش دهید.شماره یک: Named Entity Recognition (NER)تشخیص موجودیت نام‌گذاری‌شده (NER) یک تسک در سطح elementary در پردازش زبان طبیعی است که در آن هدف، شناسایی و طبقه‌بندی آیتم‌هایی مانند نام افراد، سازمان‌ها، مکان‌ها و تاریخ‌ها از یک متن مشخص است.هدف یا Objectiveهدف این تحقیق ایجاد یک سیستم NER است که می تواند به طور خودکار موارد نامگذاری شده را در متن شناسایی و دسته بندی کند و امکان استخراج اطلاعات مهم از داده های بدون ساختار (unstructured data) را فراهم کند.مروری بر مجموعه داده ها و پیش پردازش داده هابرای این پروژه به مجموعه داده برچسب‌گذاری شده‌ای نیاز است که حاوی متن و موجودیت‌های حاشیه‌نویسی شده (annotated entities) باشد. مجموعه داده‌های رایج برای NER شامل CoNLL-2003، OntoNotes و Open Multilingual Wordnet هستند.پیش پردازش داده شامل Tokenizingتقسیم بندی یا Tokenizing متن: متن به واحدهای کوچک‌تر و معنی‌دار مانند کلمات یا عبارات تقسیم می‌شود.تبدیل به نمایش عددی (numerical representation): token ها به اعداد تبدیل می‌شوند تا رایانه بتواند آن‌ها را پردازش کند.مدیریت نویز یا ناسازگاری در حاشیه‌نویسی‌هادستاوردهای کلیدی و یافته‌ها:سیستم تشخیص موجودیت نام‌گذاری‌شده (NER) قادر خواهد بود تا موجودیت‌های نام‌گذاری‌شده را در متن ارائه‌شده شناسایی و طبقه‌بندی کند. این سیستم می‌تواند در استخراج اطلاعات، تحلیل احساسات و سایر کاربردهای پردازش زبان طبیعی (NLP) برای کسب بینش از داده‌های بدون ساختار استفاده شود.شماره دو: Machine Translationترجمه ماشینی یکی از تسک های ضروری NLP است که به طور خودکار متن را از یک زبان به زبان دیگر ترجمه می کند و ارتباط بین زبانی (cross-lingual communication) و دسترسی (accessibility) را تسهیل می کند.هدف یا Objectiveترجمه ماشینی با هدف ترجمه یکپارچه متن از یک زبان به زبان دیگر، امکان ارتباط بین زبانی (cross-lingual communication) و دسترسی آسان را فراهم می کند.مروری بر مجموعه داده ها و پیش پردازش داده هااین پروژه به پیکره های موازی (parallel corpora) نیاز دارد که مجموعه‌ای از متون به زبان‌های مختلف با ترجمه‌های مربوطه هستند. مجموعه داده های محبوب شامل WMT، IWSLT و Multi30k است. پیش پردازش داده‌ها شامل توکن‌سازی، مدیریت تفاوت‌های خاص زبان (language-specific nuances)، و تولید جفت های ورودی-هدف (input-target pairs) برای آموزش است.دستاوردهای کلیدی و یافته‌ها:سیستم ترجمه ماشینی می‌تواند ترجمه‌های معتبری را بین چند زبان ایجاد کند، که امکان تماس بین فرهنگی (cross-cultural contact) را فراهم می‌کند و اطلاعات را برای مخاطبان در سراسر جهان در دسترس‌تر می‌سازد.شماره سه: Text Summarizationخلاصه کردن متن یک تسک مهم پردازش زبان طبیعی است که شامل ایجاد خلاصه‌های مختصر و منسجم از بخش های طولانی‌تر متن است. این امکان بازیابی و درک سریع اطلاعات را فراهم می کند و آن را برای حجم زیادی از داده های متنی ارزشمند می کند.هدف یا Objectiveهدف این پروژه توسعه یک مدل خلاصه سازی متن است که قادر به ایجاد خلاصه های آموزنده و مختصر از document های متنی طولانی است.مروری بر مجموعه داده ها و پیش پردازش داده هااین پروژه به مجموعه داده‌ای نیاز دارد که شامل مقالات یا اسنادی با خلاصه‌های تولید شده توسط انسان است. پیش‌پردازش داده‌ها شامل توکن‌سازی متن، مدیریت punctuation ها، و ایجاد جفت‌های ورودی-هدف (input-target pairs) برای آموزش است.دستاوردهای کلیدی و یافته‌ها:مدل خلاصه‌سازی متن با موفقیت خلاصه‌های مختصر و متناسب تولید خواهد کرد، که باعث بهبود کارایی بازیابی اطلاعات و بهبود تجربه کاربر هنگام مواجهه با محتوای متنی گسترده می‌شود.شماره چهار: Text Correction and Spell Checkingپروژه‌های اصلاح متن و بررسی املایی به دنبال توسعه الگوریتم‌هایی هستند که به صورت خودکار اشتباهات املایی و دستور زبانی در داده‌های متنی را اصلاح می‌کنند. این کار دقت و خوانایی محتوای نوشته شده را بهبود می‌بخشد. هدف یا Objectiveاین پروژه به دنبال ساخت یک مدل بررسی املایی و اصلاح متن است تا کیفیت محتوای نوشته شده را ارتقا دهد و ارتباط موثر را تضمین کند.مروری بر مجموعه داده ها و پیش پردازش داده هااین پروژه به مجموعه داده‌ای نیاز دارد که شامل متن با کلمات اشتباه املایی و نسخه‌های اصلاح شده متناظر است. پیش‌پردازش داده‌ها شامل رسیدگی به حروف بزرگ، نشانه‌گذاری يا punctuation ها و کاراکترهای خاص است.دستاوردهای کلیدی و یافته‌ها:مدل اصلاح متن با دقت اشتباهات املایی و دستور زبانی را شناسایی و اصلاح خواهد کرد، کیفیت محتوای نوشته شده را به طور قابل توجهی بهبود می‌بخشد.شماره پنجم: Sentiment Analysisتحلیل احساسات یکی از مهمترین تسک های NLP است که احساس بیان شده در یک متن را تعیین می‌کند، مانند اینکه آیا مثبت، منفی یا خنثی است. این مدل برای تحلیل بازخورد مشتری، نگرش‌های بازار و نظارت بر رسانه‌های اجتماعی بسیار حیاتی است.هدف یا Objectiveاین پروژه به دنبال توسعه یک مدل تحلیل احساسات است که قادر به طبقه‌بندی متن به دسته‌بندی‌های احساسی و کسب بینش از داده‌های متنی است.مروری بر مجموعه داده ها و پیش پردازش داده هابرای آموزش مدل تحلیل احساسات، نیاز به یک مجموعه داده برچسب‌دار از داده‌های متنی با برچسب‌های احساسی متناظر است. پیش‌پردازش داده‌ها شامل پاکسازی متن، توکن‌سازی و رمزگذاری (encoding) است.دستاوردهای کلیدی و یافته‌ها:مدل تحلیل احساسات به شرکت‌ها امکان می‌دهد تا نظرات و احساسات مشتریان را به طور موثر سنجیده و ارزیابی کنند، که این امر به تصمیم‌گیری مبتنی بر داده‌ها کمک می‌کند و رضایت مشتریان را افزایش می‌دهد.شماره ششم: Text Annotation and Data Labelingتفسیر متن و برچسب‌زنی داده‌ها تسک های اساسی در پروژه‌های برتر NLP هستند، زیرا شامل برچسب‌زنی داده‌های متنی برای آموزش مدل‌های یادگیری ماشینی با نظارت است. این یک گام حیاتی است تا دقت و کیفیت مدل‌های NLP را تضمین کند.هدف یا Objectiveاین پروژه به دنبال توسعه یک ابزار یا برنامه تفسیری است که به طور موثر به مفسران اجازه می‌دهد تا داده‌های متنی را برای وظایف NLP برچسب‌زنی و تفسیر کنند.مروری بر مجموعه داده ها و پیش پردازش داده هااین پروژه به مجموعه داده‌ای از داده‌های متنی که نیاز به تفسیر دارد، نیازمند است. پیش‌پردازش داده‌ها شامل ایجاد یک رابط کاربری دوستانه برای تفسیرگر و تضمین همسانی و کنترل کیفیت است.دستاوردهای کلیدی و یافته‌ها:ابزار تفسیر فرآیند برچسب‌زنی داده‌ها را ساده‌تر خواهد کرد، توسعه سریع‌تر مدل NLP را تسهیل می‌کند و دقت داده‌های برچسب‌زده شده را برای بهبود عملکرد مدل تضمین می‌کند.شماره هفت: ایجاد Chatbotsایجاد چت‌بات‌ها یک پروژه چالش‌برانگیز NLP است که شامل ساخت عوامل مکالمه‌ای بسیار پیچیده قادر به مدیریت مکالمات کاربری تعاملی و جذاب است. چت‌بات‌ها به طور انحصاری در خدمات مشتری، دستیاران مجازی و برنامه‌های مختلف دیگر استفاده می‌شوند.هدف یا Objectiveهدف از ایجاد چت‌بات‌ها ساخت عامل های هوش مصنوعی مکالمه‌ای موثر است که قادر به داشتن مکالمات تعاملی و مناسب با کاربران در چندین حوزه است.مروری بر مجموعه داده ها و پیش پردازش داده هاآموزش چت‌بات نیازمند یک مجموعه داده مکالمه‌ای است که شامل تعاملات user-bot و پاسخ‌های متناظر است. پیش‌پردازش داده‌ها شامل توکن‌سازی، رسیدگی به تاریخچه مکالمه برای پاسخ‌های آگاه از متن و پیش پردازش جفت‌های ورودی-هدف (input-target pairs) است.دستاوردهای کلیدی و یافته‌ها:چت‌بات هوش مصنوعی قصد دارد تجربه کاربر و خدمات پشتیبانی مشتری را با ساده‌سازی جریان‌های کاری و ارائه تعاملات شخصی‌سازی شده بهبود بخشد، افزایش تعامل و رضایت کاربر را افزایش می‌دهد.شماره هشت: Text-to-Speech (TTS) and Speech-to-Text (STT)متن به گفتار (TTS) و گفتار به متن (STT) اجزای مهم پردازش زبان طبیعی هستند که ارتباط بی دردسر بین انسان ها و ماشین ها را تسهیل می کنند. TTS متن نوشته شده را به صدای انسان تبدیل می کند. در مقابل، STT کلمات گفته شده را به متن نوشته شده تبدیل می کند.هدف یا Objectiveهدف از متن به گفتار (TTS) و گفتار به متن (STT) این است که یک سیستم NLP دو طرفه را طراحی کنند که بتواند متن نوشته شده را به صدای شبیه به انسان ترجمه کند و کلمات گفته شده را به متن نوشته شده تبدیل کند.مروری بر مجموعه داده ها و پیش پردازش داده هابرای TTS، مجموعه داده ای شامل متن و داده های صوتی جفت شده برای آموزش مدل لازم است. پیش پردازش داده ها شامل تبدیل متن به صدا ها و آماده سازی ویژگی های صوتی است. برای STT، مجموعه داده صوتی با ترجمه ها لازم است. پیش پردازش داده ها شامل استخراج ویژگی های مربوطه از داده های صوتی است.دستاوردهای کلیدی و یافته‌ها:سیستم NLP دو طرفه (bidirectional NLP system) امکان تعامل بین انسان ها و ماشین ها را فراهم می کند. TTS صدایی شبیه به انسان خواهد ساخت، که رابط کاربری را جذاب تر و قابل دسترس تر می کند. STT اجازه خواهد داد تا ترجمه خودکار گفتار انجام شود، که امکان پردازش و تجزیه و تحلیل کارآمد اطلاعات گفته شده را فراهم می کند. دقت و عملکرد سیستم تجربه کاربر را بهبود بخشیده و استفاده از برنامه های مبتنی بر صدا را گسترش خواهد داد.شماره نه: Emotion Detectionتشخیص احساسات یک تسک ارزشمند NLP است که شامل شناخت و درک احساسات منتقل شده از طریق متن است. کاربردهای آن شامل تحلیل احساسات، خدمات مشتری و تعامل باز انسان-کامپیوتر (open human-computer interaction) است.هدف یا Objectiveاین پروژه به دنبال ایجاد یک سیستم NLP است که قادر به درک احساساتی مانند خوشحالی، غم و خشم، از جمله دیگران از کلمات گفته شده یا نوشته شده است.مروری بر مجموعه داده ها و پیش پردازش داده هابرای آموزش مدل تشخیص احساسات، مجموعه داده متن یا گفتار مشخص شده با احساسات برچسب زده شده لازم است. پیش پردازش داده ها شامل استخراج ویژگی ها و آماده سازی داده ها برای طبقه بندی احساسات است.مدل تشخیص احساسات به درک احساسات کاربر کمک خواهد کرد، امکان پاسخ های متناسب با حالات عاطفی کاربران را فراهم می کند و بهبود برنامه های مختلف NLP را امکان پذیر می سازد.شماره ده: Inspiring Quote Generatorتولید کننده نقل قول الهام بخش یا همان Inspiring Quote Generator یک پروژه خلاقانه NLP است که مدلی را می سازد که بر اساس کلمات کلیدی یا موضوعات ورودی، نقل قول های انگیزشی و بلند کننده تولید می کند.هدف یا Objectiveاین پروژه به دنبال توسعه یک مدل NLP برای تولید نقل قول های الهام بخش برای بالابردن انگیزه کاربران است.مروری بر مجموعه داده ها و پیش پردازش داده هاآموزش مدل تولید کننده نقل قول نیازمند یک مجموعه داده شامل نقل قول ها با کلمات کلیدی یا موضوعات مرتبط است. پیش پردازش داده ها شامل tokenization و آماده سازی داده ها برای آموزش مدل تولید زبان است.دستاوردهای کلیدی و یافته‌ها:این مدل به کاربران نقل قول های انگیزشی شخصی می دهد، مثبت بودن را ترویج می کند و می تواند در برنامه ها و پلتفرم های مختلف گنجانده شود.باتشکر ازhttps://www.analyticsvidhya.com/blog/2023/08/nlp-projects/</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Mon, 06 May 2024 16:33:18 +0330</pubDate></item><item><title>بررسی LDAP با Django</title><link>https://virgool.ir/@vakily/بررسی-ldap-با-django-oecjr1gh1crl</link><description>در این مقاله، نحوه اتصال و authenticate یک برنامه Django با یک سرور LDAP یا Lightweight Directory Access Protocol را بررسی خواهیم کرد. فریم ورک Django با یک بک‌اند authentication پیش‌فرض برای authenticate کردن اطلاعات کاربری با database ارائه شده همراه است. بنابراین به جای آن، Django App خود را به سرور LDAP وصل می‌کنیم تا کاربر با Active Directory خودش authenticate شود.پیاده سازی LDAPما از django-auth-ldap استفاده خواهیم کرد، یک کتابخانه open-source عالی برای Django است. این کتابخانه با یک  LDAP Authentication Backend  داخلی عرضه می‌شود که authenticate کردن کاربران با سرور LDAP را بسیار آسان می‌کند.سپس، یک login/logout REST API  در django-rest-framework با استفاده از SessionAuthentication  فریمورک rest برای authenticate کاربران با سرور LDAP ایجاد خواهیم کرد.در فایل settings.py تنظیمات را اضافه نمایید.مسیر uri سرور LDAP را اضافه کنید.AUTH_LDAP_SERVER_URI = &#34;ldap://test.example.com:389&#34;اکنون admin سرور LDAP را اضافه کنید تا بتوانید عملیات جستجوی مختلف کاربر را انجام دهید.AUTH_LDAP_BIND_DN = &#34;cn=admin,dc=example,dc=com&#34;&#xA;AUTH_LDAP_BIND_PASSWORD = &#34;test@1234&#34;اکنون مسیر جستجوی کاربران در دایرکتوری LDAP را اضافه کنید، یعنی در کدام پوشه باید LDAP برای کاربران جستجو کند. آرگومان ldap.SCOPE_SUBTREE به LDAP می گوید که در همه زیرپوشه های directory کاربران جستجو کند.import ldap&#xA;from django_auth_ldap.config import LDAPSearch&#xA;AUTH_LDAP_USER_SEARCH = LDAPSearch(&#34;OU=users,DC=example,DC=com&#34;,&#xA;                                   ldap.SCOPE_SUBTREE,&#xA;                                   &#34;(uid=%  (user)s)&#34;)اکنون mapping را اضافه کنید تا ویژگی‌های مدل User جنگو را از LDAP directory پر کنید. پس از authentication موفقیت‌آمیز از سرور LDAP، مدل User جنگو با ویژگی‌های زیر پر می‌شود.AUTH_LDAP_USER_ATTR_MAP = {&#xA;&#34;first_name&#34;: &#34;givenName&#34;,&#xA;    &#34;last_name&#34;: &#34;sn&#34;,&#xA;    &#34;email&#34;:&#34;mail&#34;&#xA;}   حالا LDAP authentication backend را قبل از ModelBackend اضافه کنید تا ابتدا از طریق LDAP عمل authentication را به جای django Model Backend پیش فرض انجام دهد.AUTHENTICATION_BACKENDS = (&#xA;    &#34;django_auth_ldap.backend.LDAPBackend&#34;,&#xA;    &#34;django.contrib.auth.backends.ModelBackend&#34;,&#xA;)در نهایت، SessionAuthentication را به DEFAULT_AUTHENTICATION_CLASSES اضافه کنید.REST_FRAMEWORK = {&#xA;    &#39;DEFAULT_AUTHENTICATION_CLASSES&#39;: (&#xA;        &#39;rest_framework.authentication.SessionAuthentication&#39;,&#xA;    ),&#xA;}درباره Login APIدر این قسمت، ابتدا authentication_classes را روی empty تنظیم می کنیم زیرا برای login api به pre-authentication نیاز نداریم. ما از توابع پیش فرض django یعنی authenticate() و login() استفاده خواهیم کرد.هنگامی که تابع authenticate() اجرا می شود، django به طور خودکار ابتدا LDAPBackend را برای authenticate کاربران انتخاب می کند و در صورت عدم موفقیت، به سراغ backend بعدی یعنی ModelBackend می رود.from django.contrib.auth import authenticate, login, logout&#xA;from rest_framework.permissions import IsAuthenticated&#xA;from rest_framework.response import Response&#xA;from rest_framework.views import APIView&#xA;class LDAPLogin(APIView):&#xA;    &#34;&#34;&#34;&#xA;    Class to authenticate a user via LDAP and&#xA;    then creating a login session&#xA;    &#34;&#34;&#34;&#xA;    authentication_classes = ()&#xA;    def post(self, request):&#xA;        &#34;&#34;&#34;&#xA;        Api to login a user&#xA;        :param request:&#xA;        :return:&#xA;        &#34;&#34;&#34;&#xA;        user_obj = authenticate(username=request.data[&#39;username&#39;],&#xA;                                password=request.data[&#39;password&#39;])&#xA;        login(request, user_obj)&#xA;        data={&#39;detail&#39;: &#39;User logged in successfully&#39;}&#xA;        return Response(data, status=200)نحوه Logout APIدر اینجا، ما permission_classes را روی IsAuthenticated تنظیم می‌کنیم تا فقط فردی که وارد سیستم شده است بتواند درخواست logout را ارسال کند.class LDAPLogout(APIView):&#xA;    &#34;&#34;&#34;&#xA;    Class for logging out a user by clearing his/her session&#xA;    &#34;&#34;&#34;&#xA;    permission_classes = (IsAuthenticated,)&#xA;&#xA;    def post(self, request):&#xA;        &#34;&#34;&#34;&#xA;        Api to logout a user&#xA;        :param request:&#xA;        :return:&#xA;        &#34;&#34;&#34;&#xA;        logout(request)&#xA;        data={&#39;detail&#39;: &#39;User logged out successfully&#39;}&#xA;        return Response(data, status=200)نتیجه گیریتکنیک LDAP authentication مشکل بزرگی را در ایجاد حساب های جدید هنگام ورود به یک وب سایت جدید و به خاطر سپردن چندین مجموعه از login credential ها را حل می کند.امیدوارم این مقاله نکاتی را در مورد authentication از طریق LDAP و مزایای مربوط به آن ارائه کرده باشد.باتشکر ازhttps://medium.com/@itsayushbansal/ldap-authentication-with-django-a2b4f00c9a04</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Fri, 03 May 2024 22:55:41 +0330</pubDate></item><item><title>بررسی Kafka با KRaft mode - قسمت اول</title><link>https://virgool.ir/@vakily/بررسی-kafka-با-kraft-mode-قسمت-اول-zoziit5bvqjv</link><description>آپاچی کافکا یک پلتفرم event streaming به صورت توزیع شده است که توسط هزاران شرکت برای pipelines های داده با عملکرد بالا، تجزیه و تحلیل به صورت streaming، یکپارچه سازی داده ها و برنامه های کاربردی حیاتی یا mission-critical applications استفاده می شود.مفهوم KRaft یا Kafka Raft، پروتکل اجماعی یا consensus protocol است که در Kafka برای حذف وابستگی به ZooKeeper برای مدیریت metadata معرفی شده است. این تغییر باعث ساده‌سازی معماری Kafka شده و مسئولیت مدیریت metadata را به خود Kafka می‌سپارد.در این مقاله قصد دارم به نحوه استقرار و اجرا آن با استفاده از Docker بپردازم.جهت بررسی آن به دنبال فایلی برای Docker Compose می‌گشتم که به من امکان اجرای Kafka در حالت Kraft را بدهد. اما متاسفانه، تمام دستورالعمل‌هایی که پیدا کردم شامل انجام چندین مرحله بودند، از جمله ایجاد یک cluster ID، فرمت کردن log ها، و در نهایت راه‌اندازی container ها.آیا امکان اجرای Kafka در حالت Kraft با تنها یکبار اجرای Docker Compose وجود دارد؟زمانی که Kafka را بدون Zookeeper اجرا می‌کنیم، باید موارد زیر را مشخص کنیم:ویژگیprocess.roles - می‌تواند broker يا controller یا هر دو باشد.ویژگیcontroller.quorum.voters - آدرس‌هایی به فرمت nodeid@servername:portاست  که جهت اجماع (consensus) رأی می‌دهند. این تنظیم جایگزین تنظیم قدیمیzookeeper.connect می‌شود.ویژگیnode.id - همان node ID مرتبط با role هایی است که process ایفا می‌کند.قبل از شروع، clusterIdباید تولید شود و storage باید با یک ابزار خاص فرمت شود.برای تولید uuid می توانیم از اسکریپت زیر استفاده کنیم:kafka-storage.sh random-uuidو command جهت format کردن به صورت زیر است:kafka-storage.sh formatشناسه خوشه یا cluster ID باید فقط یک بار تولید شود و بین همه container ها به اشتراک گذاشته شود. علاوه بر این، از همان cluster ID باید برای format کردن log ها استفاده شود.لذا  Docker Compose ما شامل چهار container خواهد بود که سه container اول به عنوان broker های Kafka عمل می کنند. هر یک از این broker ها دو نقش broker و controller را به طور همزمان بر عهده خواهند گرفت. container چهارم، cluster ID را در یک فایل تولید می کند و سپس خارج می شود.این container برای broker به شکل زیر است:kafka1: image: confluentinc/cp-kafka:7.3.3 hostname: kafka1 container_name: kafka1 ports: - &#34;39092:39092&#34; environment: KAFKA_LISTENERS: BROKER://kafka1:19092,EXTERNAL://kafka1:39092,CONTROLLER://kafka1:9093 KAFKA_ADVERTISED_LISTENERS: BROKER://kafka1:19092,EXTERNAL://kafka1:39092 KAFKA_INTER_BROKER_LISTENER_NAME: BROKER KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,BROKER:PLAINTEXT,EXTERNAL:PLAINTEXT KAFKA_PROCESS_ROLES: &#39;controller,broker&#39; KAFKA_NODE_ID: 1 KAFKA_CONTROLLER_QUORUM_VOTERS: &#39;1@kafka1:9093,2@kafka2:9093,3@kafka3:9093&#39; KAFKA_LOG_DIRS: &#39;/tmp/kraft-combined-logs&#39; volumes: - ./scripts/update_run.sh:/tmp/update_run.sh - ./clusterID:/tmp/clusterID command: &#34;bash -c &#39;/tmp/update_run.sh &amp;&amp; /etc/confluent/docker/run&#39;&#34;این container دارای دو volume است:اول: clusterID - این همان دایرکتوری است که clusterID در آن تولید می شود.دوم: update_run.sh - اسکریپتی است که منتظر می ماند تا clusterID در دسترس باشد و سپس فرآیند format کردن را اجرا می کند.در قسمت زير conainer برای تولید id مشخص شده است:kafka-gen: image: confluentinc/cp-kafka:7.3.3 hostname: kafka-gen container_name: kafka-gen volumes: - ./scripts/create_cluster_id.sh:/tmp/create_cluster_id.sh - ./clusterID:/tmp/clusterID command: &#34;bash -c &#39;/tmp/create_cluster_id.sh&#39;&#34;این conainer به سادگی بررسی می کند که آیا cluster ID از قبل موجود است یا خیر. اگر موجود نباشد، یک مورد جدید ایجاد می کند.فایل compose نهایی را می توانید از اینجا ببینید.دور زدن تحریم های Dockerیکی از ساده ترین راه های آن استفاده از docker.arvancloud.ir است. می توانید آن را پشت هر آدرس image قرار دهید تا با سرعت بالا image ها را دریافت نمایید.یعنی:image: docker.arvancloud.ir/confluentinc/cp-kafka:7.3.3اتصال به kafka از طریق Offset Explorerبرای اتصال تنها کافی است در تنظيمات kafka برای EXTERNAL در KAFKA_ADVERTISED_LISTENERS مقدار localhost را قرار دهید.به عنوان مثال برای container کافکا اولی:KAFKA_ADVERTISED_LISTENERS: BROKER://kafka1:19092,EXTERNAL://localhost:39092باتشکر ازhttps://kafka.apache.org/https://docs.confluent.io/platform/current/kafka-metadata/kraft.htmlhttps://github.com/katyagorshkova/kafka-krafthttps://medium.com/@katyagorshkova/docker-compose-for-running-kafka-in-kraft-mode-20c535c48b1ahttps://www.arvancloud.ir/fa/dev/dockerhttps://www.kafkatool.com/index.html</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Mon, 22 Apr 2024 14:26:28 +0330</pubDate></item><item><title>شناسایی 5 گروه برتر تبلیغاتی یک مجموعه داده</title><link>https://virgool.ir/@vakily/شناسایی-5-گروه-برتر-تبلیغاتی-یک-مجموعه-داده-vkjd2dvirpwt</link><description>در این نوشته قصد داریم با بررسی یک دیتاست، 5 گروه برتر تبلیغاتی آن را بدست بیاوریم.برای این منظور در محیط توسعه، ابتدا دیتاست را می خوانیم.import warnings&#xA;warnings.simplefilter(&#39;ignore&#39;)&#xA;&#xA;import pandas as pd&#xA;import numpy as np&#xA;import seaborn as sns&#xA;import matplotlib.pyplot as plt&#xA;from pandas.plotting import parallel_coordinates&#xA;&#xA;%matplotlib inline&#xA;&#xA;data = pd.read_csv(&#39;./data/ad_table.csv&#39;, parse_dates=[&#39;date&#39;])&#xA;data.tail(20)حال می بایست درآمد را از هزینه کم کنیم تا سود بدست آید.data[&#39;profit&#39;] = data[&#39;total_revenue&#39;] - data[&#39;avg_cost_per_click&#39;] * data[&#39;clicked&#39;]&#xA;data.head()برای شناسایی 5 گروه برتر تبلیغاتی، معیارهای مختلفی مانند میانگین نرخ کلیک یا میانگین نرخ تبدیل وجود دارد. در اینجا، از آنجایی که اطلاعات درآمد و هزینه داده شده است، ما به سادگی از سود خالص به ازای هر تبلیغ داده شده برای یافتن 5 گروه برتر تبلیغاتی استفاده می کنیم.def unit_profit(df):&#xA;    &#34;&#34;&#34; function to calculate the unit profit &#34;&#34;&#34;&#xA;    profit = df[&#39;profit&#39;].sum()&#xA;    shown = df[&#39;shown&#39;].sum()&#xA;    val = profit / shown&#xA;    return val&#xA;grouped = data.groupby(&#39;ad&#39;).apply(unit_profit).reset_index()&#xA;grouped = grouped.rename(columns={0: &#39;unit_profit&#39;})&#xA;grouped = grouped.sort_values(by=&#39;unit_profit&#39;, ascending=False)&#xA;grouped.head(10)بر اساس محاسبات بالا، می‌توانیم آن ها را مشاهده کنیم: ad_group_16، ad_group_2، ad_group_14، ad_group_31، ad_group_27.همچنین می توانیم از طریق نمودار زیر وضعیت نقاط داده را با توجه به ابعاد مختلف مشاهده نماییم.classes=[&#39;ad_group_16&#39;, &#39;ad_group_2&#39;, &#39;ad_group_14&#39;, &#39;ad_group_31&#39;, &#39;ad_group_27&#39;]&#xA;features=[&#39;shown&#39;, &#39;clicked&#39;, &#39;converted&#39;, &#39;avg_cost_per_click&#39;,  &#39;ad&#39;]&#xA;&#xA;plt.figure(figsize=(15,8))&#xA;visualizer = pd.plotting.radviz(dd[features], &#39;ad&#39;, colormap=plt.get_cmap(&#34;Set2&#34;))&#xA;plt.legend(bbox_to_anchor=(1.0, 1.0))</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Sun, 27 Mar 2022 20:25:36 +0430</pubDate></item><item><title>تجزیه و تحلیل داده های کیفی</title><link>https://virgool.ir/@vakily/تجزیه-و-تحلیل-داده-های-کیفی-vripb0wgperj</link><description>بیایید با آنچه که نمودار های affinity به ما کمک می کنند شروع کنیم:1. آنها به درک انواع داده ها (نظر کاربران/بازخورد ها، حقایق، مسائل و ... ) کمک می کنند.2. اطلاعات را به گونه ای گروه بندی می کنند که بتوانید تصمیمات تجاری را بر اساس آنها اتخاذ کنید.طراحان تجربه کاربری برای درک چندین چیز مانند نقاط درد کاربر (user’s pain points)، نیازها و ترجیحات آنها استفاده می کنند و به آنها کمک می کند فرصت ها را نیز شناسایی کنند. این یک تمرین است که با استفاده از sticky note ها، marker ها و تخته انجام می شود.در این مقاله بر روی نمودار Affinity از دیدگاه یک مدیر کسب و کار تمرکز می کنیم و اینکه چگونه مدیر می تواند از داده های کیفی بینش کسب کند.بیایید یک مورد فرضی کوچک اما کامل را برای درک اهمیت و کاربرد تکنیک دیاگرام Affinity در نظر بگیریم.مثال: شما مالک هتل هند بیزینس (Hind Business Hotel) هستید و از 20 سال گذشته این هتل را با موفقیت اداره می کنید. معمولاً ضریب اشغال (occupancy rate) هتل شما در حدود 90٪ باقی می ماند اما اخیراً این میزان در یک سال گذشته به 75٪ کاهش یافته است. مهمانان شما عمدتاً مهمانان تکراری هستند که در فواصل زمانی معین به هتل شما سفر می کنند و اقامت می کنند. شما می خواهید بفهمید که دلایل این افت چیست. شما به عنوان مالک هتل می خواهید مشکلات اساسی را که میهمانان در طول اقامت با آن مواجه هستند پیدا کنید.شما از کارمند خود می خواهید فهرستی از نظرات مهمانان در 60 روز گذشته را تهیه کند. او به شما کمک می کند تا همه نظرات منفی را فیلتر کنید و به اشتراک بگذارید.اکنون، بررسی ها را تحت عناوین یا گروه های مختلف دسته بندی کنید. این گروه ها اساسا مجموعه ای از دامنه وسیع تری از بررسی هستند. در حالت ایده آل نباید بیش از 8 تا 10 گروه ایجاد شود.به اسکرین شات بالا توجه کنید. همه شکایات را در این 8 دسته طبقه بندی کرده ایم. مجموع هر دسته، یعنی تعداد 1 ها در هر دسته را محاسبه کنید.در مرحله بعد، جدولی را مطابق جدول زیر ایجاد کنید که تعداد (count) و مقدار cumulative را از نظر دسته نشان می دهد.بینش ها یا Insight های بدست آمده از تجزیه و تحلیلحدود 80 درصد از مسائل را می توان تنها با تمرکز بر 4 چیز حل کرد. اتاق ها و امکانات آن (Rooms and its facilities) بیشترین سهم را در این رقم 80 درصدی دارند. حتی اگر فقط اتاق ها و امکانات آن را تعمیر کنیم، می توانیم نظرات منفی را به میزان قابل توجهی کاهش دهیم.به عنوان مالک می خواهیم بفهمیم که چه مشکلی در اتاق و امکانات آن رخ داده است و آیا مشکلی رایج در اتاق ها وجود دارد که به دلیل آن افراد زیادی درباره آنها نظر منفی می دهند؟ همچنین ممکن است بخواهیم نظرات مثبت را به طور مشابه تجزیه و تحلیل کنیم تا ببینم آیا نتایجی که می‌گیرم درست هستند یا خیر.برای دسترسی به نمونه فایل اکسل اینجا را کلیک کنید.منبع</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Sat, 26 Mar 2022 15:48:26 +0430</pubDate></item><item><title>SQL Window Functions: The Intuitive Guide</title><link>https://virgool.ir/@vakily/sql-window-functions-the-intuitive-guide-afxw8fqpju6d</link><description>در این نوشته هدف اصلی، درک مفاهیم اساسی window function ها و اعمال آنها در گردش کار SQL است. window function ها چیزی بیش از FOPO (Function Over PartitionBy OrderBy) نیستند. در اینجا یک طرح کلی از آنچه در این مقاله پوشش داده خواهد شد، آمده است.The GROUP BYThe Window Function — 4 Major Components (The FOPO)The func() OVER ()The PARTITION BYThe ORDER BYThe PARTITION BY &amp; ORDER BYSummaryAppendixThe GROUP BYاگر درک خوبی از GROUP BY دارید، می توانید مفهوم window function ها به راحتی درک کنید. به طور خلاصه، GROUP BY یک جدول را به ردیف های کمتری متراکم می کند یا ردیف های منحصر به فرد را خروجی می گیرد. هنگام گروه بندی بر اساس یک ستون، کوئری SQL یک سطر را برای هر مقدار متمایز یافت شده تحت آن ستون خروجی می دهد. در گروه بندی چندین ستونه، خروجی از ترکیبات منحصر به فرد ستون های مشخص شده (با / بدون) برخی aggregate function ها تشکیل می شود. در اینجا مثالی آورده شده است.در این جدول product_orders، هر order_id به تمام آیتم های محصول (product_name) خریداری شده توسط مشتری پیوست می شود.ابتدا order_id به عنوان ستون GROUP BY تعیین می شود.دوم، مقادیر مربوط به order_id با استفاده از تابع تجمعی SUM در یک مقدار (total_amount) جمع می‌شوند.اکنون، بیایید نگاهی عمیق‌تر به مکانیزم window function ها بیندازیم.4 کامپونت اصلی window function ها - The FOPOابتدا، کامپوننت تابع یا function، رفتار داده ها را تعیین می کند. برای مثال، می‌توانیم بر اساس یک ستون (به عنوان مثال، DENSE_RANK) رتبه‌بندی کنیم یا سطل‌هایی (bin هایی) با اندازه مساوی ایجاد کنیم (مانند NTILE). window function های موجود در Postgres را اینجا بررسی کنید. aggregate function ها (به عنوان مثال، SUM، COUNT، AVG، و غیره) را می توان به عنوان window function ها نیز استفاده کرد - در اینجا فهرست شده است.دوم، کاربرد OVER این است که می تواند همه چیز را کنار هم نگه دارد. توابع بالا با استفاده از عبارت OVER برای ایجاد window function ها فراخوانی یا فعال می شوند.سوم، مشابه GROUP BY، عبارت PARTITION BY شبیه یک subgroup-by است. به جای جمع کردن (collapsing) مجموعه داده، PARTITION BY در واقع subgroups/blocks/partitions ها را بر اساس ستون یا ستون های مشخص شده ایجاد می کند.در نهایت، عبارت ORDER BY داده ها را دوباره بر اساس ستون یا ستون های مشخص شده مرتب می کند.بر اساس لول رفتار مورد نیاز برای transform دیتا، نیازی به استفاده از همه کامپوننت ها نیست، به جز OVER. (به یاد داشته باشید: عبارت OVER باعث فراخوانی window function ها می شود و همچنین aggregate function ها را قادر می سازد تا به window function ها تبدیل شوند.) در اینجا موارد استفاده وجود دارد.func() OVER ()func(&lt;column, integer value&gt;) OVER ()func() OVER (PARTITION BY &lt;column(s)&gt;)func(&lt;column, integer value&gt;) OVER (PARTITION BY &lt;column(s)&gt;)func() OVER (PARTITION BY &lt;column(s)&gt; ORDER BY &lt;column(s)&gt;)func(&lt;column, integer value&gt;) OVER (PARTITION BY &lt;column(s)&gt; ORDER BY &lt;column(s)&gt;)The func() OVER ()روش OVER () بدون تعریف PARTITION BY (و/یا) ORDER BY ، تابع را در کل مجموعه داده اعمال می کند. این رویکرد به خوبی با aggregate function ها جفت می شود. یکپارچگی جدول یا مجموعه داده حفظ می شود در حالی که یک تابع برای محاسبه یک مقدار با استفاده از تمام ردیف ها اعمال می شود.در این مثال، سه aggregate function با عبارت OVER جفت می‌شوند تا سه window function ایجاد کنند که با total_amount، total_count و total_mean نمایش داده می‌شوند. برای مثال total_amount تمام مقادیر زیر ستون amount را جمع می‌کند و مجموع جدید در هر ردیف ظاهر می‌شود. همین منطق برای total_count و total_mean صدق می کند. این setup به محاسبه درصد کل و ایجاد نسبت‌هایی در برابر مقدار کل یا آماری مانند میانگین کمک می‌کند.SELECT &#xA;  t1.*,&#xA;  SUM(t1.amount) OVER () AS total_amount,&#xA;  COUNT(*) OVER () AS total_count,&#xA;  AVG(t1.amount) OVER () AS total_mean&#xA;FROM orders t1;در نتیجه، مقادیر window function ها در ایجاد معیارهای استاندارد برای مقایسه آسان در میان مجموعه داده مفید هستند. اولین بلوک خاکستری برجسته، مقادیر کل را در مثال ارائه شده در زیر نشان می دهد، در حالی که بلوک دوم حاوی معیارهایی است که داده ها را توصیف می کند.SELECT &#xA;  t1.order_id,&#xA;  t1.order_date,&#xA;  -- aggregate functions + OVER clause = window functions&#xA;  SUM(t1.amount) OVER () AS total_amount,&#xA;  ROUND(AVG(t1.amount) OVER (), 2) AS avg_order_size,&#xA;  SUM(t1.num_product_items) OVER () AS total_product_items,&#xA;  COUNT(*) OVER () AS total_count,&#xA;  -- create ratios and % of total using values from window functions&#xA;  ROUND(1.0 * t1.amount / SUM(t1.amount) OVER (), 4) AS percent_amount,&#xA;  ROUND(1.0 * t1.num_product_items / SUM(t1.num_product_items) OVER (), 4) AS &#xA;ercent_product_items&#xA;FROM orders t1;The PARTITION BYهمانطور که قبلاً اشاره کردم، PARTITION BY مشابه GROUP BY است. مانند GROUP BY، با تعریف ستون یا ستون ها PARTITION BY شروع کنید. هنگامی که زیرگروه ها تعریف شدند، عبارت OVER تابع را فراخوانی یا فعال می کند تا منطق خود را در هر زیرگروه اجرا کند. برخلاف GROUP BY، بند PARTITION BY جدول را فشرده نمی کند. در عوض، یکپارچگی جدول را حفظ می کند در حالی که خروجی را به عنوان یک ستون اضافه می کند.SELECT&#xA;  user_id,&#xA;  order_id,&#xA;  product_name,&#xA;  amount,&#xA;  NTILE(3) OVER (PARTITION BY order_id) AS ntile_by_order_id,&#xA;  FIRST_VALUE(amount) OVER (PARTITION BY order_id) AS first_amount_value_by_order_id,&#xA;  COUNT(*) OVER (PARTITION BY order_id) AS count_by_order_id,&#xA;  SUM(amount) OVER (PARTITION BY order_id) AS sum_by_order_id,&#xA;  ROUND(AVG(amount) OVER (PARTITION BY order_id), 4) AS avg_amount_by_order_id&#xA;FROM product_orders;برای مثال، با استفاده از جدول product_orders، عبارت PARTITION BY روی ستون order_id است. علاوه بر این، تعداد زیر گروه ها با تعداد منحصر به فرد order_id تعریف می شود. در این مورد، آن عدد، سه است.در NTILE : NTILE(3) برابر با تعداد bin ها است و PARTITION BY زیر گروه ها (یا پارتیشن ها) را تعیین می کند که در آن هر زیر گروه به سه bin تقسیم می شود.در FIRST_VALUE: تابع اولین مقدار یا ردیف را در زیرگروه تعریف شده را خروجی می دهد.در COUNT: تعداد ردیف های هر زیر گروه تعریف شده را می شمارد.در SUM: مقادیر (مثلاً amount) را در هر زیرگروه جمع می کند.در AVG: میانگین هر زیرگروه تعریف شده را محاسبه می کند.در خروجی، بلوک های خاکستری مشخص شده زیر زیرگروه های تعریف شده را با عبارت PARTITION BY و ایجاد ستون های جدید توسط window function ها را نشان می دهند.The ORDER BYعبارت ORDER BY هنگام رتبه بندی یا مرتب سازی داده ها استفاده می شود. این می تواند یک عبارت مستقل در window function ها باشد یا با عبارت PARTITION BY جفت شود. گاهی اوقات، فقط استفاده از عبارت ORDER BY مناسب تر خواهد بود، که امکان رتبه بندی یا ترتیب کل مجموعه داده را فراهم می کند. به عنوان مثال:SELECT&#xA;  order_id,&#xA;  amount,&#xA;  num_product_items,&#xA;  -- ranking by num_product_items&#xA;  ROW_NUMBER() OVER (ORDER BY num_product_items) AS row_num_by_items,&#xA;  RANK() OVER (ORDER BY num_product_items) AS rank_by_items,&#xA;  DENSE_RANK() OVER (ORDER BY num_product_items) AS dense_rank_by_items,&#xA;  -- ranking by amount&#xA;  ROW_NUMBER() OVER (ORDER BY amount) AS row_num_by_amount,&#xA;  RANK() OVER (ORDER BY amount) AS rank_by_amount,&#xA;  DENSE_RANK() OVER (ORDER BY amount) AS dense_rank_by_amount&#xA;FROM orders;استفاده از عبارت ORDER BY در توابع رتبه بندی، view مرتبی را بر اساس مقادیر یافت شده در ستون num_product_items و amount ایجاد می کند. تفاوت بین توابع رتبه بندی در ناحیه پررنگ نارنجی زیر نشان داده شده است. یادآوری: عبارت ORDER BY به ترتیب صعودی (ASC) تنظیم شده است. برای نزولی، باید با DESC نشان داده شود (به عنوان مثال، ORDER BY amount DESC).در ROW_NUMBER(): این تابع بدون توجه به مقادیر تکراری در ستون، به ترتیب با صعود یا نزول رتبه بندی می کند.در RANK(): تابع به صورت متوالی با افزایش یا نزول رتبه بندی می کند، اما زمانی که مقادیر تکراری وجود داشته باشد، گپ هایی وجود خواهند داشت. به عنوان مثال، در num_product_items، دو مورد از شماره 1 وجود دارد. بنابراین، تابع هر دو را در رتبه 1 قرار می دهد (زیر rank_by_items). در مرحله بعد، دو مورد از 2 در زیر num_product_items وجود دارد، و تابع اینها را به عنوان 3 رتبه بندی می کند.در ()DENSE_RANK: این تابع مانند تابع RANK() است اما رد نمی شود و شکاف یا گپی را ایجاد نمی کند. برخلاف ROW_NUMBER()، که در آن هر ردیف بدون توجه به مقادیر تکراری با یک رتبه منحصر به فرد مشخص می‌شود، DENSE_RANK() همان رتبه را برای مقادیر تکراری بدون شکاف اعمال می‌کند.The PARTITION BY &amp; ORDER BYپس از بررسی مکانیزم  PARTITION BY و ORDER BY به طور جداگانه، جفت کردن این دو کامپوننت مرحله بعدی است. PARTITION BY بر اساس ستون یا مجموعه ای از ستون های انتخابی، زیر گروه ها (یا پارتیشن ها) را ایجاد می کند. ORDER BY داده ها را به ترتیب صعودی یا نزولی سازماندهی می کند. من جفت شدن این مؤلفه ها را با استفاده از جدول product_orders نشان خواهم داد.در این مثال، من از 9 window function برای نشان دادن جفت شدن PARTITION BY و ORDER BY استفاده می کنم. در این مرحله، اگر درک کاملی از هر کامپوننت دارید، این باید ساده باشد. شرح هر window function ای برای Postgres در اینجا موجود است.در این کوئری SQL، تمام window function ها از order_id در عبارت PARTITION BY استفاده می کنند. تعداد order_id های یکتا برابر با تعداد زیر گروه ها است و ستون ORDER BY داده های هر زیرگروه را مرتب می کند.SELECT&#xA;  user_id,&#xA;  order_id,&#xA;  product_name,&#xA;  amount,&#xA;  -- rank items within the order by amount&#xA;  ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY amount DESC) AS row_num,&#xA;  -- rank items within the order by amount and highlight same values with same rank&#xA;  DENSE_RANK() OVER (PARTITION BY order_id ORDER BY amount DESC) AS dense_rnk,&#xA;  -- understand the percentile ranking of items in terms of amount within the order&#xA;  PERCENT_RANK() OVER (PARTITION BY order_id ORDER BY amount) AS percent_rnk,&#xA;  -- what is the first product_name within the order based on items being ordered by price ascending?&#xA;  FIRST_VALUE(product_name) OVER (PARTITION BY order_id ORDER BY amount RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS first_val,&#xA;  -- what is the last product_name within the order based on items being ordered by price ascending?&#xA;  LAST_VALUE(product_name) OVER (PARTITION BY order_id ORDER BY amount RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_val,&#xA;  -- create three bins within the order by bucketing items based on amount ascending&#xA;  NTILE(3) OVER (PARTITION BY order_id ORDER BY amount) AS ntile_bin,&#xA;  -- what is the second product_name within the order ordered by amount?&#xA;  NTH_VALUE(product_name, 2) OVER (PARTITION BY order_id RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS nth_val,&#xA;  -- grab the amount of an item that immediately precedes the current item within the order ordered by amount&#xA;  LAG(amount) OVER (PARTITION BY order_id ORDER BY amount) AS lag_val,&#xA;  -- grab the amount of an item that immediately following the current item within the order ordered by amount&#xA;  LEAD(amount) OVER (PARTITION BY order_id ORDER BY amount) AS lead_val&#xA;FROM product_orders;یکی از مواردی که قبلاً مورد بحث قرار نگرفت، استفاده از عبارت «RANGE BETWEEN UNBOUNDED PRECEDING UNBUNDED AND UNBOUNDED FOLLOWING» در توابع FIRST_VALUE()، LAST_VALUE() و NTH_VALUE() است. این عبارت برای تعریف ردیف اول و آخر زیرگروه مورد نیاز است. هیچ چیز خاصی در مورد این عبارت وجود ندارد، به جز اینکه باید برای تنظیم frame توابع پنجره ای یا window function ها شامل شود.خلاصهنکته کلیدی این است که توابع پنجره تلفیقی از مفاهیم SQL موجود هستند که با هم ترکیب شده اند تا روشی متفاوت برای برش داده ها ایجاد کنند. استفاده از توابع پنجره ای مزایای مشخصی دارد و به شما امکان می دهد تا به سرعت داده های transform شده را در مقابل صرف کردن زمان برای ایجاد توابع سفارشی خود، خروجی بگیرید.ضمیمهاگر قبلاً Postgres را روی رایانه خود نصب کرده اید، لطفاً این دستورات CREATE TABLE و INSERT را اجرا کنید و پرس و جوهای SQL را که قبلاً به اشتراک گذاشته ام را اجرا کنید.DROP TABLE IF EXISTS orders;&#xA;&#xA;CREATE TABLE orders (&#xA;  order_id serial primary key,&#xA;  order_date timestamp,&#xA;  user_id integer,&#xA;  amount numeric,&#xA;  num_product_items integer&#xA;);&#xA;&#xA;INSERT INTO orders VALUES (134,&#39;2017-12-03 14:18:12&#39;,1,19.99,1);&#xA;INSERT INTO orders VALUES (145,&#39;2018-01-05 12:33:00&#39;,1,54.56,2);&#xA;INSERT INTO orders VALUES (156,&#39;2018-01-18 21:34:59&#39;,1,36.78,3);&#xA;INSERT INTO orders VALUES (167,&#39;2018-03-07 09:35:34&#39;,1,24.56,2);&#xA;INSERT INTO orders VALUES (234,&#39;2018-03-12 09:45:56&#39;,2,63.96,4);&#xA;INSERT INTO orders VALUES (245,&#39;2018-04-01 10:45:56&#39;,2,456.87,6);&#xA;INSERT INTO orders VALUES (256,&#39;2018-05-04 18:23:14&#39;,2,122.45,3);&#xA;INSERT INTO orders VALUES (267,&#39;2018-08-11 21:59:59&#39;,2,34.56,1);&#xA;INSERT INTO orders VALUES (345,&#39;2016-06-12 18:45:01&#39;,3,136.08,5);&#xA;INSERT INTO orders VALUES (356,&#39;2017-06-10 09:51:14&#39;,3,165.67,4);&#xA;INSERT INTO orders VALUES (367,&#39;2018-06-07 22:54:04&#39;,3,156.76,3);&#xA;&#xA;DROP TABLE IF EXISTS product_orders;&#xA;&#xA;CREATE TABLE product_orders (&#xA;  user_id integer,&#xA;  order_date timestamp,&#xA;  order_id integer,&#xA;  product_name varchar,&#xA;  amount numeric&#xA;);&#xA;&#xA;INSERT INTO product_orders VALUES (1,&#39;2017-11-12 00:11:45&#39;,123,&#39;dvd_movie&#39;,19.99);&#xA;INSERT INTO product_orders VALUES (1,&#39;2017-11-12 00:11:45&#39;,123,&#39;tennis_balls&#39;,12.99);&#xA;INSERT INTO product_orders VALUES (1,&#39;2017-11-12 00:11:45&#39;,123,&#39;bestseller_book&#39;,28.56);&#xA;INSERT INTO product_orders VALUES (1,&#39;2017-11-12 00:11:45&#39;,123,&#39;jacket_winter&#39;,112.99);&#xA;INSERT INTO product_orders VALUES (1,&#39;2017-11-12 00:11:45&#39;,123,&#39;sweater_winter&#39;,49.99);&#xA;INSERT INTO product_orders VALUES (2,&#39;2018-03-12 09:45:56&#39;,234,&#39;socks_spring&#39;,9.99);&#xA;INSERT INTO product_orders VALUES (2,&#39;2018-03-12 09:45:56&#39;,234,&#39;hoodie_jacket&#39;,16.99);&#xA;INSERT INTO product_orders VALUES (2,&#39;2018-03-12 09:45:56&#39;,234,&#39;blue_jeans&#39;,24.99);&#xA;INSERT INTO product_orders VALUES (2,&#39;2018-03-12 09:45:56&#39;,234,&#39;baseball_hat&#39;,11.99);&#xA;INSERT INTO product_orders VALUES (3,&#39;2016-06-12 18:45:01&#39;,345,&#39;pc_game_2&#39;,24.99);&#xA;INSERT INTO product_orders VALUES (3,&#39;2016-06-12 18:45:01&#39;,345,&#39;pc_game_3&#39;,45.99);&#xA;INSERT INTO product_orders VALUES (3,&#39;2016-06-12 18:45:01&#39;,345,&#39;console_controller&#39;,35.12);&#xA;INSERT INTO product_orders VALUES (3,&#39;2016-06-12 18:45:01&#39;,345,&#39;surge_protector&#39;,12.99);&#xA;INSERT INTO product_orders VALUES (3,&#39;2016-06-12 18:45:01&#39;,345,&#39;desk_lamp&#39;,16.99);منبع</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Fri, 25 Mar 2022 02:03:10 +0430</pubDate></item><item><title>Titanic Competition in SQL</title><link>https://virgool.ir/@vakily/titanic-competition-in-sql-mndvsdadfryi</link><description>هیچ چیز قدرتمندتر از یادگیری چیزی جدید یا رساندن یک مهارت به سطوح بالاتر با استفاده از روش های ساده نیست. در این مقاله، من از SQL (Postgres) برای انجام تجزیه و تحلیل اکتشافی خود و ایجاد یک مجموعه آموزشی (training set) ویژگی تبدیل شده برای مدل یادگیری ماشین خود استفاده خواهم کرد.اگرچه پایتون یا R زبان واقعی فعلی برای علم داده و یادگیری ماشین است، اما داشتن یک پایه قوی در SQL، گاهی اوقات به شما کمک می‌کند داده‌های خود را سریع کاوش کنید. بیشتر داده هایی که با آنها کار می کنیم در یک پایگاه داده رابطه ای زندگی می کنند. داشتن توانایی نوشتن کوئری های SQL به صورت روان به شما این امکان را می دهد که به راحتی با داده ها روبه رو شوید و به سرعت تجزیه و تحلیل خود را شروع کنید.هدفاگرچه پایتون رویکرد ترجیحی من خواهد بود، اما می‌خواستم ببینم آیا می‌توانم تمام تحلیل‌های اکتشافی و مهندسی ویژگی‌های خود را در SQL انجام دهم؟! هدف من این است که نشان دهم SQL چقدر می تواند برای گردش کار فرد قدرتمند و مکمل باشد. اگرچه یکی از محدودیت‌های آشکار SQL، توانایی مصورسازی داده‌ها است، اما همچنان می‌توانید با نوشتن کوئری ها و خروجی نتایج، دستاوردهای بزرگی به دست آورید. بیا شروع کنیم!اکتشافتحقیقات من در مورد غرق شدن کشتی تایتانیک نشان داد که زنان و کودکان در انتقال مسافران به قایق های نجات نسبت به دیگران اولویت دارند. این مفهوم نقش مهمی در نحوه گروه بندی و تجزیه و تحلیل مجموعه داده های Kaggle خواهد داشت.علاوه بر این، بحث هایی در مورد اینکه آیا مجموعه داده های train و test را جدا نگه دارید یا آنها را برای مهندسی ویژگی و انتخاب ترکیب کنید، وجود دارد. در بیشتر موارد، اولی برای جلوگیری از نشت داده ها (data leakage) معنی دار خواهد بود.روش معمول این است که مجموعه داده آزمایشی را کنار بگذاریم، آن را فراموش کنیم و فقط از مجموعه داده آموزشی برای impute و مهندسی ویژگی ها (engineer features) استفاده کنیم. برای این تمرین، تصمیم گرفتم train و test را ترکیب کنم تا داده های بیشتری برای پیش بینی میزان زنده ماندن داشته باشم. این یک جهان ثابت است (fixed universe) و ما انتظار نداریم داده های جدیدی به pipeline پیش بینی وارد شود.برای شروع، فایل های train.csv و test.csv را از Kaggle دانلود کردم و فایل ها را به دو جدولی که در پایگاه داده Postgres ایجاد کرده بودم، وارد کردم. بعد، من این دو جدول را با هم ترکیب کردم تا اولین جدول کاری خود را ایجاد کنم (titanic_train_test_raw). Titanic-MachineLearningfromDisaster|Kaggle برای درج رکوردها در جداول خود، psql را در ترمینال خود با تایپ کردن &#34;psql postgres&#34; باز کردم. این ابزار خط فرمان PostgreSQL است. من دو دستور زیر را برای قرار دادن فایل‌های CSV در جداول خود اجرا کردم.\copy titanic_train_raw from ‘file/path/train.csv’ delimiter ‘,’ csv HEADER;&#xA;\copy titanic_test_raw from ‘file/path/test.csv’ delimiter ‘,’ csv HEADER;برای درک بهتر داده ها، Survival_rate را برای هر ویژگی موجود در مجموعه train محاسبه کردم. من کل خروجی را در اینجا به اشتراک نمی گذارم زیرا آنها را قسمت به قسمت در طول مقاله به اشتراک خواهم گذاشت.کد :with titanic_survival_by_feature_high_level as&#xA;(&#xA;  select&#xA;    feature,&#xA;    feature_value,&#xA;    survival_rate,&#xA;    survived_passengers,&#xA;    total_passengers&#xA;  from&#xA;  (&#xA;    select&#xA;      &#39;pclass&#39; as feature, &#xA;      cast(pclass as varchar) as feature_value,&#xA;      round(avg(survived),4) as survival_rate,&#xA;      sum(survived) as survived_passengers, count(*) as total_passengers&#xA;    from titanic_train_raw&#xA;    group by 1,2&#xA;      union&#xA;    select&#xA;      &#39;name&#39;, &#xA;      split_part(split_part(name, &#39;, &#39;, 2), &#39;.&#39;, 1), &#xA;      round(avg(survived),4) as survival_rate,&#xA;      sum(survived) as num_survived, count(*) as total_passengers&#xA;    from titanic_train_raw&#xA;    group by 1,2&#xA;      union&#xA;    select&#xA;      &#39;sex&#39;, &#xA;      sex, &#xA;     round(avg(survived),4) as survival_rate,&#xA;      sum(survived) as num_survived, count(*) as total_passengers&#xA;    from titanic_train_raw&#xA;    group by 1,2&#xA;      union&#xA;    select&#xA;      &#39;age&#39;, &#xA;      cast(age_bucket as varchar) as age_bucket, &#xA;      round(avg(survived),4) as survival_rate,&#xA;      sum(survived) as num_survived, count(*) as total_passengers&#xA;    from (select ntile(6) over (order by age) as age_bucket, tr.* from titanic_train_raw tr) ag&#xA;    group by 1,2&#xA;      union&#xA;    select&#xA;      &#39;sibsp&#39;, &#xA;      cast(sibsp as varchar) as sibsp, &#xA;      round(avg(survived),4) as survival_rate,&#xA;      sum(survived) as num_survived, count(*) as total_passengers&#xA;    from titanic_train_raw&#xA;    group by 1,2&#xA;      union&#xA;    select&#xA;      &#39;parch&#39;, &#xA;      cast(parch as varchar) as parch, &#xA;      round(avg(survived),4) as survival_rate,&#xA;      sum(survived) as num_survived, count(*) as total_passengers&#xA;    from titanic_train_raw&#xA;    group by 1,2&#xA;      union&#xA;    select&#xA;      &#39;fare&#39;, &#xA;      cast(fare_bucket as varchar) as fare_bucket, &#xA;      round(avg(survived),4) as survival_rate,&#xA;      sum(survived) as num_survived, count(*) as total_passengers&#xA;    from (select ntile(6) over (order by fare) as fare_bucket, tr.* from titanic_train_raw tr) fr&#xA;    group by 1,2&#xA;      union&#xA;    select&#xA;      &#39;cabin&#39;, &#xA;      substring(cabin,1,1) as cabin, &#xA;      round(avg(survived),4) as survival_rate,&#xA;      sum(survived) as num_survived, count(*) as total_passengers&#xA;    from titanic_train_raw&#xA;    group by 1,2&#xA;      union&#xA;    select&#xA;      &#39;embarked&#39;, &#xA;      coalesce(embarked,&#39;S&#39;) as embarked, &#xA;      round(avg(survived),4) as survival_rate,&#xA;      sum(survived) as num_survived, count(*) as total_passengers&#xA;    from titanic_train_raw&#xA;    group by 1,2&#xA;  ) t1&#xA;)&#xA;select *&#xA;from titanic_survival_by_feature_high_level&#xA;order by 1,2,3 desc;خروجی :1. مقادیر از دست رفته یا Missing valuesبیایید نگاهی دقیق‌تر به مقادیر از دست رفته بیندازیم و ببینیم چه feature هایی بخاطر پراکندگی نیاز به تخمین یا حتی کاهش دارند. محاسبات missing value ها با داده های ترکیبی train و test انجام می شود. از آنجایی که داده های test ویژگی هدف Survived را ندارند، ستون ترکیبی Survived، مقدار 31.93 درصد از مقادیر آن را از دست داده است. همچنین ویژگی های Age، Cabin، Fare و Embarked به ترتیب 20.09، 77.46، 0.08 و 0.15 درصد گم شده اند.کد:select&#xA;  round(1.0 * sum(case when f1.passengerid is null then 1 else 0 end) / max(f1.total_passengers), 4) as passengerid,&#xA;  round(1.0 * sum(case when f1.survived is null then 1 else 0 end) / max(f1.total_passengers), 4) as survived,&#xA;  round(1.0 * sum(case when f1.pclass is null then 1 else 0 end) / max(f1.total_passengers), 4) as pclass,&#xA;  round(1.0 * sum(case when f1.name is null then 1 else 0 end) / max(f1.total_passengers), 4) as name,&#xA;  round(1.0 * sum(case when f1.sex is null then 1 else 0 end) / max(f1.total_passengers), 4) as sex,&#xA;  round(1.0 * sum(case when f1.age is null then 1 else 0 end) / max(f1.total_passengers), 4) as age,&#xA;  round(1.0 * sum(case when f1.sibsp is null then 1 else 0 end) / max(f1.total_passengers), 4) as sibsp,&#xA;  round(1.0 * sum(case when f1.parch is null then 1 else 0 end) / max(f1.total_passengers), 4) as parch,&#xA;  round(1.0 * sum(case when f1.ticket is null then 1 else 0 end) / max(f1.total_passengers), 4) as ticket,&#xA;  round(1.0 * sum(case when f1.fare is null then 1 else 0 end) / max(f1.total_passengers), 4) as fare,&#xA;  round(1.0 * sum(case when f1.cabin is null then 1 else 0 end) / max(f1.total_passengers), 4) as cabin,&#xA;  round(1.0 * sum(case when f1.embarked is null then 1 else 0 end) / max(f1.total_passengers), 4) as embarked&#xA;from&#xA;(&#xA;&#x9;select&#xA;&#x9;  count(*) over () as total_passengers,&#xA;&#x9;  t1.*&#xA;&#x9;from titanic_train_test_raw t1&#xA;) f1;2. میزان نجات یافتگان به صورت کلیاز training data، من درصد زنده مانده ها در مقابل درصد فوت شده ها را محاسبه کردم. از 891 مسافر در training data، تنها 38.38 درصد از آنها زنده مانده اند. همچنین، این تجزیه و تحلیل به من اجازه داد تا ببینم که کلاس هدف (target class) خیلی نامتوازن نباشد- تقریباً یک 60٪ به 40٪ است.کد:select&#xA;  case when f1.survived = 1 then &#39;Survived&#39; else &#39;Not Survived&#39; end as survival_status,&#xA;  round(1.0 * count(*) / max(f1.total_passengers), 4) as survival_rate,&#xA;  count(*) as num_of_passengers,&#xA;  max(f1.total_passengers) as total_passengers&#xA;from&#xA;(&#xA;&#x9;select&#xA;&#x9;  count(*) over () as total_passengers,&#xA;&#x9;  t1.*&#xA;&#x9;from titanic_train_raw t1&#xA;) f1&#xA;group by 1;3. میزان زنده ماندن بر اساس جنسیت و سنمسافران زن در مقایسه با مسافران مرد بیشترین احتمال زنده ماندن را داشتند. تنها بر اساس جنسیت، training data به ما می گوید که میزان زنده ماندن برای زنان تقریباً 74.2٪ و برای مردان 18.89٪ است.با استفاده از SQL خالص، 10 عدد bin یا (age_cohort) برای گروه بندی سنین مختلف ایجاد کردم. من به هیچ گونه تقسیم بندی دقیقی از گروه های سنی در نظر نخواهم داشت، بنابراین تعداد سطل ها یا bin ها دلخواه است. در حالی که نرخ زنده ماندن زنان در تمام گروه‌های سنی بالاتر از مردان بوده است، جنسیت مذکر زیر 9 سال سن، نرخ زنده ماندنشان تقریباً 60٪ می باشد. براساس نتایجی که قبلا بدست آمد، تنها بر اساس جنسیت، میزان زنده ماندن مردان کمتر از 20 درصد بود، اما با برش داده‌ها براساس گروه‌های سنی می‌بینیم که یک زیر گروه از مردان نرخ زنده ماندن نسبتاً بالاتری داشتند. (کودکان)کد:-- survival based on sex&#xA;select&#xA;  t1.sex,&#xA;  round(1.0 * sum(survived) / max(gender_cnt), 4) as survival_rate,&#xA;  sum(survived) as survived_passengers,&#xA;  max(gender_cnt) as total_passengers&#xA;from&#xA;(&#xA;&#x9;select&#xA;&#x9;  passengerid,&#xA;&#x9;  count(*) over (partition by sex) as gender_cnt,&#xA;&#x9;  sex,&#xA;&#x9;  survived&#xA;&#x9;from titanic_train_test_raw&#xA;&#x9;where cohort = &#39;train&#39;&#xA;) t1&#xA;where t1.survived = 1&#xA;group by 1;&#xA;&#xA;&#xA;&#xA;-- survival based on sex and age cohorts (10 bins)&#xA;select&#xA;  t1.sex,&#xA;  t1.age_cohort,&#xA;  min(age) as age_min,&#xA;  max(age) as age_max,&#xA;  count(*) as num_survived,&#xA;  max(age_sex_cnt) as num_age_cohort,&#xA;  round(1.0 * count(*) / max(age_sex_cnt), 4) as survival_rate&#xA;from&#xA;(&#xA;&#x9;select&#xA;&#x9;  passengerid,&#xA;&#x9;  age,&#xA;&#x9;  count(*) over (partition by sex, floor(1.0 * age / 10)) as age_sex_cnt,&#xA;&#x9;  sex,&#xA;&#x9;  floor(1.0 * age / 10) as age_cohort,&#xA;&#x9;  survived&#xA;&#x9;from titanic_train_test_raw&#xA;&#x9;where cohort = &#39;train&#39;&#xA;) t1&#xA;where t1.survived = 1&#xA;group by 1,2&#xA;order by 1,2;4. میزان زنده ماندن بر اساس مبلغ کرایه (fare) و میانگین آن به ازای هر مسافربرای اینکه سریعاً  ارتباط کرایه با میزان زنده ماندن را محاسبه کنم، از تابع پنجره ای ntile استفاده کردم تا مسافران را به طور مساوی در 6 بین (bin) قرار دهم و آماری را برای بررسی دقیق تر ایجاد کنم.در یک نگاه، به نظر می رسد survival_rate با گران شدن کرایه ها افزایش می یابد. در همان زمان، fare_mean و fare_stddev به طور چشمگیری از بین (bin) 5 به 6 پرش می کنند. بالاترین قیمت fare_max مقدار 512.3292 دلار است، در حالی که کمترین fare_min مقدار 0 دلار است. مقداری نویز در ستون کرایه وجود دارد. آنچه مستمر وجود دارد این است که زنده ماندن زنان بسیار بیشتر از مردان است. بر اساس ویژگی fare_grouping، میزان زنده ماندن زنان 2 تا 9 برابر بیشتر از مردان است (survival_ratio).متوجه شدم که کرایه نشان دهنده هزینه کل بلیط است و نه کرایه هر مسافر. به عنوان مثال، بلیط PC 17755، چهار مسافر وجود دارد. Cardeza یک خانواده ثروتمند است که با دو کارمند خود، Miss Ward و Mr. Lesurer، در first class سفر می کنند.برای اینکه بفهمم هزینه کرایه چقدر است، مبلغ کرایه را بر تعداد کل مسافران هر بلیط تقسیم کردم و میانگین ها را بر اساس Pclass گروه بندی کردم. هنگام بررسی ویژگی بلیط، خانواده ها، گروه های مختلط و افرادی را دیدم که به بلیط های فردی متصل شده بودند. در نتیجه، به جای استفاده از [SibSp (siblings &amp; spouses) + ParCh (parents &amp; children) + 1 (PassengerId)]، که معمولاً توسط سایر افراد Kaggle برای محاسبه ویژگی Family_size استفاده می‌شود، با استفاده از تعداد مسافران در هر بلیط، انحراف معیار کمتری ایجاد کنم و به من اطمینان داد که میانگین کرایه نسبتا دقیق تری برای هر مسافر فراهم می کند.به طور متوسط، کرایه first class برای هر مسافر حدود 32 دلار، کرایه second class برای هر مسافر حدود 12 دلار و third class حدود 8 دلار است. این میانگین مقدار کمی از نویز موجود در ویژگی اصلی کرایه را حذف کرد. fare_mean به نظر می رسد که ارتباط زیادی با Pclass دارد. بنابراین، داشتن هر دو ویژگی، Pclass و fare_per_passenger، ممکن است اضافی باشد. بعداً، ممکن است بخواهیم یکی از این موارد را در طول ساخت مدل حذف کنیم.کد 1:-- distribution of fares and survival based on arbitray fare groupings&#xA;select&#xA;  fare_grouping,&#xA;  count(*) as passenger_cnt,&#xA;  count(case when sex = &#39;female&#39; then passengerid else null end) as female_passenger_cnt,&#xA;  count(case when sex = &#39;male&#39; then passengerid else null end) as male_passenger_cnt,&#xA;  min(fare) as fare_min,&#xA;  max(fare) as fare_max,&#xA;  round(avg(fare),2) as fare_mean,&#xA;  round(stddev(fare),2) as fare_stddev,&#xA;  round(avg(survived),4) as survival_rate,&#xA;  round(avg(case when sex = &#39;female&#39; then survived else null end),4) as female_survival_rate,&#xA;  round(avg(case when sex = &#39;male&#39; then survived else null end),4) as male_survival_rate,&#xA;  round(round(avg(case when sex = &#39;female&#39; then survived else null end),4) / round(avg(case when sex = &#39;male&#39; then survived else null end),4), 2) as survival_ratio&#xA;from&#xA;(&#xA;&#x9;select&#xA;&#x9;  passengerid,&#xA;&#x9;  pclass,&#xA;&#x9;  sex,&#xA;&#x9;  fare,&#xA;&#x9;  survived,&#xA;&#x9;  ntile(6) over (order by fare) as fare_grouping&#xA;&#x9;from titanic_train_test_raw&#xA;&#x9;where cohort = &#39;train&#39;&#xA;) t1&#xA;group by 1&#xA;order by 1;کد 2:-- this query shows that passenger_cnt per ticket does not always equal family_size_cnt from sibsp+parch+1&#xA;select&#xA;  ticket,&#xA;  max(fare) as fare,&#xA;  count(passengerid) as passenger_cnt,&#xA;  max(sibsp + parch + 1) as family_size_cnt&#xA;from titanic_train_test_raw&#xA;group by 1&#xA;having count(passengerid) != max(sibsp + parch + 1);کد 3:-- calculate fare_per_passenger and average fare_per_passenger per class&#xA;-- pclass is already grouping the fares into groups. Most likely redundant to have both features.&#xA;select&#xA;  pclass,&#xA;  round(avg(fare_per_passenger),2) as fare_mean,&#xA;  round(stddev(fare_per_passenger),2) as fare_stddev,&#xA;  percentile_disc(0.5) within group (order by fare_per_passenger) as fare_median_disc,&#xA;  min(fare_per_passenger) as fare_min,&#xA;  max(fare_per_passenger) as fare_max&#xA;from&#xA;(&#xA;&#x9;select&#xA;&#x9;  pclass,&#xA;&#x9;  ticket,&#xA;&#x9;  max(fare) as fare_total,&#xA;&#x9;  count(passengerid) as ticket_passenger_cnt, -- used as denominator b/c more reliable when count(passengerid) != max(sibsp + parch + 1)&#xA;&#x9;  max(sibsp + parch + 1) as family_size_cnt,&#xA;&#x9;  round(max(fare) / count(passengerid), 4) as fare_per_passenger&#xA; &#x9;from titanic_train_test_raw&#xA;&#x9;group by 1,2&#xA;) t1&#xA;group by 1&#xA;order by 1;5. میزان زنده ماندن بر اساس Title از ویژگی نام اصلی17 عنوان منحصر به فرد وجود دارد و برخی از آنها نرخ زنده ماندن بالایی دارند. در training data فقط دو مسافر با عنوان Major و یک مسافر با Sir وجود دارد. برای اینکه هر گروه بندی برای مدل سازی مرتبط و تاثیرگذار باشد، عناوین نادر را به چهار عناون اضافه کردم - Mr, Mrs, Miss, and Master - و بنابراین یک ویژگی title_grouping ایجاد کردم. به عنوان مثال، Mlle، که مخفف Mademoiselle (دختر خانم) است، به Miss.عنوان Master جالب است زیرا نرخ زنده ماندن نسبتاً بالایی دارد و تعداد کمی از آنها در training data وجود دارد. در طی این دوره، به پسران تا رسیدن به سن بلوغ این لقب داده می شد. اکنون ما راهی برای شناسایی پسران با استفاده از title_grouping داریم در حالی که همه دختران و زنان در Mrs یا Miss جمع شده اند.من میزان زنده ماندن را برای هر title_grouping محاسبه کردم و اعداد بسیار گویای هستند. با جدا کردن پسران از گروه مردان، میزان زنده ماندن مردان کاهش می یابد و زنده ماندن پسران نزدیک به 60٪ است. من این ویژگی را در طول کار آماده سازی training data نهایی در مقادیر عددی رمزگذاری خواهم کرد.-- Boys are with Master title and girls have Miss titles which are grouped into Miss title grouping.&#xA;select&#xA;  case when split_part(split_part(name,&#39;.&#39;,1),&#39;, &#39;,2) in (&#39;Dr&#39;,&#39;Rev&#39;,&#39;Col&#39;,&#39;Major&#39;,&#39;Jonkheer&#39;,&#39;Sir&#39;,&#39;Don&#39;,&#39;Capt&#39;) and sex = &#39;male&#39; then &#39;Mr&#39;&#xA;       when split_part(split_part(name,&#39;.&#39;,1),&#39;, &#39;,2) in (&#39;Mlle&#39;) then &#39;Miss&#39;&#xA;       when split_part(split_part(name,&#39;.&#39;,1),&#39;, &#39;,2) in (&#39;Dr&#39;,&#39;Ms&#39;,&#39;the Countess&#39;,&#39;Mme&#39;,&#39;Lady&#39;,&#39;Dona&#39;) and sex = &#39;female&#39; then &#39;Mrs&#39;&#xA;       else split_part(split_part(name,&#39;.&#39;,1),&#39;, &#39;,2)&#xA;  end as title_grouping,&#xA;  round(avg(survived),4) as survival_rate,&#xA;  count(*)&#xA;from titanic_train_test_raw&#xA;where cohort = &#39;train&#39;&#xA;group by 1&#xA;order by 2 desc;6. میزان زنده ماندن بر اساس زن یا فرزند بودنبا مقاله Chris Deotte’s در مورد ویژگی‌ای که او ایجاد کرد به نام «woman-child-groups» بر اساس گروه‌بندی مسافران با نام خانوادگی (surnames) و القاب (titles)، برخوردم. با در نظر گرفتن این موضوع، یک ویژگی باینری ایجاد کردم که هر مسافر می تواند woman یا boy باشد. is_woman_child = 1 یعنی همه زنان و کودکان را میگیرد در حالی که is_woman_child = 0 یعنی همه مردان بالغ را می گیرد.کد :-- is_woman_child flag &gt;&gt; this grabs adult women, girls and boys where boys had hire chance of survival than adult men&#xA;select&#xA;  case when title_grouping in (&#39;Mrs&#39;,&#39;Miss&#39;,&#39;Master&#39;) then 1 else 0 end as is_woman_child,&#xA;  round(avg(survived),4) as survival_rate&#xA;from&#xA;(&#xA;&#x9;select&#xA;&#x9;  case when split_part(split_part(name,&#39;.&#39;,1),&#39;, &#39;,2) in &#xA;&#39;Dr&#39;,&#39;Rev&#39;,&#39;Col&#39;,&#39;Major&#39;,&#39;Jonkheer&#39;,&#39;Sir&#39;,&#39;Don&#39;,&#39;Capt&#39;) and sex = &#39;male&#39; then &#39;Mr&#39;&#xA;               when split_part(split_part(name,&#39;.&#39;,1),&#39;, &#39;,2) in (&#39;Mlle&#39;) then &#39;Miss&#39;&#xA;  &#x9;       when split_part(split_part(name,&#39;.&#39;,1),&#39;, &#39;,2) in (&#39;Dr&#39;,&#39;Ms&#39;,&#39;the Countess&#39;,&#39;Mme&#39;,&#39;Lady&#39;,&#39;Dona&#39;) and sex = &#39;female&#39; then &#39;Mrs&#39;&#xA;  &#x9;       else split_part(split_part(name,&#39;.&#39;,1),&#39;, &#39;,2)&#xA;          end as title_grouping,&#xA;&#x9;  t1.*&#xA;&#x9;from titanic_train_test_raw t1&#xA;&#x9;where cohort = &#39;train&#39;&#xA;) f1&#xA;group by 1;7. نرخ زنده ماندن بر اساس سطح کابینبرخی از بررسی هایی که برای این کار انجام دادم نشان داد که اکثریت مسافران third class در سطوح کابین F و G قرار داشتند. با این کار، منطقی بود که سطوح کابین را با دقت بیشتری بررسی کنیم، اگرچه 77٪ از مقادیر وجود نداشت. من فرض کردم که سطوح پایین کابین، شانس زنده ماندن مسافر را کاهش می دهد.پس از انجام برخی تجزیه و تحلیل ها، زمانی که مسافران بخشی از کلاس پایین تر و سطوح کابین پایین تر هستند، میزان زنده ماندن کاهش می یابد.همانطور که در زیر نشان داده شده است، ستون embarked به تنهایی کاملاً میزان زنده ماندن را برایمان تعریف نمی کند، اما من معتقدم که می توان از آن برای ایجاد ویژگی های جدیدی استفاده کرد که قدرت پیش بینی نسبتاً بالاتری دارند.به عنوان یادداشت جانبی، دو مسافر با مقادیر Embarked گم شده وجود دارد، اما من این مسافران را جستجو کردم و هر دو در ساوت همپتون (S) انگلستان سوار کشتی شدند.من فرض کردم که ارتباطی بین مکان سوار شدن (embarked) و عرشه یا deck (cabin_level) کابین قرار دارد. به عبارت دیگر، هر مکان سوار شدن برای یک مجموعه خاص از کابین ها بود و نوعی تشکیلات وجود داشت که ابتدا کابین ها بر اساس مکان سوار شدن پر می شدند. بنابراین، اگر یک بلیط third-class داشتید که با F شروع می شد، نشان می داد در آن عرشه کابین مسافری اقامت دارد. برای مثال به احتمال زیاد از ساوت همپتون، انگلستان، سوار کشتی شده اند.کد :-- cabin level and pclass survival&#xA;select&#xA;  pclass,&#xA;  cabin_level,&#xA;  count(*) as num_passengers,&#xA;  round(avg(survived),4) as survival_rate&#xA;from titanic_train_test_raw_v2&#xA;where cohort = &#39;train&#39;&#xA;group by 1,2&#xA;order by 1,2;&#xA;&#xA;-- embarked doesn&#39;t seem to be as strong as a feature to predict survival&#xA;select&#xA;  coalesce(embarked,&#39;S&#39;) as embarked,&#xA;  round(avg(survived),4) as survival_rate&#xA;from titanic_train_raw&#xA;group by 1;تبدیل ویژگی و مهندسی (Feature Transformation and Engineering)اکنون که ویژگی‌های آموزشی اصلی و بینش‌های بهتر در مورد زنده ماندن مسافران را درک می‌کنم، زمان آن رسیده است که یافته‌های خود را ادغام کنیم و شروع به جمع‌آوری مجموعه داده‌های آموزشی بهینه‌شده برای فیت کردن مدل کنیم.1.ساخت ویژگی های is_one_family / is_mix_group / is_aloneمن فرض می‌کنم که همان شماره بلیت، مجموعه ای از مسافرانی را که با هم سفر می‌کنند تعریف می‌کند. علاوه بر این، فرض می‌کنم که اگر فردی تنها مسافری باشد که به بلیط متصل شده است، این مسافر یک مسافر تنها است. بنابراین، مسافران را بر اساس شماره بلیط و نام خانوادگی استخراج شده از ویژگی اصلی Name گروه بندی کردم.یک trade-off با این فرض وجود دارد، اما فرض می کنم که این بیشتر سناریوهای گروه را در بر می گیرد. هدف اصلی از تقسیم بندی گروه ها به این روش، تعمیم جمعیت کشتی است. (ship’s population)اگر بلیطی دارای تنها یک نام خانوادگی با چند مسافر باشد، یک خانواده در نظر گرفته می شود که 1 درست است و 0 نادرست است (is_one_family). این در درجه اول به خانواده هایی مرتبط است که با هم سفر می کنند. بنابراین، اگر مسافر بخشی از بلیط یک خانواده بود، این فلگ عنوان 1 علامت گذاری می شود.اگر بلیطی دارای چندین نام خانوادگی و چندین مسافر باشد، به عنوان یک گروه مختلط (is_mix_group) تعریف می شود. به عنوان مثال شماره بلیط 1601 دارای 7 نام خانوادگی مختلف است. در مجموع 67 بلیط با دو یا چند نام خانوادگی پیوست شده است. من فقط 12 بلیط برتر را در اینجا نشان می دهم.اگر بلیطی دارای تنها یک نام خانوادگی و یک مسافر باشد، بیانگر مسافری است که به تنهایی سفر می کند (is_alone). با نگاهی دقیق تر به جمعیت male یا male population، مسافران male ای که به تنهایی سفر می کنند کمترین میزان زنده ماندن (15.57 درصد) را در مقایسه با مردان بالغ با خانواده (17.46 درصد) و پسران با خانواده (57.5 درصد) داشتند.در یک نگاه کلی، مسافران male بالغ بدون خانواده یا بخشی از یک گروه مختلط کمترین شانس زنده ماندن را داشتند. ما الگوهای جالبی را در این خروجی می بینیم. مسافران male که با خانواده خود سفر می کردند، بالاترین میزان زنده ماندن را داشتند. به احتمال زیاد این مسافران male پسرها بودند. من این را در زیر تأیید می کنم.وقتی پسرها را از male population جدا کردم، بسیار واضح‌تر شد. پسران با سرعت بیشتری نسبت به مردان بالغ زنده ماندند.کد :-- some tickets have multiple non-family individuals which were employed by wealthy employer e.g. ticket number PC 17757 while some tickets had a whole family attached.&#xA;select&#xA;  ticket,&#xA;  count(distinct trim(split_part(name,&#39;,&#39;,1))) as num_surnames,&#xA;  max(trim(split_part(name, &#39;,&#39;, 1))) as surname_1,&#xA;  min(trim(split_part(name, &#39;,&#39;, 1))) as surname_2,&#xA;  max(pclass) as pclass&#xA;from titanic_train_test_raw&#xA;group by 1&#xA;order by 2 desc;&#xA;&#xA;-- group families by surname and ticket with assumption all families traveled on a single ticket and measure survival&#xA;-- male passengers with a family or with a mix group slightly higher probability of survival while boys with family has the highest chance of survival&#xA;-- adult male passengers without family or part of a mix group has the lowest chance of survival&#xA;select&#xA;  sex,&#xA;  case when trim(split_part(split_part(name,&#39;.&#39;,1),&#39;, &#39;,2)) = &#39;Master&#39; then &#39;Boy&#39; else &#39;Adult&#39; end as bucket,&#xA;  case when (sibsp+parch+1) = 1 then 1 else 0 end as is_alone,&#xA;  round(avg(survived), 4)&#xA;from titanic_train_test_raw&#xA;where cohort = &#39;train&#39;&#xA;and sex = &#39;male&#39;&#xA;group by 1,2,3;&#xA;&#xA;-- is_mix_group flag &gt;&gt; flag passengers who are traveling with group of other passengers on the same ticket&#xA;-- is_one_family flag &gt;&gt; flag passengers traveling with families&#xA;-- is_alone flag &gt;&gt; flag passenegers traveling alone&#xA;select&#xA;  case when num_surnames = 1 and num_passengers &gt; 1 then 1 else 0 end as is_one_family,&#xA;  case when num_surnames &gt; 1 and num_passengers &gt; 1 then 1 else 0 end as is_mix_group,&#xA;  case when num_surnames = 1 and num_passengers = 1 then 1 else 0 end as is_alone,&#xA;  count(*) as num_tickets&#xA;from&#xA;(&#xA;&#x9;select&#xA;&#x9;  ticket,&#xA;&#x9;  count(passengerid) as num_passengers,&#xA;&#x9;  count(distinct trim(split_part(name,&#39;,&#39;,1))) as num_surnames&#xA;&#x9;from titanic_train_test_raw&#xA;&#x9;group by 1&#xA;) t1&#xA;group by 1,2,3;&#xA;&#xA;-- We do see some interesting patterns in this output. Particularly, male + is_one_family = 1, which has the highest survival rate. This is most likely due to the boys in this cohort.&#xA;select&#xA;  f1.sex,&#xA;  f2.is_one_family,&#xA;  f2.is_mix_group,&#xA;  f2.is_alone,&#xA;  round(avg(f1.survived),4) as survival_rate&#xA;from titanic_train_raw f1&#xA;left join&#xA;(&#xA;&#x9;select&#xA;&#x9;  ticket,&#xA;&#x9;  case when num_surnames = 1 and num_passengers &gt; 1 then 1 else 0 end as is_one_family,&#xA;&#x9;  case when num_surnames &gt; 1 and num_passengers &gt; 1 then 1 else 0 end as is_mix_group,&#xA;&#x9;  case when num_surnames = 1 and num_passengers = 1 then 1 else 0 end as is_alone&#xA;&#x9;from&#xA;&#x9;(&#xA;&#x9;&#x9;select&#xA;&#x9;&#x9;  ticket,&#xA;&#x9;&#x9;  count(passengerid) as num_passengers, -- looking for actual number of passengers per ticket versus family_size because family size can also reflect family members on other tickets&#xA;&#x9;&#x9;  count(distinct trim(split_part(name,&#39;,&#39;,1))) as num_surnames&#xA;&#x9;&#x9;from titanic_train_test_raw&#xA;&#x9;&#x9;group by 1&#xA;&#x9;&#x9;-- Because ticket numbers are tied to class, it will be better to great group flags using passengers attached to individual tickets.&#xA;&#x9;) t1&#xA;) f2&#xA;  on f1.ticket = f2.ticket&#xA;group by 1,2,3,4&#xA;order by 1,5 desc;&#xA;&#xA;-- male passengers with family or with a mix group slightly higher probability of survival while boys with family has the highest chance of survival&#xA;-- adult male passengers without family or part of a mix group has the lowest chance of survival&#xA;select&#xA;  f1.sex,&#xA;  case when trim(split_part(split_part(f1.name,&#39;.&#39;,1),&#39;, &#39;,2)) = &#39;Master&#39; then &#39;Boy&#39; else &#39;Adult&#39; end as bucket,&#xA;  f2.is_one_family,&#xA;  f2.is_mix_group,&#xA;  f2.is_alone,&#xA;  round(avg(f1.survived),4) as survival_rate&#xA;from titanic_train_raw f1&#xA;left join&#xA;(&#xA;&#x9;select&#xA;&#x9;  ticket,&#xA;&#x9;  case when num_surnames = 1 and num_passengers &gt; 1 then 1 else 0 end as is_one_family,&#xA;&#x9;  case when num_surnames &gt; 1 and num_passengers &gt; 1 then 1 else 0 end as is_mix_group,&#xA;&#x9;  case when num_surnames = 1 and num_passengers = 1 then 1 else 0 end as is_alone&#xA;&#x9;from&#xA;&#x9;(&#xA;&#x9;&#x9;select&#xA;&#x9;&#x9;  ticket,&#xA;&#x9;&#x9;  count(passengerid) as num_passengers, -- looking for actual number of passengers per ticket versus family_size because family size can also reflect family members on other tickets&#xA;&#x9;&#x9;  count(distinct trim(split_part(name,&#39;,&#39;,1))) as num_surnames&#xA;&#x9;&#x9;from titanic_train_test_raw&#xA;&#x9;&#x9;group by 1&#xA;&#x9;&#x9;-- Because ticket numbers are tied to class, it will be better to great group flags using passengers attached to individual tickets.&#xA;&#x9;) t1&#xA;) f2&#xA;  on f1.ticket = f2.ticket&#xA;where f1.sex = &#39;male&#39;&#xA;group by 1,2,3,4,5&#xA;order by 1,6 desc;&#xA;&#xA;-- ticket+surname count does not match sum of sibsp+parch+1&#xA;select&#xA;  ticket,&#xA;  split_part(name,&#39;,&#39;,1) as surname,&#xA;  count(*) cnt,&#xA;  max(sibsp+parch+1) as sum_,&#xA;  max(cohort) as cohort&#xA;from titanic_train_test_raw&#xA;group by 1,2&#xA;having count(*) != max(sibsp+parch+1);&#xA;-- e.g. A/4 48871 - fourth member of the group missing, Joseph Davies.&#xA;&#x9;-- https://www.encyclopedia-titanica.org/titanic-victim/alfred-davies.html&#xA;&#xA;select&#xA;  ticket,&#xA;  split_part(name,&#39;,&#39;,1) as surname,&#xA;  count(*) cnt,&#xA;  max(sibsp+parch+1) as sum_,&#xA;  max(cohort) as cohort&#xA;from titanic_train_test_raw&#xA;group by 1,2&#xA;having count(*) &lt; max(sibsp+parch+1);&#xA;&#xA;select&#xA;  ticket,&#xA;  split_part(name,&#39;,&#39;,1) as surname,&#xA;  count(*) cnt,&#xA;  max(sibsp+parch+1) as sum_,&#xA;  max(cohort) as cohort&#xA;from titanic_train_test_raw&#xA;group by 1,2&#xA;having count(*) &gt; max(sibsp+parch+1);2. بررسی family_sizeبرای تعیین اندازه خانواده، منطقی است که SibSp، ParCh، و مسافر فعلی (+1) را اضافه کنید. با این حال، به جای تعریف این موضوع در سطح مسافر، تعیین حداکثر اندازه خانواده بر اساس شماره بلیط و نام خانوادگی منطقی تر بود.من به این فرض پایبند هستم که خانواده ها با هم و در این مورد با یک بلیط سفر کرده اند. در نتیجه، مجموع SibSp، ParCh، و مسافر فعلی، که نشان دهنده اندازه خانواده است، با شماره بلیط و نام خانوادگی مطابقت داده می شود. من یک mapping SQL subquery ایجاد کردم که در آن اگر شماره بلیط و نام خانوادگی یکسانی وجود دارد، اندازه خانواده (SibSp + ParCh + 1) برای مسافر map می شود.پس از جمع‌آوری منطق، به میانگین میزان زنده ماندن بر اساس اندازه خانواده و Pclass نگاه کردم. خانواده های نسبتا پرجمعیت میزان بقا کمتری داشتند. به راحتی می توان اینطور استنباط کرد که اگر عضوی از یک خانواده بزرگ بودید، مرده اید! همچنین اگر تنها نیز بودید میمردید! از آنجایی که تنها تعداد انگشت شماری بلیط با چهار مسافر یا بیشتر وجود دارد، تعمیم زنده ماندن گروه های بزرگ دشوار است. با این حال، بر اساس داده‌های موجود، ارزش دیدن این را دارد که آیا اندازه خانواده در پیش‌بینی زنده ماندن اهمیت نسبی دارد یا خیر.کد:-- average survival rate by family size&#xA;-- larger the family size survival was very low. Basically, if you were part of a big family, you died.&#xA;select&#xA;  pclass,&#xA;  family_size,&#xA;  round(avg(survival_rate), 4) as avg_survival_rate_by_familysize,&#xA;  count(*) as unique_ticket_cnt&#xA;from&#xA;(&#xA;    select&#xA;      ticket,&#xA;      pclass,&#xA;      trim(split_part(name,&#39;,&#39;,1)) as family_name,&#xA;      max(sibsp+parch+1) as family_size,&#xA;      round(avg(survived),4) as survival_rate&#xA;    from titanic_train_test_raw&#xA;    group by 1,2,3&#xA;) t1&#xA;group by 1,2&#xA;order by 1,2 desc;3. اولین جدول ویژگی های تلفیقی را بسازید: titanic_train_test_raw_v2من اکنون اولین جدول تلفیقی خود را بر اساس تمام یافته هایم در بالا تجمیع می کنم. در این مرحله، ویژگی های جدید را ترکیب کرده ام و ویژگی های موجود را برای مصرف بهتر مدل تغییر می دهم.رمزگذاری (Encoding) ویژگی جنسیت : female = 1 and male = 0نام خانوادگی (نام خانوادگی) را از ویژگی Name استخراج کنید.افزودن ویژگی title_grouping که قبلا به اشتراک گذاشتم.افزودن ویژگی is_woman_childاستخراج سطوح کابین (عرشه) یا cabin levels (deck) از ویژگی کابینرمزگذاری یا (Encoding) ویژگی Embarked به صورت S = 0، C = 1، و Q = 2افزودن ویژگی Family_size بر اساس شماره بلیط و نام خانوادگی (surname)افزودن ویژگی‌های is_one_family، is_mix_group و is_aloneافزودن ویژگی fare_per_passenger با تقسیم کرایه بر تعداد PassengerId یافت شده در هر بلیطکد :drop table if exists titanic_train_test_raw_v2;&#xA;&#xA;create table titanic_train_test_raw_v2 as&#xA;(&#xA;&#x9;select&#xA;&#x9;  t1.passengerid,&#xA;&#x9;  t1.cohort,&#xA;&#x9;  t1.survived,&#xA;&#x9;  t1.pclass,&#xA;&#x9;  case when t1.sex = &#39;female&#39; then 1 else 0 end as sex,&#xA;&#x9;  t1.age,&#xA;&#x9;  t4.fare_per_passenger,&#xA;&#x9;  t1.fare,&#xA;&#x9;  t1.ticket,&#xA;&#x9;  trim(split_part(t1.name,&#39;,&#39;,1)) as family_name,&#xA;&#x9;  case when split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2) in (&#39;Dr&#39;,&#39;Rev&#39;,&#39;Col&#39;,&#39;Major&#39;,&#39;Jonkheer&#39;,&#39;Sir&#39;,&#39;Don&#39;,&#39;Capt&#39;) and t1.sex = &#39;male&#39; then &#39;Mr&#39;&#xA;&#x9;       when split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2) = &#39;Dr&#39; and t1.sex = &#39;female&#39; then &#39;Mrs&#39;&#xA;&#x9;       when split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2) in (&#39;Mlle&#39;) then &#39;Miss&#39;&#xA;&#x9;       when split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2) in (&#39;Ms&#39;,&#39;the Countess&#39;,&#39;Mme&#39;,&#39;Lady&#39;,&#39;Dona&#39;) then &#39;Mrs&#39;&#xA;&#x9;       else split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2)&#xA;&#x9;  end as title_grouping,&#xA;&#x9;  case when split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2) in (&#39;Dr&#39;,&#39;Rev&#39;,&#39;Col&#39;,&#39;Major&#39;,&#39;Jonkheer&#39;,&#39;Sir&#39;,&#39;Don&#39;,&#39;Capt&#39;) and t1.sex = &#39;male&#39; then 0&#xA;&#x9;       when split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2) = &#39;Dr&#39; and t1.sex = &#39;female&#39; then 1&#xA;&#x9;       when split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2) in (&#39;Mlle&#39;,&#39;Ms&#39;,&#39;Miss&#39;,&#39;Mrs&#39;,&#39;Miss&#39;,&#39;the Countess&#39;,&#39;Mme&#39;,&#39;Lady&#39;,&#39;Dona&#39;) then 1&#xA;&#x9;       when split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2) = &#39;Master&#39; then 1&#xA;&#x9;       when split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2) = &#39;Mr&#39; then 0&#xA;&#x9;  end as is_woman_child,&#xA;&#x9;  t1.sibsp,&#xA;&#x9;  t1.parch,&#xA;&#x9;  t1.cabin,&#xA;&#x9;  substring(trim(t1.cabin),1,1) as cabin_level,&#xA;&#x9;  t2.family_size,&#xA;&#x9;  t3.is_one_family,&#xA;&#x9;  t3.is_mix_group,&#xA;&#x9;  t3.is_alone,&#xA;&#x9;  case when coalesce(embarked,&#39;S&#39;) = &#39;S&#39; then 0&#xA;&#x9;       when coalesce(embarked,&#39;S&#39;) = &#39;C&#39; then 1&#xA;&#x9;       when coalesce(embarked,&#39;S&#39;) = &#39;Q&#39; then 2&#xA;&#x9;  end as embarked&#xA;&#x9;from titanic_train_test_raw t1&#xA;&#x9;     left join&#xA;&#x9;     (&#xA;&#x9;&#x9;select&#xA;&#x9;&#x9;  ticket,&#xA;&#x9;&#x9;  trim(split_part(name,&#39;,&#39;,1)) as family_name,&#xA;&#x9;&#x9;  max(sibsp + parch + 1) as family_size&#xA;&#x9;&#x9;from titanic_train_test_raw -- logic assumes a family traveled on a single ticket&#xA;&#x9;&#x9;group by 1,2&#xA;&#x9;     ) t2&#xA;&#x9;       on t1.ticket = t2.ticket&#xA;&#x9;       and trim(split_part(t1.name,&#39;,&#39;,1)) = t2.family_name&#xA;&#x9;     left join&#xA;&#x9;     (&#xA;&#x9;&#x9; select&#xA;&#x9;&#x9;   ticket,&#xA;&#x9;&#x9;   case when num_surnames = 1 and num_passengers &gt; 1 then 1 else 0 end as is_one_family,&#xA;&#x9;&#x9;   case when num_surnames &gt; 1 and num_passengers &gt; 1 then 1 else 0 end as is_mix_group,&#xA;&#x9;&#x9;   case when num_surnames = 1 and num_passengers = 1 then 1 else 0 end as is_alone&#xA;&#x9;&#x9; from&#xA;&#x9;&#x9; (&#xA;&#x9;&#x9;    select&#xA;&#x9;&#x9;      ticket,&#xA;&#x9;&#x9;      count(passengerid) as num_passengers,&#xA;&#x9;&#x9;      count(distinct trim(split_part(name,&#39;,&#39;,1))) as num_surnames&#xA;&#x9;&#x9;    from titanic_train_test_raw&#xA;&#x9;&#x9;    group by 1&#xA;&#x9;&#x9; ) tic&#xA;&#x9;     ) t3&#xA;&#x9;        on t1.ticket = t3.ticket&#xA;&#x9;     left join&#xA;&#x9;     (&#xA;&#x9;&#x9; select&#xA;&#x9;&#x9;   ticket,&#xA;&#x9;&#x9;   round(max(fare) / count(passengerid), 2) as fare_per_passenger&#xA;&#x9;&#x9; from titanic_train_test_raw&#xA;&#x9;&#x9; group by 1&#xA;&#x9;     ) t4&#xA;&#x9;       on t4.ticket = t1.ticket&#xA;);4. دومین جدول ویژگی های تلفیقی را بسازید: titanic_train_test_raw_v3با استفاده از برخی از ویژگی‌هایی که قبلا ایجاد شده‌اند، یک جدول تلفیقی دوم (v3) ایجاد کردم تا ویژگی‌های بیشتری را اضافه کنم و تغییرات بیشتری ایجاد کنم. بهتر است هنگام استفاده از SQL چندین جدول به این روش بسازید زیرا به سازماندهی کمک می کند و با داشتن تکه های کوچکتر SQL را خواناتر می کند.مقادیر از دست رفته سن یا Age missing values:در ابتدا می بایست مقادیر سن از دست رفته را پر کنید. من داده ها را بر اساس Pclass، Sex، و title_grouping گروه بندی کردم تا میانگین سنی هر گروه را محاسبه کنم. من از میانگین به جای میانه استفاده کردم زیرا هر دو مجموعه اعداد مشابه هستند. همچنین انحراف معیار میانگین را برای بررسی تغییرپذیری یا variability محاسبه کردم.ویژگی Age_bucket:علاوه بر آن، یک ویژگی به نام age_bucket ایجاد کردم. تصمیم گرفتم که متغیر Age پیوسته را بگیرم و آنها را در 7 سطل یا bin قرار دهم. از آنجایی که ویژگی Age حاوی میانگین های تخمینی است، شاید بهتر باشد که این ویژگی را به یک categorical feature تبدیل کنید تا نویز در ویژگی پیوسته به حداقل برسد.ویژگی Fare_bucket &amp; fare missing values:من میانگین کرایه به ازای هر مسافر به ازای هر کلاس را در طول تحلیل خود محاسبه کردم، و مشخص بود که قیمت‌ها به کلاس مرتبط هستند. همچنین fare missing values را با fare_per_passenger که به Pclass هر مسافر مرتبط بود پر کردم. در همان زمان، 5 سطل یا bin را برای ایجاد یک categorical feature ایجاد کردم.ویژگی Title_grouping: چهار برچسب text string در این ویژگی به مقادیر عددی (numeric values) تبدیل شدند. (Master = 0, Mrs = 1, Miss = 2, and Mr = 3)ویژگی Cabin_level &amp; cabin level missing values : رویکرد در نظر گرفته شده برای پر کردن مقادیر از دست رفته cabin_level این است که همه مسافران را بر اساس Pclass، Embarked و cabin_level که Cabin مقدار null نیستند، شمارش کنم. در مرحله بعد، تعداد مسافران متصل به Pclass، Embarked و cabin_level را به ترتیب نزولی رتبه‌بندی کردم و برای هر ترکیب از Pclass و Embarked، مورد cabin_level را با بیشترین تعداد مسافران متصل به آن انتخاب کردم.کد:-- cabin level estimating logic in SQL to fill in missing cabin level values per passenger&#xA;select *&#xA;from&#xA;(&#xA;  select&#xA;    pclass,&#xA;    embarked,&#xA;    cabin_level,&#xA;    row_number() over (partition by pclass, embarked order by num_passengers desc) as cabin_rnk&#xA;  from&#xA;  (&#xA;     select&#xA;       pclass,&#xA;       embarked,&#xA;       cabin_level,&#xA;       count(*) as num_passengers&#xA;     from titanic_train_test_raw_v2&#xA;     where cabin_level is not null&#xA;     group by 1,2,3&#xA;  ) cl&#xA;) t3&#xA;where t3.cabin_rnk = 1;If Pclass = 1 and Embarked = 0, then cabin_level = C.If Pclass = 1 and Embarked = 1, then cabin_level = C.If Pclass = 1 and Embarked = 2, then cabin_level = C.If Pclass = 2 and Embarked = 0, then cabin_level = F.If Pclass = 3 and Embarked = 0, then cabin_level = G.And so on!کد:drop table if exists titanic_train_test_raw_v3;&#xA;&#xA;create table titanic_train_test_raw_v3 as&#xA;&#xA;select&#xA;  t1.passengerid,&#xA;  t1.cohort,&#xA;  t1.survived,&#xA;  t1.pclass,&#xA;  t1.sex,&#xA;  coalesce(t1.age, t2.age_mean) as age,&#xA;  case when floor(1.0 * coalesce(t1.age, t2.age_mean) / 10) &gt;= 7 then 7 else floor(1.0 * coalesce(t1.age, t2.age_mean) / 10) end as age_bucket,&#xA;  coalesce(t1.fare, t4.fare_mean) as fare,&#xA;  coalesce(t1.fare_per_passenger, t4.fare_mean) as fare_per_passenger,&#xA;  case when floor(coalesce(t1.fare_per_passenger, t4.fare_mean) / 11) &gt; 4 then 5 else floor(coalesce(t1.fare_per_passenger, t4.fare_mean) / 11) end as fare_bucket,&#xA;  t1.ticket,&#xA;  t1.family_name,&#xA;  case when t1.title_grouping = &#39;Master&#39; then 0&#xA;       when t1.title_grouping = &#39;Mrs&#39; then 1&#xA;      when t1.title_grouping = &#39;Miss&#39; then 2&#xA;       when t1.title_grouping = &#39;Mr&#39; then 3&#xA;  end as title_grouping,&#xA;  t1.is_woman_child,&#xA;  t1.sibsp,&#xA;  t1.parch,&#xA;  t1.cabin,&#xA;  case when coalesce(t1.cabin_level, t3.cabin_level) = &#39;A&#39; then 0&#xA;       when coalesce(t1.cabin_level, t3.cabin_level) = &#39;B&#39; then 1&#xA;       when coalesce(t1.cabin_level, t3.cabin_level) = &#39;C&#39; then 2&#xA;       when coalesce(t1.cabin_level, t3.cabin_level) = &#39;D&#39; then 3&#xA;       when coalesce(t1.cabin_level, t3.cabin_level) = &#39;E&#39; then 4&#xA;       when coalesce(t1.cabin_level, t3.cabin_level) = &#39;F&#39; then 5&#xA;       when coalesce(t1.cabin_level, t3.cabin_level) = &#39;G&#39; then 6&#xA;       when coalesce(t1.cabin_level, t3.cabin_level) = &#39;T&#39; then 7&#xA;  end as cabin_level,&#xA;  t1.family_size,&#xA;  t1.is_one_family,&#xA;  t1.is_mix_group,&#xA;  t1.is_alone,&#xA;  t1.embarked&#xA;from titanic_train_test_raw_v2 t1&#xA;     left join&#xA;    (&#xA;        select&#xA;          pclass,&#xA;          sex,&#xA;         title_grouping,&#xA;         round(avg(age),2) as age_mean,&#xA;          round(stddev(age),2) as age_stddev,&#xA;&#x9;  count(passengerid) as num_passengers&#xA;        from titanic_train_test_raw_v2&#xA;&#x9;group by 1,2,3&#xA;     ) t2&#xA;       on t1.pclass = t2.pclass&#xA;       and t1.sex = t2.sex&#xA;       and t1.title_grouping = t2.title_grouping&#xA;     left join&#xA;     (&#xA;        select&#xA;          pclass,&#xA;          embarked,&#xA;          cabin_level,&#xA;          row_number() over (partition by pclass, embarked order by num_passengers desc) as cabin_rnk&#xA;        from&#xA;        (&#xA;           select&#xA;             pclass,&#xA;             embarked,&#xA;             cabin_level,&#xA;             count(*) as num_passengers&#xA;           from titanic_train_test_raw_v2&#xA;           where cabin_level is not null&#xA;           group by 1,2,3&#xA;        ) cl&#xA;      ) t3&#xA;        on t1.pclass = t3.pclass&#xA;        and t1.embarked = t3.embarked&#xA;        and t3.cabin_rnk = 1&#xA;      left join&#xA;      (&#xA;         select&#xA;           pclass,&#xA;           round(avg(fare_per_passenger),2) as fare_mean&#xA;         from&#xA;         (&#xA;            select&#xA;              pclass,&#xA;              ticket,&#xA;              round(max(fare) / count(passengerid), 4) as fare_per_passenger&#xA;            from titanic_train_test_raw&#xA;            group by 1,2&#xA;         ) t1&#xA;         group by 1&#xA;       ) t4&#xA;         on t1.pclass = t4.pclass&#xA;);5. ایجاد منطق «women-child-group»در ادامه سعی کردم ویژگی Chris Deotte را با تغییراتی در SQL دوباره ایجاد کنم. در مقاله بعدی خود، این ویژگی را از نظر تأثیر و اهمیت آزمایش خواهم کرد.ابتدا، عنوان هر مسافر به عنوان مرد، زن یا پسر (man, woman, or boy) برچسب گذاری می شود. به طور همزمان، همه عناوین male به عنوان &#34;noGroup&#34; برچسب گذاری می شوند زیرا اولویت زنده ماندن به زنان و کودکان داده می شود.سپس، تعداد یا فرکانس نام خانوادگی برای هر مسافر را محاسبه کردم. این فرکانس به کل مجموعه داده نگاه می کند و نه در سطح بلیط. هر مسافری با تعداد نام خانوادگی یک یا کمتر، در صورت وجود، به عنوان &#34;noGroup&#34; برچسب گذاری می شود. بنابراین، زنان و کودکان در خانواده ها نسبت به زنانی که به تنهایی سفر می کنند، اولویت دارند.در این مرحله، احتمال زنده ماندن با استفاده از ویژگی هدف Survived داده های آموزشی بر اساس ویژگی نام خانوادگی به روز شده محاسبه می شود. همچنین اکثر نام‌های خانوادگی به «noGroup» تغییر کرده‌اند، و بنابراین، زنده ماندن همه مسافران با استفاده از این ویژگی نام خانوادگی به‌روزرسانی شده تعمیم می‌یابد.کد:drop table if exists titanic_train_test_wcg_v0;&#xA;&#xA;create table titanic_train_test_wcg_v0 as&#xA;&#xA;&#x9;select&#xA;&#x9;  round(avg(t3.survived) over (partition by t3.surname), 4) as surname_survival,&#xA;&#x9;  t3.*&#xA;&#x9;from&#xA;&#x9;(&#xA;&#x9;&#x9;select&#xA;&#x9;&#x9;  case when count(*) over (partition by t2.surname) &lt;= 1 then &#39;noGroup&#39; else t2.surname end as surname,&#xA;&#x9;&#x9;  count(*) over (partition by t2.surname) as surname_freq,&#xA;&#x9;  t2.title, t2.cohort,&#xA;&#x9;&#x9;  t2.passengerid, t2.survived,&#xA;&#x9;&#x9;  t2.pclass, t2.name, t2.sex,&#xA;&#x9;&#x9;  t2.age, t2.sibsp,&#xA;&#x9;&#x9;  t2.parch, t2.ticket,&#xA;&#x9;&#x9;  t2.fare, t2.cabin, t2.embarked&#xA;&#x9;&#x9;from&#xA;&#x9;&#x9;(&#xA;&#x9;&#x9;&#x9;select&#xA;&#x9;&#x9;&#x9;  case when trim(split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2)) in (&#39;Capt&#39;,&#39;Don&#39;,&#39;Major&#39;,&#39;Col&#39;,&#39;Rev&#39;,&#39;Dr&#39;,&#39;Sir&#39;,&#39;Mr&#39;,&#39;Jonkheer&#39;)&#xA;&#x9;&#x9;&#x9;       then &#39;noGroup&#39;&#xA;&#x9;&#x9;&#x9;       else trim(split_part(t1.name,&#39;,&#39;,1))&#xA;&#x9;&#x9;&#x9;  end as surname,&#xA;&#x9;&#x9;&#x9;  case when trim(split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2)) in (&#39;Capt&#39;,&#39;Don&#39;,&#39;Major&#39;,&#39;Col&#39;,&#39;Rev&#39;,&#39;Dr&#39;,&#39;Sir&#39;,&#39;Mr&#39;,&#39;Jonkheer&#39;) then &#39;man&#39;&#xA;&#x9;&#x9;&#x9;       when trim(split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2)) in (&#39;Dona&#39;,&#39;the Countess&#39;,&#39;Mme&#39;,&#39;Mlle&#39;,&#39;Ms&#39;,&#39;Miss&#39;,&#39;Lady&#39;,&#39;Mrs&#39;) then &#39;woman&#39;&#xA;&#x9;&#x9;&#x9;       when trim(split_part(split_part(t1.name,&#39;.&#39;,1),&#39;, &#39;,2)) = &#39;Master&#39; then &#39;boy&#39;&#xA;&#x9;&#x9;&#x9;  end as title,&#xA;&#x9;&#x9;&#x9;  t1.*&#xA;&#x9;&#x9;&#x9;from titanic_train_test_ra t1&#xA;&#x9;&#x9;) t2&#xA;&#x9;) t3&#xA;);در نهایت با استفاده از title و surname_survival، یک فلگ باینری جدید به نام title_surname_survival ایجاد کردم. من دو جدول برای ثبت هر کدام ایجاد کردم - titanic_train_ml_features_v0 و titanic_test_ml_features_v0.مجموعه داده آموزش ML: titanic_train_ml_features_v0مجموعه داده تست ML: titanic_test_ml_features_v0 (مورد یکسان با مجموعه داده آموزشی به جز ویژگی Survived وجود ندارد.)کد :drop table if exists titanic_train_ml_features_v0;&#xA;&#xA;create table titanic_train_ml_features_v0 as&#xA;(&#xA;&#x9;select&#xA;&#x9;  t1.survived,&#xA;&#x9;  t1.passengerid,&#xA;          t2.title_surname_survival,&#xA;&#x9;  t1.pclass,&#xA;&#x9;  t1.sex,&#xA;&#x9;  t1.age,&#xA;&#x9;  t1.age_bucket,&#xA;&#x9;  t1.fare,&#xA;&#x9;  t1.fare_bucket,&#xA;&#x9;  t1.title_grouping,&#xA;&#x9;  t1.is_woman_child,&#xA;&#x9;  t1.family_size,&#xA;&#x9;  t1.is_one_family,&#xA;&#x9;  t1.is_mix_group,&#xA;&#x9;  t1.is_alone,&#xA;&#x9;  t1.cabin_level,&#xA;&#x9;  t1.embarked&#xA;&#x9;from titanic_train_test_raw_v3 t1&#xA;&#x9;     left join&#xA;&#x9;     (&#xA;&#x9;       select&#xA;                 passengerid,&#xA;                 max(case when title = &#39;woman&#39; and surname_survival = 0 then 0&#xA;                          when title = &#39;woman&#39; and surname_survival &gt;= 0.75 then 1&#xA;                          when title = &#39;boy&#39; and surname_survival &gt;= 0.75 then 1&#xA;                          when title = &#39;woman&#39; and surname_survival is null then 1&#xA;                          when title = &#39;boy&#39; and surname_survival is null then 1&#xA;                          else 0&#xA;                 end) as title_surname_survival&#xA;&#x9;       from titanic_train_test_wcg_v0&#xA;&#x9;       group by 1&#xA;&#x9;     ) t2&#xA;&#x9;       on t1.passengerid = t2.passengerid&#xA;&#x9;where t1.cohort = &#39;train&#39;&#xA;);&#xA;&#xA;drop table if exists titanic_test_ml_features_v0;&#xA;&#xA;create table titanic_test_ml_features_v0 as&#xA;(&#xA;&#x9;select&#xA;&#x9;  t1.passengerid,&#xA;          t2.title_surname_survival,&#xA;&#x9;  t1.pclass,&#xA;&#x9;  t1.sex,&#xA;&#x9;  t1.age,&#xA;&#x9;  t1.age_bucket,&#xA;&#x9;  t1.fare,&#xA;&#x9;  t1.fare_bucket,&#xA;&#x9;  t1.title_grouping,&#xA;&#x9;  t1.is_woman_child,&#xA;&#x9;  t1.family_size,&#xA;&#x9;  t1.is_one_family,&#xA;&#x9;  t1.is_mix_group,&#xA;&#x9;  t1.is_alone,&#xA;&#x9;  t1.cabin_level,&#xA;&#x9;  t1.embarked&#xA;&#x9;from titanic_train_test_raw_v3 t1&#xA;&#x9;     left join&#xA;&#x9;     (&#xA;               select&#xA;                 passengerid,&#xA;                 max(case when title = &#39;woman&#39; and surname_survival = 0 then 0&#xA;                          when title = &#39;woman&#39; and surname_survival &gt;= 0.75 then 1&#xA;                          when title = &#39;boy&#39; and surname_survival &gt;= 0.75 then 1&#xA;                          when title = &#39;woman&#39; and surname_survival is null then 1&#xA;                          when title = &#39;boy&#39; and surname_survival is null then 1&#xA;                          else 0&#xA;                 end) as title_surname_survival&#xA;&#x9;       from titanic_train_test_wcg_v0&#xA;&#x9;       group by 1&#xA;&#x9;     ) t2&#xA;&#x9;       on t1.passengerid = t2.passengerid&#xA;&#x9;where t1.cohort = &#39;test&#39;&#xA;);خلاصهاطلاعات بسیار زیادی در این مقاله ارائه شده است. من تجزیه و تحلیل اکتشافی و مهندسی ویژگی خود را با استفاده از SQL صرف انجام دادم. از GROUP BY، توابع پنجره، توابع تجمع، subqueries، WITH clause، HAVING clause و سایر تکنیک‌های SQL برای slice و dice داده‌ها استفاده کردم.مرحله بعدی این است که مجموعه داده های آموزشی و آزمایشی نهایی را برای تجزیه و تحلیل با استفاده از پایتون پیاده سازی کنید. در مقاله بعدی خود، از Python برای آزمایش مدل‌های مختلف ML، درک اهمیت ویژگی و تنظیم مدل انتخابی با استفاده از RandomizedSearchCV و GridSearchCV خواهم پرداخت.منبع</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Thu, 24 Mar 2022 19:28:30 +0430</pubDate></item><item><title>بررسی kpi های یک مجموعه داده</title><link>https://virgool.ir/@vakily/بررسی-kpi-های-یک-مجموعه-داده-t4tlficrtrzx</link><description>شناخت معیارهای اصلی کسب و کار اولین قدم از تجزیه و تحلیل است. معیار هایی هدفشان تجزیه و تحلیل و ردیابی براساس با محصول، موقعیت، اهداف و موارد دیگر شرکت است. اکثر کسب و کارها همیشه شاخص های کلیدی عملکرد (KPI) خود را دنبال می کنند. در این مثال، KPI های اصلی که می توانند مربوط به حوزه درآمد باشند مانند درآمد، میانگین مقدار سفارش، فراوانی سفارش و ... بررسی خواهند شد.دیتاست انتخاب شده مربوط به یک خرده‌فروشی آنلاین مستقر در بریتانیا است که از 541909 ردیف و 8 ویژگی تشکیل شده است. (لینک دیتاست)path = &#34;data.csv&#34; &#xA;df = pd.read_csv( path, encoding = &#34;ISO-8859-1&#34;, parse_dates = [&#39;InvoiceDate&#39;] )&#xA;df.head()معرفی ویژگی های داده:ستون InvoiceNo: شماره فاکتورستون StockCode: کد موجودی کالاستون Description: توضیحات محصولستون Quantity: تعداد اقلام خریداری شدهستون InvoiceDate: تاریخی که سفارش فاکتور شده است.ستون UnitPrice: قیمت هر کالاستون CustomerID: شناسه منحصر به فرد مشتریستون Country: کشوری که سفارش از آن انجام شده است.محاسبه میزان درآمد به ازای هر کشور# calculate Revenue for each row&#xA;df[&#39;Revenue&#39;] = df[&#39;UnitPrice&#39;] * df[&#39;Quantity&#39;]&#xA;&#xA;# we look at the revenue by country&#xA;revenue_country = pd.DataFrame(df.groupby(&#39;Country&#39;)[&#39;Revenue&#39;].agg(sum).sort_values(ascending=False)).reset_index()&#xA;&#xA;plt.figure(figsize=(15,13))&#xA;sns.set_theme(style=&#34;whitegrid&#34;)&#xA;ax = sns.barplot(y=&#34;Country&#34;, x=&#34;Revenue&#34;, data=revenue_country)&#xA;ax.set_title(&#34;Revenue Countries&#34;)&#xA;plt.show()بالای 90 درصد دیتای کاربران از کشور UK بوده است بنابراین برای دستیابی به اهدف این تجزیه و تحلیل، بر روی مشتریان همین کشور تمرکز خواهیم کرد.میزان درآمد ماهانه# create a new dataframe with YearMonth and Revenue columns&#xA;revenue = df_uk.groupby([&#39;InvoiceYearMonth&#39;])[&#39;Revenue&#39;].sum().reset_index()&#xA;revenue.head()&#xA;&#xA;# line chart showing the monthly revenue&#xA;plt.figure(figsize=(15,13))&#xA;sns.set_theme(style=&#34;whitegrid&#34;)&#xA;ax = sns.barplot(y=&#34;InvoiceYearMonth&#34;, x=&#34;Revenue&#34;, data=revenue)&#xA;ax.set_title(&#34;Revenue&#34;)&#xA;plt.show()نمودار بالا روند صعودی درآمد تولید شده تا نوامبر 2011 را نشان می دهد (زیرا داده های دسامبر ناقص است). تا آگوست 2011، کسب و کار ماهیانه بین 400 تا 600 هزار درآمد داشت، از آن زمان تاکنون، درآمد کسب و کار به طور چشمگیری افزایش یافته و به بیش از 1.2 میلیون در نوامبر 2011 رسیده است.حال برای دستیابی به کنکاش های بیشتر، نرخ رشد ماهانه را محاسبه می کنیم.revenue[&#39;MonthlyGrowth&#39;] = revenue[&#39;Revenue&#39;].pct_change()&#xA;revenue[&#39;positive&#39;] = revenue[&#39;MonthlyGrowth&#39;] &gt; 0&#xA;plt.figure(figsize=(15,13))&#xA;clrs = revenue.positive.map({True: &#39;darkgreen&#39;, False: &#39;brown&#39;})&#xA;ax = sns.barplot(x=revenue.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;InvoiceYearMonth&#39;],&#xA;                 y=round(revenue.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;MonthlyGrowth&#39;]*100,2),&#xA;                 data=revenue,&#xA;                 palette=clrs)&#xA;ax.set_title(&#34;Revenue&#34;)&#xA;plt.show()ماه سپتامبر با رشد تقریبی 60 درصدی نسبت به ماه های قبل بوده است. همچنین نوامبر نیز با رشد 46.2 درصدی، ماه بسیار خوبی بوده است. ماه های مارس و می هر دو بیش از 30 درصد افزایش یافته اند، اما این ممکن است به دلیل عملکرد ضعیف ماه های قبل باشد.ژانویه و آوریل 2011 عملکرد ضعیفی دارند.کاربران فعال ماهانهmonthly_active = df_uk.groupby(&#39;InvoiceYearMonth&#39;)[&#39;CustomerID&#39;].nunique().reset_index() monthly_active.columns = [&#39;InvoiceYearMonth&#39;,&#39;ActiveCustomers&#39;] &#xA;plt.figure(figsize=(13,7)) plot_data = sns.barplot(x=monthly_active.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;InvoiceYearMonth&#39;], y=monthly_active.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;ActiveCustomers&#39;]) &#xA;ax.set_title(&#34;Monthly Active Customers&#34;)&#xA;plt.show()monthly_active[&#39;ActiveCustomersRate&#39;] = monthly_active[&#39;ActiveCustomers&#39;].pct_change()&#xA;monthly_active[&#39;positive&#39;] = monthly_active[&#39;ActiveCustomersRate&#39;] &gt; 0&#xA;plt.figure(figsize=(13,7))&#xA;ax = sns.barplot(x=monthly_active.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;InvoiceYearMonth&#39;],&#xA;y=round(monthly_active.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;ActiveCustomersRate&#39;]*100,2),&#xA;palette=monthly_active.positive.map({True: &#39;darkgreen&#39;, False: &#39;brown&#39;}))&#xA;ax.set_title(&#34;Monthly Active Customers Rate&#34;)&#xA;plt.show()در ژانویه، شرکت تقریباً 200 مشتری خود را از دست داد که از 871 در دسامبر به 684 در ژانویه رسید که نشان دهنده -21.47٪ کاهش است. به طور مشابه، در ماه آوریل کسب و کار از 923 مشتری به 817 رسید که نشان دهنده کاهش 11.48 درصدی است.میزان سفارشات ماهانهmonthly_orders = df_uk.groupby(&#39;InvoiceYearMonth&#39;)[&#39;InvoiceNo&#39;].nunique().reset_index()&#xA;monthly_orders.columns = [&#39;InvoiceYearMonth&#39;,&#39;Orders&#39;]&#xA;plt.figure(figsize=(13,7))&#xA;ax = sns.barplot(x=monthly_orders.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;InvoiceYearMonth&#39;],&#xA;y=monthly_orders.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;Orders&#39;])&#xA;ax.set_title(&#34;Monthly Orders&#34;)&#xA;plt.show()monthly_orders[&#39;OrdersRate&#39;] = monthly_orders[&#39;Orders&#39;].pct_change()&#xA;monthly_orders[&#39;positive&#39;] = monthly_orders[&#39;OrdersRate&#39;] &gt; 0&#xA;plt.figure(figsize=(13,7))&#xA;ax = sns.barplot(x=monthly_orders.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;InvoiceYearMonth&#39;],&#xA;y=round(monthly_orders.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;OrdersRate&#39;]*100,2),&#xA;palette=monthly_orders.positive.map({True: &#39;darkgreen&#39;, False: &#39;brown&#39;}))&#xA;ax.set_title(&#39;Monthly Orders Rate&#39;)&#xA;plt.show()تعداد سفارش ها بین دسامبر و فوریه کاهش یافته است و از 1885 به 1259 سفارش رسیده است که نشان دهنده -33.21٪ کاهش است. سفارشات تا ماه می افزایش یافتند. سفارشات دوباره تا آگوست 27.72-% کاهش یافت و در نهایت تا نوامبر افزایش یافته است.میانگین ماهانه سفارشاتmonthly_aov = monthly_aov.groupby(&#39;InvoiceYearMonth&#39;)[&#39;Revenue&#39;].mean().reset_index()&#xA;monthly_aov.columns = [&#39;InvoiceYearMonth&#39;,&#39;AOV&#39;]&#xA;plt.figure(figsize=(13,7))&#xA;ax = sns.barplot(x=monthly_aov.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;InvoiceYearMonth&#39;],&#xA;y=round(monthly_aov.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;AOV&#39;],2))&#xA;ax.set_title(&#39;Monthly AOV&#39;)&#xA;plt.show()# calculate the monthly orders rate&#xA;monthly_aov[&#39;AOVRate&#39;] = monthly_aov[&#39;AOV&#39;].pct_change()&#xA;# bar chart showing the monthly orders rate&#xA;monthly_aov[&#39;positive&#39;] = monthly_aov[&#39;AOVRate&#39;] &gt; 0&#xA;plt.figure(figsize=(13,7))&#xA;ax = sns.barplot(x=monthly_aov.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;InvoiceYearMonth&#39;],&#xA;y=round(monthly_aov.query(&#34;InvoiceYearMonth &lt; 201112&#34;)[&#39;AOVRate&#39;]*100,2),&#xA;palette=monthly_aov.positive.map({True: &#39;darkgreen&#39;, False: &#39;brown&#39;}))&#xA;ax.set_title(&#39;Monthly AOV Rate&#39;)&#xA;plt.show()نرخ مشتریان جدیدمشتریان جدید یعنی کسانی که برای اولین بار در بازه زمانی تعیین شده خرید کرده اند. لازم به ذکر است اولین و آخرین ماه دیتاست را در نظر نمی گیریم.first_order = df_uk.groupby(&#39;CustomerID&#39;).InvoiceDate.min().reset_index()&#xA;first_order.columns = [&#39;CustomerID&#39;,&#39;FirstOrder&#39;]&#xA;first_order[&#39;FirstOrder&#39;] = first_order[&#39;FirstOrder&#39;].map(lambda date: 100*date.year + date.month)&#xA;# merge first purchase date column to our main dataframe (df_uk)&#xA;df_uk = pd.merge(df_uk, first_order, on=&#39;CustomerID&#39;)&#xA;&#xA;df_uk[&#39;UserType&#39;] = &#39;New&#39;&#xA;df_uk.loc[df_uk.InvoiceYearMonth != df_uk.FirstOrder,&#34;UserType&#34;] = &#39;Existing&#39;&#xA;&#xA;new_customer_ratio = df_uk.query(&#34;UserType == &#39;New&#39;&#34;).groupby([&#39;InvoiceYearMonth&#39;])[&#39;CustomerID&#39;].nunique()/df_uk.query(&#34;UserType == &#39;Existing&#39; or UserType == &#39;New&#39;&#34;).groupby([&#39;InvoiceYearMonth&#39;])[&#39;CustomerID&#39;].nunique()&#xA;new_customer_ratio = new_customer_ratio.reset_index()&#xA;new_customer_ratio = new_customer_ratio.dropna()&#xA;&#xA;new_customer_ratio.columns = [&#39;InvoiceYearMonth&#39;,&#39;NewCustomerRatio&#39;]&#xA;&#xA;&#xA;customer_type_revenue = df_uk.groupby([&#39;InvoiceYearMonth&#39;,&#39;UserType&#39;])[&#39;Revenue&#39;].sum().reset_index()&#xA;&#xA;plt.figure(figsize=(13,7))&#xA;data = customer_type_revenue.query(&#34;InvoiceYearMonth != 201112 and InvoiceYearMonth != 201012&#34;)&#xA;ax = sns.barplot(x =&#34;InvoiceYearMonth&#34;, y = &#39;Revenue&#39;, data = data, hue = &#34;UserType&#34;)&#xA;ax.set_title(&#39;Monthly New vs Existing Customer Revenue&#39;)&#xA;plt.show()در نمودار بالا می‌بینیم که درآمد مشتریان جدید با گذشت زمان کاهش می‌یابد، این ممکن است به این دلیل باشد که ما فقط برای یک سال داده داریم.محاسبه نرخ حفظ مشتریاین تجزیه و تحلیل به درک میزان حفظ مشتریان پس از یک دوره زمانی مشخص کمک می کند.def cohort_period(df):&#xA;   df[&#39;CohortPeriod&#39;] = np.arange(len(df)) + 1&#xA;   return df&#xA;&#xA;df_cohort = df_uk.groupby([&#39;FirstOrder&#39;,&#39;InvoiceYearMonth&#39;])&#xA;df_cohort = df_cohort.agg({&#39;CustomerID&#39;: pd.Series.nunique})&#xA;df_cohort.rename(columns={&#39;CustomerID&#39;: &#39;Nb_Customers&#39;}, inplace=True)&#xA;df_cohort = df_cohort.groupby(level=0).apply(cohort_period)&#xA;cohorts = df_cohort[&#39;Nb_Customers&#39;].unstack(0)&#xA;cohort_retention = df_cohort[&#39;Nb_Customers&#39;].unstack(0).divide(cohort_group_size, axis=1)&#xA;sns.set(style=&#39;white&#39;)&#xA;plt.figure(figsize=(12, 8))&#xA;plt.title(&#39;Customers Cohorts Retention&#39;)&#xA;sns.heatmap(cohort_retention.T, mask=cohort_retention.T.isnull(), annot=True, fmt=&#39;.0%&#39;)در طول یک سال، این شرکت تنها 27 درصد از مشتریان خود را حفظ کرده است.در این نوشته سعی شد با استفاده از ابزار های پایتونی تجزیه و تحلیل انجام شود، امید است که در آینده این تحلیل با استفاده SQL پیاده سازی شود.منبع</description><category>ابوالفضل وکیلی</category><author>ابوالفضل وکیلی</author><pubDate>Wed, 23 Mar 2022 14:42:03 +0430</pubDate></item></channel></rss>