مطالب
افزونه rtlColResizable جهت تغییر سایز ستون‌های جدول‌های راست به چپ HTML
برای تغییر سایز ستون‌های جداول HTML با استفاده از ماوس، افزونه‌های زیادی تدارک دیده شده است که از جمله مطرح‌ترین آن‌ها می‌توان به colResizable اشاره کرد. حتی اگر از DataGrid‌های مطرح وب هم استفاده کرده باشید، اکثر آن‌ها از تغییر سایز ستون‌ها توسط کاربر پشتیبانی می‌کنند. اما مشکل بزرگی که در همه‌ی آن‌ها مشترک است  این است که فقط از چیدمان‌های چپ به راست پشتیبانی می‌کنند و به محض اینکه شما ساختار راست به چپ را به جدول مورد نظر اعمال کنید، عملکرد تغییر سایز ستون‌ها با اشکال مواجه می‌شود.
به همین جهت برای تغییر سایز ستون‌ها توسط کاربر، افزونه ای برای jQuery تدارک دیدم که با جداول معمول HTML که همان table‌ها هستند سازگار است و به راحتی به هر جدولی می‌توان آن را اعمال کرد.
 
کدهای افزونه‌ی rtlColResizable:
(function ($, undefined) {

    $.fn.extend({
        'rtlColResizable': function (options) {
            var defaults = {
                //Default values for the plugin's options here
            };

            options = $.extend(defaults, options);

            var isMouseButtonPressed;
            var $resizingElement = undefined;
            var resizingElementStartWidth;
            var mouseCursorStartX;
            var isCursorInResizingPosition;

            var addResizingCursorStyle = function ($element) {
                $element.css({
                    'cursor': 'col-resize',
                    'user-select': 'none',
                    '-o-user-select': 'none',
                    '-ms-user-select': 'none',
                    '-moz-user-select': 'none',
                    '-khtml-user-select': 'none',
                    '-webkit-user-select': 'none',
                });
            };

            var removeResizingCursorStyle = function ($element) {
                $element.css({
                    'cursor': 'default',
                    'user-select': 'text',
                    '-o-user-select': 'text',
                    '-ms-user-select': 'text',
                    '-moz-user-select': 'text',
                    '-khtml-user-select': 'text',
                    '-webkit-user-select': 'text',
                });
            };

            var canResize = function (e) {
                return (e.offsetX || e.clientX - $(e.target).offset().left) < 10;
            };

            return this.each(function () {

                var opts = options;
                var tableColumns = $(this).find('th');

                tableColumns.filter(':not(:last-child)').mousedown(function (e) {

                    $resizingElement = $(this);
                    isMouseButtonPressed = true;
                    mouseCursorStartX = e.pageX;
                    resizingElementStartWidth = $resizingElement.width();

                });

                tableColumns.mousemove(function (e) {

                    if (canResize(e)) {
                        addResizingCursorStyle($(e.target));
                        isCursorInResizingPosition = true;

                    } else if (!isMouseButtonPressed) {
                        removeResizingCursorStyle($(e.target));
                        isCursorInResizingPosition = false;
                    }

                    if (isCursorInResizingPosition && isMouseButtonPressed) {

                        $resizingElement.width(resizingElementStartWidth + (mouseCursorStartX - e.pageX));
                    }

                });

                $(document).mouseup(function () {
                    if (isMouseButtonPressed) {
                        removeResizingCursorStyle($resizingElement);
                        isMouseButtonPressed = false;
                    }

                });

            });
        }
    });

})(jQuery);
 
نحوه‌ی استفاده:
این افزونه با تگ Table در HTML سازگار است. فقط تنها موردی که باید رعایت شود این است که در هنگام تعریف ساختار جدول، باید استاندارد تعریف ستون‌ها یا همان Header‌ها را رعایت کنید و از تگ‌های thead و th استفاده کنید.
نمونه ای از نحوه‌ی استفاده از آن را در کدهای زیر می‌بینید:
<!DOCTYPE html>
<html>
<head>
    <title>rtlColResizable Sample</title>
</head>
<body>
    <table id="myTable">
        <thead>
            <tr>
                <th>ستون1</th> <!-- نام ستون‌ها را حتما در این تگ باید تعریف کنید -->
                <th>ستون2</th>
                <th>ستون3</th>
            </tr>
        </thead>
        <tr>
            <td>داده مربوط به ستون 1</td>
            <td>داده مربوط به ستون 2 </td>
            <td>داده مربوط به ستون 3</td>
        </tr>
    </table>

    <script type="text/javascript" src="jquery-1.9.1.min.js"></script>
    <script type="text/javascript" src="jquery.rtlColResizable.js"></script>
    <script>

        $('table#myTable').rtlColResizable();

    </script>
</body>
</html>
     
دریافت نمونه کدی از نحوه‌ی استفاده از این افزونه
 
مطالب
مرور چند تجربه کوتاه با Microsoft virtual pc

از virtual pc که یک ویندوز اکس پی بر روی آن نصب کرده‌ام برای اتصال به VPN‌ استفاده می‌کنم. (متاسفانه آخرین نگارش vmware برای این‌کار جواب نداد)
زمان اتصال به VPN کل سیستم وارد شبکه مورد نظر خواهد شد و این مورد شاید به‌دلایلی برای مثال قطع اینترنت و یا اعمال پالیسی‌های شبکه بر روی کامپیوتر کاری جالب نباشد (استفاده از VPN برای اتصال به یک شبکه دومین ویندوزی). اما با نصب ماشین مجازی و اجرای یک سیستم عامل دیگر به موازات سیستم عامل اصلی، کار اتصال به VPN از داخل ماشین مجازی صورت خواهد گرفت و تمام این اعمال هم از سیستم عامل مادر مجزا و ایزوله خواهند بود.
یک ویندوز اکس پی با اختصاص 200 مگ رم هم کار می‌کند و عملا باری را بر روی سیستم عامل مادر تحمیل نخواهد کرد. همچنین حتما از منوی action گزینه install or update virtual machine additions را انتخاب کنید تا کارآیی سیستم عامل مجازی را بهبود بخشید. حداقل فایده آن این است که اشاره‌گر ماوس را به سادگی می‌توان از ماشین مجازی خارج کرد و هر بار نیازی به فشردن دکمه‌ ALT سمت راست نخواهد بود!
اولین مشکلی که هنگام کار با یک ماشین مجازی خود نمایی می‌کند بحث انتقال فایل بین سیستم عامل مادر (ویندوزی که شما ماشین مجازی را روی آن نصب کرده‌اید) و ماشین مجازی است. عمومی‌ترین راه، ایجاد یک فایل iso از فایل‌های مورد نظر است و سپس انتخاب منوی CD و گزینه capture iso image . این روش بر روی vmware هم جواب می‌دهد (معرفی فایل iso بعنوان CD-ROM آن). خوشبختانه عمل drag & drop (از سیستم عامل مادر به ماشین مجازی) که شاید در وحله اول به ذهن نرسد اینجا بخوبی کار خواهد کرد و مشکل ساخت فایل‌های iso را برطرف می‌کند. (البته vmware کمی پیشرفته‌تر است و حتی copy و Paste را نیز پشتیبانی می‌کند. اما خوب، رایگان نیست!)
مشکل بعدی با ms virtual pc افزایش تدریجی حجم آن است. روز اول 2 گیگ، روز سوم 4 گیگ، هفته بعد می‌شود 6 گیگ! برای فشرده سازی آن می‌توان به روش زیر عمل کرد:
به مسیر زیر مراجعه کنید: (اگر پیش‌فرض‌های نصب را پذیرفته‌اید)
C:\Program Files\Microsoft Virtual PC\Virtual Machine Additions
فایل Virtual Disk Precompactor.iso را از طریق منوی CD و گزینه capture iso image باز کنید. برنامه‌ای به صورت خودکار اجرا خواهد شد که سیستم عامل مجازی را آماده فشرده سازی می‌کند. پس از پایان کار، سیستم عامل مجازی را خاموش کنید. سپس به منوی file گزینه virtual disk wizard مراجعه نمائید. در صفحه بعدی گزینه ویرایش یک ماشین مجازی موجود را انتخاب کرده و فایل ماشین مجازی مورد نظر را که پیشتر برای فشرده سازی آماده کردیم به آن معرفی کنید. در صفحه بعد گزینه compact it را انتخاب کرده و در ادامه می‌توانید مسیر جدیدی را مشخص کنید یا انتخاب کنید که فایل نهایی فشرده شده جایگزین فایل موجود شود.
با اینکار یک ماشین مجازی 6 گیگابایتی به 3 گیگ کاهش حجم یافت که قابل توجه است.
برای استفاده از اینترنت سیستم عامل مادر در ms virtual pc می‌شود از منوی edit ، گزینه setting و انتخاب networking در صفحه ظاهر شده، تنظیم اولین adapter شبکه را بر روی shared networking NAT قرار داد و همه چیز به خوبی کار خواهد کرد. (البته برای استفاده از اینترنت در vmware باید روی کانکشن اینترنت خود در سیستم عامل مادر کلیک راست کرد و سپس انتخاب گزینه advanced و فعال سازی internet connection sharing بر روی کارت شبکه مجازی نصب شده آن ضروری خواهد بود)



