DAX’ta KEEPFILTERS() Fonksiyonu

Filtre bağlamıyla tanışma dönemi zordur. Tasarladığınız formüller, beklentinizden farklı ve çoğu zaman hatalı sonuçlar verebilir. Bağlamlar ve filtrelerin birbirleriyle ilişkisini her aşamada imgeleştirene kadar da bu süreç devam eder. Aynı sonucu veren satırlar, hatalı oluşan toplamlar, yanlış ortalamalar vb. sorunlar çoğu zaman ya filtrelerin nüanslarından ya da bağlamları göz önünde bulundurmanın atlanmasından kaynaklanır. Bugün en önemli nüanslardan birine, KEEPFILTERS() fonksiyonuna değineceğiz.

KEEPFILTERS(), temel olarak CALCULATE() ile bir hesaplama yapılırken filtreleri korur. Bu sayede, özellikle birden fazla sütunda, belirli filtreleri sabit tutarak daha doğru sonuçlar elde edilmesini sağlar. Aynı zamanda hesaplama zamanını kısaltarak ölçü performansının artmasına önemli ölçüde katkı sağlar. İteratörlerle kullanımı da mümkün olmasına rağmen bu yazıda CALCULATE() ile kullanımı üzerinde duracağız.

Contoso Power BI dosyasındaki Satış Döviz Tutarı ölçüsü oluşturarak ilerleyelim. 

Satış Döviz Tutarı = 

 SUMX(
    Sales, 
    Sales[SalesQuantity] * Sales[UnitPrice]
 )

DELUXE ürün sınıfındaki satış döviz tutarlarını filtrelemek istediğimizi düşünelim. Formülü ilk önce KEEPFILTERS() kullanmadan yazalım.

DELUXE SATIŞLAR KEEPFILTERS OLMADAN = 

CALCULATE(
    [Satış Döviz Tutarı],
    'Product'[ClassName] = "DELUXE"
)

Satış döviz tutarı ölçüsü hesaplamayı doğru şekilde yaparken [DELUXE SATIŞLAR KEEPFILTERS OLMADAN] adlı ölçü, her satırda DELUXE satış tutarını getiririr.

Ölçü bu şekilde kısa syntax ile yazıldığında, sonuca sebep olan dinamik açık bir şekilde görülemiyor. Çalışma mantığını anlamak için, CALCULATE() fonksiyonundan ne talep ettiğimizi daha açık bir şekilde görmemiz gerekiyor.

Ölçüde yazdığımız formülün açılımına bir göz atalım:

DELUXE Satışlar Formülü Açılımı = 

CALCULATE(
    [Satış Döviz Tutarı],
    FILTER(
        ALL('Product'[ClassName]),
        'Product'[ClassName] = "DELUXE"
    )    
)

Ölçüden, DELUXE yazılı satırları filtrelemesini ve ALL() fonksiyonuyla ClassName sütunundaki filtrelerin tamamını kaldırmasını istiyoruz. 

Bu açıdan baktığımızda, hesaplama sonucunda gözlemlediğimiz bu davranışın nedeni daha açık değil mi? DAX koduna yakından bakacak olursak, ALL() fonksiyonu kullanarak ClassName üzerindeki tüm filtreleri kaldırmasını istediğimizde, her satır için aynı sonucu üretmesini sağlamış oluyoruz. Sonuçta da tablodaki her satırda aynı sonucu, DELUXE Satış Tutarını, görüyoruz. İstediğimiz sonuç bu değilse bir sorunumuz var demektir.

Bu sorunu çözmek için kaynağının ALL() fonksiyonunun davranışı olduğunu anlamamız yeterli. ALL() fonksiyonu yerine alternatif üretebilir ya da KEEPFILTERS() kullanarak var olan filtreleri koruyabiliriz. KEEPFILTERS() kullanarak devam edelim:

DELUXE SATIŞLAR KEEPFILTERS() İLE = 

CALCULATE(
    [Satış Döviz Tutarı],
    KEEPFILTERS('Product'[ClassName] = "DELUXE")
)
This image has an empty alt attribute; its file name is image-50.png

KEEPFILTERS(), CALCULTE() fonksiyonunun varsayılan davranışı olan filtrelerin üstüne yazma işlevinin önüne geçerek, ClassName sütunundaki her bir filtrenin korunmasını sağladı. Başka bir açıdan her satır için hesaplama yapılmasını engelleyerek yalnızca istenen satırların hesaplanmasını sağlamış oldu. Bu davranış çoğu durumda performans artışını destekler.

Bonus Tip: [DELUXE Satışlar Formülü Açılımı] adlı ölçüde  FILTER() fonksiyonunun tablo başvurusuna ALL yerine VALUES yazabilir ve formülün KEEPFILTERS() versiyonunda olduğu gibi çalışmasını sağlayabiliriz. Ya da daha çok sütunda filtreleme yapmak istersek VALUES() yerine SUMMARIZE() fonksiyonunu tercih edebiliriz. Büyük veri setlerinde, KEEPFILTERS() fonksiyonunun, FILTER() SUMMARIZE() ikilisine göre belirgin performans artısı sunması beklendiğini de not düşelim.

DAX’ta iki formülün performansını detaylı bir şekilde kıyaslama yöntemi arayanlar DAX Studio ile Performans Analizi
yazımızı okuyabilirler. 

Bir adım daha ilerleyelim ve CALCULATE() içerisinde iki farklı tablodan birer sütunu filtrelemek için bir örnek yapalım. Diyelim ki kıta adı ve marka adının bulunduğu bir tablomuz var. 

  • Tabloda yalnızca Kuzey Amerika ve Avrupa kıtalarına ait satış tutarlarının ve
  • ek olarak bu iki kıtadan da yalnızca belirli 3 şirketin satış rakamlarının hesaplanmasını

istiyorsak nasıl bir yol izleyebiliriz, hadi bir göz atalım:

Birden Fazla Kolon ile KEEPFILTERS = 

 CALCULATE(
    [Satış Döviz Tutarı],
    KEEPFILTERS(Geography[ContinentName] IN {"Europe", "North America"}),
    KEEPFILTERS('Product'[BrandName] IN {"Northwind Traders", "Litware", "Proseware"})   
)

CALCULATE() içerisine iki ayrı tanımlama yapmamız yeterli. Formülü, [Satış Döviz Tutarı] ile yan yana koyarak sonuçları gözlemleyebiliriz.


Bu yazıda, KEEPFILTERS() fonksiyonunun CALCULATE() ile birlikte nasıl çalıştığı, mevcut filtreleri koruyarak daha doğru sonuçlar elde etmemize nasıl yardımcı olduğu, performansı nasıl etkilediği, farklı tabloları aynı anda filtrelemede nasıl kullanılabileceği, alternatif fonksiyon örnekleri, DAX formüllerinde neden tutarlılık sorunları yaşandığı ve KEEPFILTERS() ile bu sorunların nasıl çözülebileceği gibi konulara değindik. Bir sonraki yazıda görüşmek üzere.. DAX’la kalın..