درک رفتار Value Filter در SUMMARIZECOLUMNS و بهترین تنظیم آن در Power BI
رفتار Value Filter مشخص میکند که چگونه فیلترها در هنگام محاسبهی Measureها در SUMMARIZECOLUMNS اعمال میشوند. این ویژگی بیشتر زمانی اهمیت دارد که توسعهدهندگان از آرگومانهای فیلتر در SUMMARIZECOLUMNS استفاده کنند.
این موضوع بسیار گسترده است و در اینجا تنها به سطح مقدماتی آن اشاره میکنیم. خبر خوب این است که اکثر توسعهدهندگان نیازی به یادگیری جزئیات پیچیده رفتار Value Filter ندارند. این ویژگی سه حالت دارد:
Automatic
Independent
Coalesced
از سال ۲۰۲۵، حالت Independent به عنوان امنترین و درستترین تنظیم معرفی شد. در حالی که پیش از ۲۰۲۵ مقدار پیشفرض روی Coalesced قرار داشت، حالت Automatic در مدلهای قدیمی همچنان Coalesced را نگه میدارد اما برای مدلهای جدید آن را روی Independent قرار میدهد.
بنابراین برای اطمینان خاطر، توصیه میشود همیشه رفتار Value Filter را روی Independent تنظیم کنید. با این انتخاب، مدلهای شما بهخوبی کار خواهند کرد و هرگز پشیمان نخواهید شد.
فهرست مطالب
مقدمه
سناریوهای متعددی وجود دارد که تعامل بین رفتار Value Filter و قابلیت Auto-exists میتواند مشکلساز شود، و هیچیک ساده نیستند. در این مقاله، هدف ما ارائهی یک سناریو برای نشان دادن پیچیدگیهای این موضوع است تا در نهایت بهترین روش پیشنهادی را روشن کنیم: همیشه از حالت Independent استفاده کنید.
ابتدا باید چند واقعیت مهم را درباره پایگاه داده نمونه خود بیان کنیم:
Datum یک برند است که فقط محصولات خود را در دستهی Cameras and camcorders عرضه میکند.
تعداد 132 محصول با برند A. Datum وجود دارد.
در مجموع 372 محصول در دستهی Cameras and camcorders ثبت شدهاند.
این اعداد در ادامه به ما کمک خواهند کرد. نیازی نیست آنها را به خاطر بسپارید، زیرا هر زمان نیاز باشد دوباره به آنها اشاره میکنیم.
در این مثال قصد داریم از دو Measure استفاده کنیم:
# Products → این Measure تعداد محصولات را محاسبه میکند.
All Brands → این Measure تعداد محصولات را با حذف هرگونه فیلتر از ستون Product[Brand] محاسبه میکند.
این دو Measure پایهی تحلیل ما خواهند بود و نشان میدهند که چگونه میتوان رفتار فیلترها و محاسبات در Power BI را بهتر درک کرد.
# Products = COUNTROWS ( 'Product' )
All Brands =
CALCULATE (
[# Products],
REMOVEFILTERS ( 'Product'[Brand] )
)
اگر از این دو Measure در یک ماتریس (Matrix Visual) همراه با دو Slicer استفاده کنیم (که فعلاً هیچ فیلتری اعمال نمیکنند)، هر دو Measure دقیقاً نتیجه یکسانی تولید خواهند کرد.
به بیان ساده، تا زمانی که هیچ فیلتر فعال نباشد، تفاوتی بین خروجی # Products و All Brands وجود ندارد. این موضوع نشان میدهد که عملکرد این دو Measure تنها زمانی متمایز خواهد شد که فیلترهای برند یا دستهبندی وارد عمل شوند.
درک رفتار Value Filter
در واقع، در ماتریس (Matrix) هیچ پیچیدگی خاصی وجود ندارد. اما موضوع زمانی جالب میشود که از Slicer روی ستون Product[Brand] استفاده کنیم و آن را فقط روی برند A. Datum فیلتر کنیم.
در این حالت، اعداد حاصل کمی پیچیدهتر میشوند و تفسیر آنها آسان نیست. حتی ممکن است در نگاه اول تصور کنید که در کد DAX شما یک باگ (Bug) وجود دارد.
این اتفاق دقیقاً همان جایی است که اهمیت درک رفتار Value Filter خودش را نشان میدهد. چرا که در شرایطی که فیلتر برند فعال باشد، تفاوت میان # Products و All Brands آشکار میشود و نتایج ممکن است برخلاف انتظار اولیه شما باشند.
با وجود اینکه اعداد در نگاه اول نادرست به نظر میرسند، اما مقادیر تولید شده در سطح جمع کل (Total Level) در واقع درست هستند. دلیل این موضوع به طور کامل واضح نیست و به مکانیزم Auto-exists مربوط میشود، اما خروجی نهایی صحیح است.
برای روشنتر شدن این موضوع، بهتر است ابتدا به کوئری DAX که در حال اجراست نگاه کنیم و سپس مرحله به مرحله تحلیل کنیم که چرا اعداد در سطح کل درست به دست میآیند.
EVALUATE
SUMMARIZECOLUMNS (
ROLLUPADDISSUBTOTAL (
ROLLUPGROUP ( 'Product'[Category], 'Product'[Category Code] ),
"IsGrandTotalRowTotal"
),
TREATAS ( { "A. Datum" }, 'Product'[Brand] ),
"# Products", [# Products],
"All Brands", [All Brands]
)
مرور رفتار SUMMARIZECOLUMNS
قبل از ادامه، بهتر است رفتار تابع SUMMARIZECOLUMNS را مرور کنیم.
مرحله اول – تعیین Group-by Tuples
SUMMARIZECOLUMNS ابتدا گروهبندیها (Group-by Tuples) را مشخص میکند؛ این همان ردیفهایی هستند که خروجی جدول را تشکیل میدهند.مرحله دوم – محاسبه Measureها
پس از تعیین گروهبندیها، این تابع شروع به محاسبه Measureها میکند. به عبارت دیگر، ابتدا مشخص میکند چه دستهبندیهایی باید بازگردانده شوند و سپس برای آنها Measureها را محاسبه میکند.
مثال: فیلتر روی Product[Brand]
وقتی ستون Product[Brand] روی A. Datum فیلتر میشود، این فیلتر در مرحلهی تعیین Group-by Tuples تأثیر میگذارد. بنابراین تنها یک ردیف تولید میشود: Cameras and camcorders.
این منطقی است، چون A. Datum فقط در همین دسته محصول دارد.
نکته مهم: Group-by Tuples قبل از محاسبه Measureها ساخته میشوند. بنابراین حتی اگر Measure All Brands بخواهد مقادیر دستههای دیگر را هم حساب کند، در اینجا هیچ تأثیری ندارد. چون فقط یک دستهبندی (Cameras and camcorders) وجود دارد که باید محاسبه شود.
رفتار در سطح جمع کل (Total Level)
وقتی به سطح Total میرسیم، SUMMARIZECOLUMNS هیچ فیلتری روی ستون Product[Category] اعمال نمیکند. چون در Total هدف نمایش کل دادههاست.
از طرف دیگر، Measure All Brands فیلتر روی Product[Brand] را حذف میکند و تعداد کل محصولات در همه برندها را بازمیگرداند.
به همین دلیل ممکن است ماتریس کمی گیجکننده به نظر برسد، چون ردیف دستهبندیهای دیگر نمایش داده نمیشوند، اما اعداد نشاندادهشده در واقع درست هستند، حتی اگر در نگاه اول سخت به نظر برسند.
وقتی بیش از یک دسته فیلتر شود
حالا تصور کنید با Slicer دو دسته را فیلتر کنیم: Cameras and camcorders و Cell phones.
از نظر Group-by Tuples، دسته Cell phones در ماتریس ظاهر نمیشود.
با این حال انتظار داریم مجموع کل برابر باشد با:
372 (Cameras and camcorders) + 285 (Cell phones) = 657 محصول
اما در عمل اینطور نیست. مجموع کل فقط 372 نمایش داده میشود. این همان نقطهای است که رفتار SUMMARIZECOLUMNS میتواند برای تحلیلگران سردرگمکننده باشد.
بیایید به کوئری DAX که در حال اجراست نگاهی بیندازیم:
EVALUATE
SUMMARIZECOLUMNS (
ROLLUPADDISSUBTOTAL (
ROLLUPGROUP ( 'Product'[Category], 'Product'[Category Code] ),
"IsGrandTotalRowTotal"
),
TREATAS ( { "A. Datum" }, 'Product'[Brand] ),
TREATAS ( { "Cameras and camcorders", "Cell phones" }, 'Product'[Category] ),
"# Products", [# Products],
"All Brands", [All Brands]
)
برای تغییر این متن بر روی دکمه ویرایش کلیک کنید. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است.
تابع SUMMARIZECOLUMNS در این سناریو دو فیلتر روی دو ستون قرار میدهد: Product[Brand] و Product[Category].
اما این دو فیلتر وارد فرآیندی مشابه Clustering (که با نام Auto-exists هم شناخته میشود) میشوند؛ به این صورت که در نهایت به یک فیلتر واحد روی هر دو ستون تبدیل میشوند (Coalesced).
از آنجایی که برند A. Datum فقط محصولات دستهی Cameras and camcorders را میفروشد، تنها یک Tuple معتبر باقی میماند:
A. Datum + Cameras and camcorders
این فیلتر در دو بخش استفاده میشود:
برای تعیین Group-by Tuples
برای محاسبهی Measureها
بنابراین زمانی که فیلتر روی ستون Product[Brand] حذف میشود، تنها فیلتر باقیمانده روی ستون Product[Category] خواهد بود (یعنی فقط “Cameras and camcorders”). در نتیجه، Measure داخل همین فیلتر اجرا شده و مقدار 372 را تولید میکند.
مشکل حالت Coalesced
اینکه دو فیلتر در نهایت به یک فیلتر واحد تبدیل میشوند، میتواند منجر به نتایج غیرمنتظره شود. این اتفاق زمانی رخ میدهد که Value Filter Behavior روی حالت Coalesced تنظیم شده باشد.
راهحل: استفاده از Independent
اگر رفتار Value Filter روی Independent قرار داده شود، به DAX دستور میدهیم که فیلترها را ادغام نکند و هر فیلتر را به صورت جداگانه نگه دارد:
یک فیلتر برای ستون Product[Brand]
یک فیلتر دیگر برای ستون Product[Category]
در این حالت، حذف فیلتر Product[Brand] هیچ تداخلی با فیلتر ستون Product[Category] نخواهد داشت.
بنابراین اگر Value Filter Behavior در مدل روی حالت Independent تنظیم شود، نتایج گزارش بسیار دقیقتر و منطقیتر خواهد بود و مشکل نتایج غیرمنتظره در حالت Coalesced برطرف میشود.
گزارش همچنان به دلیل نبودن ردیفهای مربوط به دستهبندیهایی که به برند “A. Datum” تعلق ندارند کمی دشوار برای خواندن است.
با این حال، مقدار Total مربوط به All Brands صحیح است و در واقع تعداد کل محصولات در دو دسته انتخابشده در Slicer را – بدون توجه به برند – نمایش میدهد.
به عبارت دیگر، حتی اگر در ماتریس برخی ردیفها دیده نشوند، عدد نهایی در سطح جمع کل (Total) درست بوده و تصویر کلی دادهها را منعکس میکند.
نتیجهگیری
همانطور که در مقدمه اشاره کردیم، سناریوهای متعددی وجود دارند که تفاوت بین حالتهای Coalesced و Independent در آنها آشکار میشود. تجربه نشان میدهد که نتایج بهدستآمده در حالت Independent بسیار شفافتر و دقیقتر هستند، در حالی که استفاده از Coalesced اغلب باعث تولید نتایجی میشود که سختتر برای خواندن و درک هستند.
توصیه اصلی ما این است:
مدلهای خود را همیشه روی Independent تنظیم کنید و هرگز دوباره به Coalesced برنگردید.
اگرچه Coalesced برای سالها تنها حالت موجود بود و به همین دلیل هنوز هم در بسیاری از مدلها دیده میشود، اما واقعیت این است که در سناریوهای پیچیده باعث نتایج گیجکننده و تفسیر دشوار میشود.
نکته مهم دیگر اینکه تغییر Value Filter Behavior هیچ تأثیری بر روی مکانیزم Auto-exists ندارد. تابع SUMMARIZECOLUMNS همچنان در مرحله تعیین Group-by Tuples از Clustering استفاده میکند (به همین دلیل تنها دستهی Cameras and camcorders دیده میشود).
تغییر رفتار Value Filter فقط بر روی نحوه اعمال فیلترها در هنگام محاسبه Measureها اثر میگذارد؛ در حالی که Group-by Tuples همچنان تحت فرآیند Clustering قرار میگیرند.
دیدگاهتان را بنویسید