بازخوردهای پروژه‌ها
اضافه کردن چند متد الحاقی
با سلام من توی پروژه هام چند تا متد استفاده می‌کنم. خوشحال می‌شم نظر شمارو هم بدونم و به پروژه اتون اضافه اش کنید.

این متد برای محاسبه اختلاف دو تاریخ استفاده میشه، البته منبعش یادم نیست این متد از کجا گرفتم:
/// <summary>
        /// DateDiff in SQL style.
        /// Datepart implemented:
        ///     "year" (abbr. "yy", "yyyy"),
        ///     "quarter" (abbr. "qq", "q"),
        ///     "month" (abbr. "mm", "m"),
        ///     "day" (abbr. "dd", "d"),
        ///     "week" (abbr. "wk", "ww"),
        ///     "hour" (abbr. "hh"),
        ///     "minute" (abbr. "mi", "n"),
        ///     "second" (abbr. "ss", "s"),
        ///     "millisecond" (abbr. "ms").
        /// </summary>
        /// <param name="startDate"></param>
        /// <param name="datePart"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public static Int64 DateDiff(this DateTime startDate, String datePart, DateTime endDate)
        {
            Int64 dateDiffVal;
            System.Globalization.Calendar cal = System.Threading.Thread.CurrentThread.CurrentCulture.Calendar;
            TimeSpan ts = new TimeSpan(endDate.Ticks - startDate.Ticks);
            switch (datePart.ToLower().Trim())
            {
                #region year

                case "year":
                case "yy":
                case "yyyy":
                    dateDiffVal = cal.GetYear(endDate) - cal.GetYear(startDate);
                    break;

                #endregion

                #region quarter

                case "quarter":
                case "qq":
                case "q":
                    dateDiffVal = (((cal.GetYear(endDate) - cal.GetYear(startDate)) * 4) + ((cal.GetMonth(endDate) - 1) / 3)) - ((cal.GetMonth(startDate) - 1) / 3);
                    break;

                #endregion

                #region month

                case "month":
                case "mm":
                case "m":
                    dateDiffVal = ((cal.GetYear(endDate) - cal.GetYear(startDate)) * 12 + cal.GetMonth(endDate)) - cal.GetMonth(startDate);
                    break;

                #endregion

                #region day

                case "day":
                case "d":
                case "dd":
                    dateDiffVal = (Int64)ts.TotalDays;
                    break;

                #endregion

                #region week

                case "week":
                case "wk":
                case "ww":
                    dateDiffVal = (Int64)(ts.TotalDays / 7);
                    break;

                #endregion

                #region hour

                case "hour":
                case "hh":
                    dateDiffVal = (Int64)ts.TotalHours;
                    break;

                #endregion

                #region minute

                case "minute":
                case "mi":
                case "n":
                    dateDiffVal = (Int64)ts.TotalMinutes;
                    break;

                #endregion

                #region second

                case "second":
                case "ss":
                case "s":
                    dateDiffVal = (Int64)ts.TotalSeconds;
                    break;

                #endregion

                #region millisecond

                case "millisecond":
                case "ms":
                    dateDiffVal = (Int64)ts.TotalMilliseconds;
                    break;

                #endregion

                default:
                    throw new Exception(String.Format("DatePart \"{0}\" is unknown", datePart));
            }
            return dateDiffVal;
        }

بررسی اینکه آیا رشته ورودی به الگوی مورد نظر مطابقت دارد یا خیر؟
/// <summary>
        /// بررسی اینکه رشته وارد شده با قالب مورد نظر مطابقت دارد یا خیر
        /// </summary>
        /// <param name="source">متن وارد شده</param>
        /// <param name="regexTemplate">قالب مورد نظر</param>
        /// <returns></returns>
        public static Boolean IsMatchTemplate(this String source, String regexTemplate)
        {
            var regex = new Regex(regexTemplate);
            return regex.IsMatch(source);
        }
البته متدهای زیادی دارم می‌ترسم وجهه خوبی نداشته باشه همش اینجا بذارم، با اجازه مدیریت سایت در صورت تمایل ایمیلتون بهم پیام خصوصی بدین، که متد هارو براتون ارسال کنم.

نظرات مطالب
Blazor 5x - قسمت 34 - توزیع برنامه‌های Blazor بر روی IIS
اضافه شدن قابلیت کامپایل AOT به Blazor 6x

Blazor WebAssembly 6x به همراه قابلیتی است به نام ahead-of-time (AOT) compilation که در این حالت، کدهای دات نتی برنامه، مستقیما به native WebAssembly کامپایل می‌شوند. این مورد سبب بالا رفتن کارآیی برنامه خواهد شد؛ در عوض بالا رفتن حجم نهایی قابل توزیع.
اگر از AOT compilation استفاده نشود (یعنی حالت متداول)، Blazor WebAssembly در مرورگر، به کمک مفسر IL یا همان NET Intermediate Language. که به صورت WebAssembly تهیه شده‌است، اجرا خواهد شد. یک چنین حالتی به دلیل استفاده‌ی از مفسر، نسبت به حالت استفاده‌ی از JIT سمت سرور (یا همان NET just-in-time (JIT) runtime.)، اندکی کندتر است. AOT compilation جهت رفع یک چنین کمبودی ارائه شده‌است تا کدهای دات نتی را مستقیما و بدون نیاز به مفسر، تبدیل به یک native WebAssembly کند. این مورد سرعت و کارآیی برنامه‌هایی را که کارهای محاسباتی مبتنی بر CPU را انجام می‌دهند، به نحو قابل ملاحظه‌ای افزایش می‌دهد. در مقابل باید درنظر داشت که حجم نهایی WebAssembly‌های واقعی تولید شده، از نمونه‌ی IL آن‌ها بالاتر است (حدود 2 برابر) که مدت زمان ابتدایی دریافت برنامه را افزایش می‌دهند.

روش فعالسازی کامپایل AOT

ابتدا نیاز است work load آن‌را توسط دستور زیر دریافت کرد (ابزارهای کامپایل AOT، جزئی از SDK نیستند):
dotnet workload install wasm-tools
سپس برای فعالسازی آن می‌توان تنظیم زیر را به فایل csporj پروژه‌های WASM اضافه کرد:
<PropertyGroup>
  <RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>
در این حالت با publish برنامه توسط دستور dotnet publish -c Release، مراحل تولید native WebAssemblyها طی می‌شوند و باید درنظر داشت که به علت کند بودن این پروسه، تنها در زمان publish نهایی، شاهد این عملیات خواهید بود و نه در زمان اجرای برنامه در حالت توسعه.

یک نکته: هنوز در نگارش 6.0 RTM، یکسری از قابلیت‌های AOT اضافه نشده‌اند که باید منتظر سرویس‌پک‌های آن بود. برای مثال اگر این کامپایل، بر روی پروژه‌ای که فقط سورس کد است اجرا شود، با موفقیت به پایان می‌رسد؛ اما با اضافه شدن کتابخانه‌های ثالث ممکن است با شکست مواجه شود. اگر در این حالت خطایی را دریافت کردید، عملیات publish را به صورت dotnet publish -p:RunAOTCompilation=true -bl انجام دهید. سوئیچ bl- سبب می‌شود تا فایلی به نام msbuild.binlog در ریشه‌ی پروژه‌ی شما تولید شود. این فایل در حقیقت لاگ باینری MSBuild است که توسط برنامه‌ی Viewer آن قابل مشاهده‌است. در اینجا به دنبال exit code‌ها بگردید؛ یک نمونه‌ی آن.
مطالب
بررسی روش نصب و استفاده از پیش نمایش NET Core 2.2.

نسخه net core 2.2. Preview 3.، روز چهارشنبه 25 مهر، مطابق با 17 اکتبر منتشر شد. این نسخه شامل ویژگی‌های جدیدی از جمله موارد زیر می‌باشد:

  • تغییرات عمده در API 
  • Authorization Server
  • بهبود کارآیی و سرعت
  • پشتیبانی از Spatial Data برای SQL Server و SQLite
  • پشتیبانی از Cosmos DB
  • جایگزینی Bootstrap 4, Angular 6

مهمترین ویژگی مربوط به EF Core برای گروهی از برنامه نویسان، پشتیبانی از فیلدهای جغرافیایی یا همان Spatial Data می‌باشد.

نسخه‌ی net core 2.2 RTM.،  قبل از انتهای سال میلادی جاری منتشر خواهد شد و پس از آن آغاز به کار بر روی net core 3. خواهد بود. برای  نسخه‌ی net Core 3.، هدف بهبود برنامه‌های مبتنی بر Desktop و سازگاری آن با فرمت جدید csproj، اعلام شده‌است.


برای استفاده از ویژگی‌های net core 2.2. باید نسخه‌ی visual studio 2017 preview، یعنی ورژن Version 15.9.0 به بعد را نصب کنید. اگر صرفا dotnet core 2.2 را نصب کنید و از ویژوال استودیوی جاری قصد استفاده را داشته باشید، به شما پیغام می‌دهد که این نسخه قابلیت استفاده از دات نت 2.2 به بعد را ندارد.



برای تست و استفاده از net core 2.2 preview 3. مراحل زیر را طی کنید:

1- ابتدا آخرین انتشار ویژوال استودیو 2017، یعنی نسخه‌ی ‌پیش‌نمایش preview را از اینجا دریافت و نصب کنید. نسخه Enterprise را انتخاب کنید تا installer دانلود شود وشروع به نصب کند. حجم این نسخه، از نسخه‌ی اصلی کمتر می‌باشد.

                                                 پس از نصب، این نسخه را می‌توانید در کنار نسخه‌ی اصلی، همزمان بر روی سیستم داشته باشید. 

2- سپس net core 2.2. را به یکی از روش‌های زیر نصب کنید:
  • برای نصب کلی بر روی سیستم،  اینجا کلیک کنید و نسخه‌ی SDK Installer مناسب دستگاه خود را دانلود کنید (64 یا 32 بیتی).
         در صورت موفقیت آمیز بودن، صفحه‌ی پایانی را به شکل زیر خواهید دید:

  • برای استفاده‌ی از EF Core آن در پروژه جاری می‌توانید آن‌‌را از اینجا  دانلود و یا بوسیله‌ی دستور زیر نصب کنید:
Install-Package Microsoft.EntityFrameworkCore -Version 2.2.0-preview3-35497

3- پس از نصب، ویژوال استودیوی preview را از همان مسیر visual studio، اجرا کنید. یک پروژه‌ی جدید از نوع وب را ایجاد کنید و فریمورک را بر روی بالاترین مقدار آن قرار دهید؛ مثل تصویر زیر:


بعد از ایجاد پروژه، می‌توانید در solution Explorer، ارجاعات جدید را مشاهده کنید:


مطالب
بررسی کارآیی کوئری‌ها در SQL Server - قسمت ششم - بررسی عملگرهای دسترسی به داده‌ها در یک Query Plan
پس از آشنایی مقدماتی با نحوه‌ی خواندن یک Query Plan، اکنون نوبت به بررسی عملگرهایی است که در آن مشاهده می‌شوند و همچنین تغییرات در کوئری‌ها چگونه بر روی آن‌ها تاثیر گذاشته و آن‌ها را تغییر می‌دهند و این تغییرات چه تاثیری را بر روی کارآیی خواهند داشت.


عملگرهای Scans و Seeks

در حالت کلی می‌توان دو نوع جدول بدون و با ایندکس را درنظر گرفت. در حالت جداول بدون ایندکس، برای جستجوی اطلاعات نیاز به Table Scan وجود دارد و برعکس آن شامل یک Clustered index scan خواهد بود. گاهی از اوقات Clustered index scanها بهترین روش دریافت اطلاعات هستند و گاهی از اوقات خیر و نیاز به بررسی بیشتری دارند. بنابراین قانون کلی، حذف آن‌ها به محض مشاهده، نیست.
نوع دیگر عملگرهای دسترسی به داده‌ها، Seeks هستند که شامل Clustered index seeks و Non-clustered index seeks می‌شوند. در بسیاری از موارد عنوان می‌شود که Seeks کارآیی بهتری را به همراه دارند. هرچند این مورد نیاز به بررسی بیشتری دارد که در ادامه با مثال‌هایی آن‌ها را مرور خواهیم کرد.


بررسی عملگر Table scan در یک Query Plan

در ادامه تعدادی از عملگرهای مرتبط با data access را از لحاظ نحوه‌ی انتخاب و تغییر آن‌ها توسط بهینه ساز کوئری‌های SQL Server بررسی می‌کنیم. برای این منظور ابتدا در management studio از منوی Query، گزینه‌ی Include actual execution plan را انتخاب می‌کنیم. سپس کوئری‌های زیر را اجرا می‌کنیم:
SET STATISTICS IO ON;
GO
SET STATISTICS TIME ON;
GO

SELECT *
INTO [Sales].[Copy_Orders]
FROM [Sales].[Orders];
GO

SELECT
    [CustomerID],
    [OrderID],
    [OrderDate]
FROM [Sales].[Copy_Orders]
WHERE [CustomerID] > 550;
GO
در اینجا در ابتدا، تمام رکوردهای جدول [Sales].[Orders]، به جدول [Sales].[Copy_Orders] کپی می‌شوند. سپس یک کوئری را بر روی این جدول کپی، اجرا کرده‌ایم.


همانطور که مشاهده می‌کنید، برای برآورده کردن قسمت where این کوئری، یک Table Scan صورت گرفته‌است؛ چون این جدول کپی، به همراه هیچ ایندکسی نیست. به همین جهت برای یافتن رکوردهای مدنظر، راه دیگری بجز اسکن کل جدول بانک اطلاعاتی وجود ندارد که بسیار ناکارآمد است.
همچنین اگر به برگه‌ی messages دقت کنیم، با توجه به روشن بودن STATISTICS IO، میزان logical reads نیز قابل مشاهده‌است:
(33035 rows affected)
Table 'Copy_Orders'. Scan count 1, logical reads 689, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
به علاوه اجرای آن نیز کمی بیشتر از نیم ثانیه، طول کشیده‌است:
SQL Server Execution Times:
CPU time = 79 ms,  elapsed time = 762 ms.


بررسی عملگر Index Seek در یک Query Plan

اکنون سؤال اینجا است که آیا می‌توان این وضعیت را بهبود بخشید؟
بله. برای این منظور یک NONCLUSTERED INDEX را بر روی جدول کپی، ایجاد می‌کنیم؛ به نحوی که CustomerID لحاظ شده‌ی در قسمت where کوئری را پوشش دهد:
CREATE NONCLUSTERED INDEX [IX_Copy_Orders_CustomerID]
ON [Sales].[Copy_Orders] (
[CustomerID]
)
INCLUDE (
[OrderID], [OrderDate]
);
GO
چون مطابق کوئری، [OrderID] و [OrderDate] در قسمت where ذکر نشده‌اند، در اینجا INCLUDE شده‌اند.

در ادامه مجددا همان کوئری را اجرا می‌کنیم:
SELECT
    [CustomerID],
    [OrderID],
    [OrderDate]
FROM [Sales].[Copy_Orders]
WHERE [CustomerID] > 550;
GO
که سبب تولید کوئری پلن زیر می‌شود:


اینبار عملگر Table Scan قبلی به یک عملگر Index Seek بر روی NONCLUSTERED INDEX تعریف شده، تغییر کرده‌است و اگر به آمار I/O آن دقت کنیم، logical reads 106 قابل مشاهده‌است که بهبود قابل ملاحظه‌ای است نسبت به عدد 689 قبلی.


بررسی عملگر Clustered index scan در یک Query Plan

در ادامه همین کوئری را بر روی جدول [Sales].[Orders] اصلی اجرا می‌کنیم:
SELECT
    [CustomerID],
    [OrderID],
    [OrderDate]
FROM [Sales].[Orders]
WHERE [CustomerID] > 550;
GO
که به صورت پیش‌فرض شامل این ایندکس‌ها است:


اجرای کوئری فوق، چنین کوئری پلنی را تولید می‌کند:


جدول [Sales].[Orders]، یک CLUSTERED INDEX را بر روی [OrderID] دارد و یک NONCLUSTERED INDEX را بر روی [CustomerID].
در کوئری پلن تولید شده، یک Clustered index scan مشاهده می‌شود. علت اینجا است که هرچند در جدول [Sales].[Orders] یک NONCLUSTERED INDEX بر روی  [CustomerID] تعریف شده‌است:
CREATE NONCLUSTERED INDEX [FK_Sales_Orders_CustomerID] ON [Sales].[Orders]
(
[CustomerID] ASC
)
اما قسمت INCLUDE ایندکس قبلی را که تعریف کردیم، ندارد و به همراه [CustomerID] و [OrderDate] نیست. به همین جهت اینبار logical reads 692 است.

بنابراین وجود عملگر Clustered index scan در یک کوئری پلن، یعنی نیاز به خواندن و اسکن کل جدول وجود دارد. برای اثبات آن، همین کوئری قبلی را که بر روی [Sales].[Orders] انجام دادیم، اینبار بدون قسمت where آن اجرا کنید. یعنی کوئری بر روی کل جدول انجام شود:
SELECT
    [CustomerID],
    [OrderID],
    [OrderDate]
FROM [Sales].[Orders]
سپس به برگه‌ی messages مراجعه کرده و عدد logical reads آن‌را مشاهده کنید. این عدد دقیقا با عدد logical reads کوئری where دار، یکی است؛ که بیانگر اسکن کامل جدول در حالت Clustered index scan است.

سؤال: آیا Clustered index scan همواره کل یک جدول را اسکن می‌کند؟
پاسخ: خیر. اگر یک کوئری برای مثال دارای top/min/max باشد، کل جدول اسکن نخواهد شد:
SELECT TOP 10
    [CustomerID],
    [OrderID],
    [OrderDate]
FROM [Sales].[Orders]
WHERE [CustomerID] > 550;
تفاوت این کوئری با کوئری‌های قبلی، در داشتن یک top 10 است. اگر آن‌را اجرا کنیم، به کوئری پلن زیر خواهیم رسید:


هرچند در اینجا هم یک Clustered index scan صورت گرفته، اما اگر به برگه‌ی messages آن مراجعه کنیم، آمار I/O آن بیانگر تنها logical reads 5 است که معادل اسکن کل جدول نیست:
(10 rows affected)
Table 'Orders'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 510, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


مقایسه‌ی عملگرهای Index Scan و Index Seek

ابتدا کوئری زیر را اجرا می‌کنیم:
SELECT
    [CustomerID],
    [OrderID]
FROM [Sales].[Orders]
WHERE [OrderID] > 30000;
این کوئری با کوئری قبلی از لحاظ قسمت select اندکی متفاوت بوده و در آن OrderDate حذف شده‌است. در قسمت where نیز کوئری بر روی OrderID صورت گرفته‌است.
در این جدول ایندکسی بر روی CustomerID وجود دارد و همچنین کلید اصلی جدول، OrderID است.

پس از اجرای این کوئری، به کوئری پلن زیر خواهیم رسید:


که بیانگر یک Index Scan است و نکته‌ی جالب آن، استفاده‌ی از ایندکس FK_Sales_Orders_CustomerID می‌باشد (نام این شیء، ذیل آیکن عملگر، مشخص است). یعنی SQL Server در اینجا از یک non-clustered index تعریف شده‌ی بر روی CustomerID استفاده کرده‌است.
اکنون اگر OrderID را تغییر دهیم چه اتفاقی رخ می‌دهد؟
SELECT
    [CustomerID],
    [OrderID]
FROM [Sales].[Orders]
WHERE [OrderID] > 60000;
اینبار به یک clustered index seek رسیدیم که بر روی کلید اصلی جدول یا همان PK_Sales_Orders که ذیل عملگر مشخص شده، رخ داده‌است:


در این مثال با دو ورودی مختلف، دو کوئری پلن مختلف تولید شده‌است؛ که مرتبط است با میزان اطلاعاتی که قرار است بازگشت داده شود.

اگر این دو کوئری را با هم اجرا کنیم (در طی یک batch)، به پلن مقایسه‌ای زیر خواهیم رسید که در آن هزینه‌ی Index Scan بیشتر است از clustered index seek:


به همراه آمار CPU و I/O ای به صورت زیر که اولی مرتبط است با index scan و دومی با clustered index seek:
(43595 rows affected)
Table 'Orders'. Scan count 1, logical reads 191, physical reads 1, read-ahead reads 182, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
 SQL Server Execution Times:
CPU time = 31 ms,  elapsed time = 754 ms.


(13595 rows affected)
Table 'Orders'. Scan count 1, logical reads 131, physical reads 0, read-ahead reads 127, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
 SQL Server Execution Times:
CPU time = 16 ms,  elapsed time = 276 ms.
به همین جهت است که عنوان می‌شود، scanها خوب نیستند و seekها بهترند.
مطالب
Value Types ارجاعی در C# 7.2
در C# 7.2 می‌توان با value types (مانند structs) همانند reference types (مانند کلاس‌ها) رفتار کرد. جائیکه کارآیی برنامه بسیار حائز اهمیت باشد (مانند بازی‌ها)، استفاده از structs و value types بسیار مرسوم است؛ از این جهت که این نوع‌ها بر روی heap تخصیص داده نمی‌شوند. اما مشکل آن‌ها این است که زمانیکه به متدها ارسال می‌شوند، مقدار آن‌ها ارسال خواهد شد و برای این منظور نیاز به ایجاد یک کپی جدید از آن‌ها می‌باشد. برای رفع این مشکل و کاهش سربار کپی کردن اشیاء، اکنون در C# 7.2 می‌توان value types را همانند reference types به متدها ارسال کرد.


واژه‌ی کلیدی جدید in

C# 7.2‌، واژه‌ی کلیدی جدیدی را به نام in جهت تعریف پارامترها، معرفی کرده‌است. زمانیکه از آن استفاده می‌شود به این معنا است که value type ارسالی به آن، توسط ارجاعی از آن، در اختیار متد قرار می‌گیرد و نه توسط مقدار کپی شده‌ی آن (حالت پیش‌فرض) و همچنین متد استفاده کننده‌ی از آن، مقدار این شیء را تغییر نمی‌دهد.
واژه‌ی کلیدی in مکمل واژه‌های کلیدی ref و out است که پیشتر به همراه زبان #C ارائه شده بودند:
- واژه‌ی کلیدی out: مقدار آرگومان مزین شده‌ی توسط آن، باید درون متد تنظیم شود و صرفا کاربرد ارائه‌ی یک خروجی اضافه‌تر توسط آن متد را دارد.
- واژه‌ی کلیدی ref: مقدار آرگومان مزین شده‌ی توسط آن، ممکن است درون متد تنظیم شود، یا خیر و همچنین توسط ارجاع به آن منتقل می‌شود.
- واژه‌ی کلیدی in: مقدار آرگومان مزین شده‌ی توسط آن، درون متد تغییر نخواهد کرد و همچنین توسط ارجاع به آن منتقل می‌شود.

برای مثال اگر پارامترهای value type متد زیر را از نوع in معرفی کنیم، امکان تغییر مقدار آن‌ها درون متد وجود نخواهد داشت:
public static int Add(in int number1, in int number2)
{
   number1 = 5; // Cannot assign to variable 'in int' because it is a readonly variable
   return number1 + number2;
}
و کامپایلر با صدور خطای readonly بودن پارامتر number1، از انجام اینکار جلوگیری می‌کند


واژه‌ی کلیدی جدید in تا چه اندازه‌ای بر روی کارآیی برنامه تاثیر دارد؟

زمانیکه یک value type را به متدی ارسال می‌کنیم، ابتدا به مکان جدیدی از حافظه کپی شده و سپس مقدار clone شده‌ی آن، به متد ارسال می‌شود. با استفاده از واژه‌ی کلیدی in، دقیقا همان ارجاع به مقدار اولیه، به متد ارسال خواهد شد؛ بدون ایجاد کپی اضافه‌تری از آن. برای بررسی تاثیر این عملیات بر روی کارآیی برنامه، می‌توان از BenchmarkDotNet استفاده کرد. برای این منظور ابتدا ارجاعی را به BenchmarkDotNet اضافه می‌کنیم:
<ItemGroup>
     <PackageReference Include="BenchmarkDotNet" Version="0.10.12" />
</ItemGroup>
سپس متدهایی را که قرار است کارآیی آن‌ها بررسی شوند، با ویژگی Benchmark مزین خواهیم کرد:
using BenchmarkDotNet.Attributes;

namespace CS72Tests
{
    public struct Input
    {
        public decimal Number1;
        public decimal Number2;
    }

    [MemoryDiagnoser]
    public class InBenchmarking
    {
        const int loops = 50000000;
        Input inputInstance = new Input();

        [Benchmark(Baseline = true)]
        public decimal RunNormalLoop_Pass_By_Value()
        {
            decimal result = 0M;
            for (int i = 0; i < loops; i++)
            {
                result = Run(inputInstance);
            }
            return result;
        }

        [Benchmark]
        public decimal RunInLoop_Pass_By_Reference()
        {
            decimal result = 0M;
            for (int i = 0; i < loops; i++)
            {
                result = RunIn(in inputInstance);
            }
            return result;
        }

        public decimal Run(Input input)
        {
            return input.Number1;
        }

        public decimal RunIn(in Input input)
        {
            return input.Number1;
        }
    }
}
در آخر برای اجرای آن خواهیم داشت:
static void Main(string[] args)
{
    var summary = BenchmarkRunner.Run<InBenchmarking>();
و در این حالت برنامه را باید توسط دستور «dotnet run -c release» اجرا کرد (اندازه گیری کارآیی در حالت release و نه دیباگ پیش‌فرض)
با این خروجی نهایی:
                      Method |      Mean |    Error |   StdDev | Scaled | Allocated |
---------------------------- |----------:|---------:|---------:|-------:|----------:|
 RunNormalLoop_Pass_By_Value | 280.04 ms | 2.219 ms | 1.733 ms |   1.00 |       0 B |
 RunInLoop_Pass_By_Reference |  91.75 ms | 1.733 ms | 1.780 ms |   0.33 |       0 B |
همانطور که ملاحظه می‌کنید، کارآیی برنامه در حالت استفاده‌ی از پارامترهای in، حداقل 3 برابر شده‌است.


امکان استفاده‌ی از واژه‌ی کلیدی in در حین تعریف متدهای الحاقی

در حین تعریف متدهای الحاقی، واژه‌ی کلیدی in باید پیش از واژه‌ی کلیدی this ذکر شود:
    public static class Factorial
    {
        public static int Calculate(in this int num)
        {
            int result = 1;
            for (int i = num; i > 1; i--)
                result *= i;

            return result;
        }
    }
در این حالت اگر برنامه را به صورت زیر اجرا کنیم (یکبار با ذکر صریح in، بار دیگر بدون in و یکبار هم به صورت فراخوانی متد الحاقی بر روی عدد):
int num = 3;
Console.WriteLine($"(in num) -> {Factorial.Calculate(in num)}");
Console.WriteLine($"(num) -> {Factorial.Calculate(num)}");
Console.WriteLine($"num. -> {num.Calculate()}");
خروجی‌های ذیل را دریافت خواهیم کرد:
(in num) -> 6
(num) -> 6
num. -> 6
به عبارتی حین فراخوانی و استفاده‌ی از متدی که پارامتر آن به صورت in تعریف شده‌است، ذکر in ضروری نیست.

و به طور کلی استفاده‌ی از in در مکان‌های ذیل مجاز است:
• methods
• delegates
• lambdas
• local functions
• indexers
• operators
 

محدودیت‌های استفاده‌ی از پارامترهای in

الف) محدودیت استفاده از پارامترهای in در تعریف overloads
مثال زیر را در نظر بگیرید:
    public class CX
    {
        public void A(Input a)
        {
            Console.WriteLine("int a");
        }

        public void A(in Input a)
        {
            Console.WriteLine("in int a");
        }
    }
در اینجا overloadهای تعریف شده‌ی متد A تنها در ذکر واژه‌ی کلیدی in یا modifier متفاوت هستند.
اگر سعی کنیم وهله‌ای از این کلاس را ایجاد کرده و از متدهای A آن استفاده کنیم:
    public class Y
    {
        public void Test()
        {
            var inputInstance = new Input();
            var cx = new CX();
            cx.A(inputInstance); // The call is ambiguous between the following methods or properties: 'CX.A(Input)' and 'CX.A(in Input)'
        }
    }
خطای کامپایلر مبهم بودن متد A مورد استفاده صادر خواهد شد. یعنی نمی‌توان overload ایی را تعریف کرد که تنها در modifier از نوع in با دیگری متفاوت باشد؛ چون ذکر in در حین فراخوانی متد، اختیاری است.

ب) پارامترهای از نوع in را در متدهای iterator نمی‌توان استفاده کرد:
public IEnumerable<int> B(in int a) // Iterators cannot have ref or out parameters
{
   Console.WriteLine("in int a");
   yield return 1;
}

ج) پارامترهای از نوع in را در متدهای async نمی‌توان استفاده کرد:
public async Task C(in int a) // Async methods cannot have ref or out parameters
{
   await Task.Delay(1000);
}


تاثیر کار با متدهای داخلی تغییر دهنده‌ی وضعیت یک struct

مثال زیر را درنظر بگیرید. به نظر شما خروجی آن چیست؟
using System;

namespace CS72Tests
{
    struct MyStruct
    {
        public int MyValue { get; set; }

        public void UpdateMyValue(int value)
        {
            MyValue = value;
        }
    }

    public static class TestInStructs
    {
        public static void Run()
        {
            var myStruct = new MyStruct();
            myStruct.UpdateMyValue(1);

            UpdateMyValue(myStruct);

            Console.WriteLine(myStruct.MyValue);
        }

        static void UpdateMyValue(in MyStruct myStruct)
        {
            myStruct.UpdateMyValue(5);
        }
    }
}
در اینجا اگر متد TestInStructs.Run را اجرا کنیم، خروجی آن، نمایش عدد 1 خواهد بود.
در ابتدا مقدار struct را به 1 تنظیم و سپس ارجاع آن‌را به متدی دیگر که مقدار آن‌را به 5 تنظیم می‌کند، ارسال کردیم. در این حالت برنامه بدون مشکل کامپایل و اجرا می‌شود.  علت اینجا است که کامپایلر #C زمانیکه متدی را در داخل یک struct فراخوانی می‌کند، یک clone از آن struct را ایجاد کرده و متد را بر روی آن clone اجرا می‌کند؛ چون نمی‌داند که آیا این متد وضعیت و مقدار این struct را تغییر می‌دهد یا خیر. در این حالت کپی اصلی بدون تغییر باقی می‌ماند (در نهایت عدد 1 را مشاهده خواهیم کرد)، اما در آخر فراخوان، ارجاعی از struct را دریافت نکرده و بر روی کپی آن کار می‌کند. بنابراین مزیت بهبود کارآیی، از دست خواهد رفت.

البته در اینجا اگر می‌خواستیم مقدار MyValue را مستقیما تغییر دهیم، کامپایلر از آن جلوگیری می‌کرد و این کد هیچگاه کامپایل نمی‌شد:
static void UpdateMyValue(in MyStruct myStruct)
{
   myStruct.MyValue = 5; // Cannot assign to a member of variable 'in MyStruct' because it is a readonly variable
   myStruct.UpdateMyValue(5);
}
مطالب دوره‌ها
یادگیری مدل در داده کاوی

مقدمه

هدف اصلی داده کاوی کشف دانش است، که این دانش نظمی که در داده‌ها وجود دارد را نمایان می‌سازد. پس از کشف دانش ممکن است با دو وضعیت مواجه شویم:
  • حالت اول هنگامی است که افراد خبره در دامنه داده مورد کاوش، آگاه به دانش استخراج شده باشند که در این صورت آن دانش به عنوان یک قانون صحیح تلقی خواهد شد.
  • در حالت دوم ممکن است دانش کشف شده، یک دانش جدید بوده و در بین افراد خبره در آن حوزه شناخته شده نباشد، در این صورت این دانش بررسی شده و در صورت منطقی بودن تبدیل به فرضیه شده و در نهایت درست یا غلط بودن این فرضیه با آزمایشات و بررسی‌های متعدد اثبات می‌شود و در صورت درست بودن فرضیه تبدیل به قانون خواهد شد.

روش‌های یادگیری مدل در داده کاوی 

پیشتر به معرفی مراحل کاری در داده کاوی که مشتمل بر سه مرحله اساسی: آماده سازی داده، یادگیری مدل و در نهایت ارزیابی و تفسیر مدل می‌باشد، پرداختیم.
در مرحله یادگیری مدل با استفاده از الگوریتم‌های متنوع و با در نظر گرفتن ماهیت داده، نظم‌های مختلف موجود در داده‌ها شناسائی می‌شود. بطور کلی روش‌های مختلف کاوش داده را به دو گروه روش‌های پیش بینی و روش‌های توصیفی طبقه بندی می‌کنند.

در روش‌های پیش بینی از مقادیر بعضی ویژگی‌ها برای پیش بینی کردن مقدار یک ویژگی مشخص استفاده می‌کنند. این روش‌ها در متون علمی با نام روش‌های با ناظر (Supervised Methods ) نیز شناخته می‌شوند. الگوریتم‌های با ناظر از دو مرحله با عنوان مرحله آموزش (یادگیری) و مرحله ارزیابی تشکیل شده اند.
در مرحله آموزش؛ با استفاده از مجموعه داده‌های آموزشی مدل ساخته می‌شود. شکل مدل ساخته شده به نوع الگوریتم یادگیرنده بستگی دارد.
در مرحله ارزیابی؛ از مجموعه داده‌های آزمایشی برای اعتبارسنجی و محاسبه دقت مدل ساخته شده استفاده می‌شود، در واقع از داده هایی که در مرحله آموزش و ساخت مدل؛ الگوریتم این مجموعه داده‌ها را ندیده است (Previously Unseen Data) استفاده می‌شود.
برای نمونه روش‌های دسته بندی (Classification)، رگرسیون (Regression) و تشخیص انحراف (Anomaly Detection) سه روش یادگیری مدل در داده کاوی با ماهیت پیش بینی هستند.
در روش‌های توصیفی همانطور که انتظار داریم الگوهای قابل توصیف از روابط حاکم بر داده‌ها بدون در نظر گرفتن هر گونه برچسب و یا متغیر خروجی بدست می‌آید. این روش‌ها در متون علمی با نام روش‌های بدون ناظر (Unsupervised Methods) نیز شناخته می‌شوند. برای نمونه روش‌های خوشه بندی (Clustering)، کاوش قوانین انجمنی (Association Rules Mining) و کشف الگوهای ترتیبی (Sequential Pattern Discovery) سه روش یادگیری مدل در داده کاوی با ماهیت توصیفی هستند.

در ادامه به معرفی هر کدام از این روش‌ها می‌پردازیم:

دسته بندی:

در الگوریتم‌های دسته بندی مجموعه داده اولیه به دو مجموعه داده با عنوان مجموعه داده‌های آموزشی (Train Dataset) و مجموعه داده‌های آزمایشی (Test Dataset) تقسیم می‌شود. می‌دانیم هر Case شامل مجموعه ای از Attribute هاست، که یکی از این ویژگی‌ها ویژگی دسته نامیده می‌شود.
در مرحله آموزش؛ مجموعه داده‌های آموزشی به یکی از الگوریتم‌های دسته بندی داده می‌شود تا بر اساس سایر ویژگی‌ها برای مقادیر ویژگی دسته، مدل ساخته شود.
پس از ساخت مدل، در مرحله ارزیابی؛ دقت مدل ساخته شده به کمک مجموعه داده‌های آزمایشی ارزیابی خواهد شد. در الگوریتم‌های دسته بندی از آنجا که ویژگی دسته مربوط به هر Case مشخص است به صورت الگوریتم‌های با ناظر محسوب می‌شوند. بدیهی است که تشخیص بر اساس دسته هایی است که مدل در مرحله آموزش با آنها روبرو شده است؛ بنابراین امکان تشخیص دسته جدید در کاربرد دسته بندی وجود نخواهد داشت.

رگرسیون:

رگرسیون در علوم آمار و شبکه‌های عصبی بطور وسیعی مورد بررسی و مطالعه قرار می‌گیرد. پیش بینی مقدار یک متغیر پیوسته بر اساس مقادیر سایر متغیرها بر مبنای یک مدل وابستگی خطی یا غیر خطی رگرسیون نامیده می‌شود. یک نوع خاصی از رگرسیون، پیش بینی سری‌های زمانی (Time Series Prediction) است؛ برای مثال تغییرات قیمت سهام شرکتی را به صورت نمودار داریم؛ می‌خواهیم ادامه روند این نمودار را برای مدتی مشخص پیش بینی کنیم. در مسائل سری‌های زمانی یکی از متغیرهای اصلی زمان می‌باشد. بدیهی است که رگرسیون لزوماً سری زمانی نیست و همانند دسته بندی کاربرد رگرسیون نیز از نوع پیش بینی با ناظر است و بطور مشابه در رگرسیون هم دو مرحله آموزش و ارزیابی نیز وجود دارد. مثال هایی از رگرسیون می‌تواند شامل موارد زیر باشد: پیش بینی میزان فروش یک محصول جدید، براساس میزان فروش محصولات گذشته و یا براساس میزان تبلیغات انجام شده و ... همچنین مسائل مربوط به پیش بینی سری‌های زمانی از قبیل بورس و ... .

تشخیص انحراف:

از کاربردهای متداول تشخیص انحراف، می‌توان به کشف کلاهبرداری کارت‌های اعتباری (Credit Card Fraud Detection) اشاره کرد. در مواقعی از این کاربرد استفاده می‌شود که تنها نمونه هایی با یک برچسب یکسان که معمولاً وضعیت نرمال را نشان می‌دهند در دسترس می‌باشند و امکان مالکیت بر داده‌ها با تمامی برچسب‌های موجود به دلایل مختلف وجود ندارد. بنابراین چون فقط نمونه‌های دسته نرمال در اختیار است، الگوریتم برای وضعیت نرمال و با توجه به یک آستانه (Threshold) مشخص مدل را می‌سازد و هر گونه تخطی از آن آستانه را؛ بعنوان وضعیت غیرنرمال در نظر می‌گیرد. توجه شود روش‌های دسته بندی تنها قادر به شناسائی دسته هایی هستند که در مرحله آموزش، نمونه ای از آنها به الگوریتم ارائه شده است، بنابراین امکان تشخیص هیچ گونه کلاهبرداری توسط روش‌های دسته بندی وجود ندارد.

خوشه بندی:

در این مسائل از آنجا که بر خلاف دسته بندی هیچ گونه دسته خاصی وجود ندارد، بنابراین براساس معیار شباهت داده‌ها گروه بندی و خوشه بندی صورت می‌گیرد. بدین ترتیب Case هایی که بیشترین شباهت را به یکدیگر دارند در یک خوشه قرار می‌گیرند، به بیان دیگر Case‌های موجود در خوشه‌های متفاوت کمترین شباهت را به یکدیگر خواهند داشت. بدیهی است که خوشه بندی براساس ویژگی ورودی نمونه‌ها انجام می‌گیرد و از آنجائی که برای این الگوریتم‌ها ویژگی دسته تعریف نمی‌شود و Case‌ها برچسب خاصی ندارند، جزء الگوریتم‌های بدون ناظر محسوب می‌شوند. در واقع هدف در تمامی الگوریتم‌های خوشه بندی کمینه کردن فاصله درون خوشه ای (Intra-Cluster Density) و بیشینه نمودن فاصله بین خوشه ای (Inter-Cluster Density) است و عملکرد خوب یک الگوریتم خوشه بندی زمانی محرز می‌شود که تا حد امکان خوشه‌ها را از یکدیگر دورتر کند و در ضمن Case‌های موجود در یک خوشه بیشترین شباهت را به یکدیگر داشته باشند.

کشف قوانین انجمنی:

قوانین وابستگی (انجمنی) اتفاق و وقوع یک شیء را براساس وقوع سایر اشیاء توصیف می‌کنند، برای مثال در یک سوپر مارکت هدف در کاوش قوانین انجمنی؛ یافتن نظم حاکم بر سبد خرید می‌باشد، در این کاربرد به ازای هر سبد؛ یک قانون پیدا می‌شود و بررسی خواهد شد که این قانون در چه تعداد از سبدها صدق می‌کند و در نهایت یک مجموعه قوانین که در بیشترین تعداد از سبدها صدق می‌کند به عنوان مجموعه قوانین انجمنی خروجی ارائه می‌شود. به بیان دیگر در این کاربرد به دنبال پیدا کردن یک مجموعه از قوانین وابستگی هستیم تا براساس آن قوانین بتوانیم نتیجه گیری کنیم وجود کدامیک از مجموعه اشیاء (Item Set) بر وجود چه مجموعه اشیاء دیگری تاثیر گذار است.

کشف الگوهای ترتیبی:

در این کاربرد به دنبال کشف الگوهایی هستیم که وابستگی‌های ترتیبی محکمی را در میان وقایع مختلف نشان می‌دهند. این کاربرد مشابه کاوش قوانین انجمنی می‌باشد با این تفاوت که در کاوش قوانین انجمنی زمان و ترتیب زمانی مطرح نیست، اما در کشف الگوهای ترتیبی زمان و ترتیب اهمیت ویژه ای دارند برای مثال می‌توان به دنباله‌های تراکنش‌های فروش اشاره نمود.

منبع: با اندکی تغییر و تلخیص "داده کاوی کاربردی در RapidMiner، انتشارات نیاز دانش"
مطالب دوره‌ها
فرآیند داده کاوی در Microsoft SQL Server (بخش یک)

مقدمه

بطور کلی داده کاوی به دو قسمت زیر تقسیم می‌شود:

1- اهداف توصیفی (Descriptive Goal): بدنبال یافتن الگوها و روابط بین داده‌ها هستیم، بدین ترتیب مدلی برای توصیف بهتر داده‌ها بدست خواهد آمد.

2- اهداف پیش بینانه (Predictive Goal): بدنبال انجام پیش بینی با استفاده از الگو‌ها و مدل‌های فوق هستیم.

همچنین مراحل اجرای یک پروژه داده کاوی شامل مراحل زیر است:
1- تحلیل: مهمترین فعالیت در این فاز، فهم عمیق مسئله و شناخت درست مسئله و شناسائی مفاهیم کلیدی (Key Concept) در مسئله است.
2- طراحی: مهمترین فعالیت این فاز، فرموله کردن مسئله با استفاده از مفاهیم کلیدی است.
3- پیاده سازی/ نگهداری و بهبود

مراحل کاری داده‏ کاوی بر اساس استاندارد CRISP-DM

محصول مشترک شرکت‌های SPSS, Teradata, NCR و دایملر- کرایسلر است و یک فرآیند استاندارد Cross-Industry برای داده کاوی است که به طور گسترده ای استفاده می‌شود. مراحل کاری در این مدل به شش فاز اصلی به شرح زیر تقسیم می‌شوند:

1. درک پروژه و فهم حوزه کاربرد (Business Understanding):
به طور صریح و آشکار اهداف و نیازمندی‌ها مشخص می‌شود. ترجمه اهداف و محدودیت آن در قاعده‏ سازی، تعریف مسئله داده‏ کاوی و مهیا کردن استراتژی اولیه برای نائل شدن به اهداف در این مرحله تعریف می‏ شود.

2. انتخاب داده‌ها (Data Understanding):
این مرحله شامل جمع آوری داده‌ها برای استفاده از تحلیل اکتشافی و مشخص کردن اطلاعات اولیه برای ارزیابی داده‏‌های با کیفیت و انتخاب داده‌های مفید و مورد نیاز می‌باشد.

3. آماده سازی داده‏‌ها (Data Preparation):
آماده کردن داده‏‌های اولیه خام به داده‏‌های نهایی، این دادها در کلیه مراحل بعدی استفاده می‌شود و از این نظر این مرحله تحلیل و تلاش بیشتری را می‌طلبد. انتخاب عناصر و شناسه‏‌های تحلیل شده را برای کاوش داده‏‌ها اختصاص می‌دهیم و با تمیز کردن داده‌های خام آن را برای ابزارهای مدل سازی آماده می‏ کنیم.

4. مدل سازی (Modeling):
با انتخاب و به ‏کار بستن تکنیک‌های مدل سازی مناسب و روش داده‏ کاوی معین نتایج مدل سازی را بهینه می‏ کنیم، که در صورت نیاز می‌توانیم با برگشت به عقب تحلیل مدل سازی را بهینه‌تر نماییم.

5. ارزیابی (Evaluation):
مشخص کردن اینکه آیا مدل انتخابی، ما را به اهدافمان که در اولین مرحله تعیین کردیم، می‏ رساند. اتخاذ تصمیم راجع به استفاده از نتایج داده‏ کاوی برای اعتبارسنجی نیز در این مرحله انجام می‏ شود.

6. استقرار (Deployment):
استفاده کردن از مدل ایجاد شده، برای مثال می‌تواند تولید یک گزارش ساده از خروجی‌ها را نام برد، و برای یک مثال پیچیده تکمیل کردن پردازش داده‏ کاوی موازی در سایر حوزه‏‌ها می‌باشد، که این الگو‏ها به یک دانش مفید و قابل استفاده تبدیل می‌شوند و پس از بهبود آنها، الگوهایی که کارا محسوب می‏ شوند در یک سیستم اجرایی به کار گرفته خواهند شد.

مراحل کاری داده کاوی در بستر تکنولوژی Microsoft

داده­ کاوی غالباً به عنوان فرآیند استخراج اطلاعات، الگوها و روندهای موجود در مجموعه­ ی عظیمی از داده­‌ها یاد می­ شود. این الگوها و روندها را می­ توان به عنوان یک مدل کاوشی تعریف نمود. به بیانی دیگر ایجاد یک مدل کاوشی بخشی از فرآیند بزرگتری است که در برگیرنده­ ی همه مراحل؛ از تعریف مسئله که مدل حل خواهد نمود تا اجرای مدل در محیط­‌‌های کاری است. می­ توان این فرآیند را با استفاده از 6 مرحله اساسی زیر تعریف نمود:

باید در نظر داشت که تهیه یک مدل داده کاوی، فرآیندی چرخشی، پویا و تکرار پذیر می­ باشد و ممکن است هر یک از این مراحل آن قدر تکرار شود، تا مدل مناسبی تهیه گردد. 

  • تعریف مسئله (Defining the Problem):

تعریف روشنی از مشکل و مسئله کسب و کار است. این مرحله شامل تجزیه و تحلیل نیازمندی­‌‌های کسب و­کار، تعریف دامنه مشکل، تعریف معیارهایی که با آن مدل­‌ها ارزیابی خواهد شد و تعریف هدف نهایی پروژه­ ی داده­ کاوی است.

  • آماده­ سازی داده­‌ها (Preparing Data):

یکپارچه ­سازی و پالایش داده­ هایی است که در مرحله­ ی تعریف مسئله فرآیند معین شده است. SSIS حاوی تمامی ابزارهای ملزوم برای تکمیل این مرحله می‌­باشد.

  • بررسی داده­‌ها (Exploring Data):

به منظور تصمیم­ گیری­‌های مناسب در هنگام تهیه مدل، می­ بایست داده­‌ها را درک نمود و پس از آن می­ توان تصمیم گیری در مورد وجود داده­‌های مخدوش در مجموعه داده و در نهایت استراتژی مناسب برای رفع این مشکلات اتخاذ نمود. Data Source view Designer موجود در BIDS حاوی ابزارهای جامعی برای بررسی و شناخت داده‌ها شامل محاسبه ارقام حداقل و حداکثر، محاسبه میانگین و انحراف معیار و بررسی توزیع داده­‌ها می­ باشد.

  • تهیه مدل ­ها (Building Models):

پیش از تهیه مدل باید، داده­‌ها را به دو دسته­ ی داده­‌های آموزشی و اعتبارسنجی (آزمایشی) تقسیم نمود. از داده­‌های آموزشی برای تهیه مدل و از داده­‌های اعتبار­سنجی برای آزمایش صحت مدل با ایجاد سوالاتی در مورد صحت پیش­ بینی­‌ها استفاده نمود. پس از تعریف ساختار کاوشی، می­ بایست به پردازش مدل پرداخته شود و ساختارهای خالی با الگوهایی که مدل را توصیف می­ نمایند، پُر شوند. این مرحله با عنوان آموزش مدل شناخته می­ شود.

  • بررسی و ارزیابی مدل­‌ها (Exploring and Validating Models):

این مرحله شامل بررسی مدل­‌های ایجاد شده به منظور آزمودن کارایی آنهاست. می­ توان مدل­‌ها را با ابزار­های موجود در Designer از جمله نمودار صعود و یا ماتریس دسته­ بندی بررسی نمود.

  • اجرا و بروزرسانی مدل­‌ها (Deploying and Updating Models):

این مرحله شامل اجرای مدل­ هایی است که بهترین کارائی را در یک محیط عملیاتی داشته­ اند. پس از استقرار مدل­‌های کاوشی در یک محیط عملیاتی می­ توان از این مدل­ها برای پیش­ بینی­ هایی بهره گرفت.


مراحل سه گانه موجود در ساخت یک مدل کاوش   

  • ایجاد ساختار کاوشی (Mining Structures): تعریف یک ساختار کاوشی شامل، تعیین تعداد ستون­‌های ورودی، تعداد ستون­‌های قابل پیش ­بینی و الگوریتم وابسته به آن می‌­باشد. ساختار کاوشی یک ساختار داده­ ای است که محدوده­ ی داده­ هایی را که از روی آنها مدل­‌های کاوش ساخته می­ شود را تعریف می­ نماید. 
  • آموزش مدل (Model Training): یک مدل کاوشی، الگوریتم­‌های کاوش را به داده­ هایی که ساختار کاوش ارائه می­ نماید، اعمال می­ کند. به بیان دیگر استفاده و کاربرد هر ستون و الگوریتمی که برای ساخت مدل استفاده می­ شود را تعریف می­ کند، پس شامل داده منبع اصلی نیست، بلکه شامل اطلاعاتی است که توسط الگوریتم کشف می­ شود. به آموزش مدل، پردازش مدل نیز گفته می‌شود و زمانی که یک مدل پردازش می­ شود داده­ هایی که توسط ساختار کاوش تعریف شده­ اند، از طریق الگوریتم­‌های داده­ کاوی انتخابی منتقل می­ شوند، الگوریتم؛ الگوها و روندها را جستجو می­ کند و در ادامه این اطلاعات در مدل ذخیره می­ شوند. از این رو پس از یادگیری و آموزش مدل، الگوهای بدست آمده در مدل کاوش ذخیره می­ شوند.

  • پیش بینی مدل (Prediction): غالباً مهمترین مرحله و هدف نهایی در پروژه­‌های داده­ کاوی است. پیش­ بینی به کشف اطلاعات ناشناخته با استفاده از الگوهای یافته شده از سوابق داده­‌ها اشاره دارد. در پیش­ بینی به یک مدل کاوشی آموزش دیده و یک مجموعه داده­ ی جدید نیاز است. و در طول پیش­ بینی موتور داده­ کاوی، قواعد بدست آمده در مرحله یادگیری را در مورد مجموعه داده­ ی جدید بکار می­ برد و نتایج پیش­ بینی را به هر Case ورودی تخصیص می­ دهد.  
اشتراک‌ها
زمان پایان پشتیبانی از نگارش‌های قدیمی‌تر Visual Studio
Visual Studio version End of Mainstream Support End of Support
Visual Studio 2022, Current Channel January 2027 January 2032
   Visual Studio 2022, version 17.0 LTSC n/a July 2023
Visual Studio 2019, version 16.11 April 2024 April 2029
   Visual Studio 2019, version 16.9 n/a October 2022
   Visual Studio 2019, version 16.7 n/a April 2022
Visual Studio 2017, version 15.9 April 2022 April 2027
Visual Studio 2015, Update 3 including KB3165756 October 2020 October 2025
Visual Studio 2013, Update 5 April 2019 April 2024
Visual Studio 2012, Update 5 January 2018 January 2023
Visual Studio 2010 and earlier Out of support Out of support
زمان پایان پشتیبانی از نگارش‌های قدیمی‌تر Visual Studio