KEEPFILTERS en CALCULATE: cómo evitar sobrescribir filtros en DAX

KEEPFILTERS en CALCULATE: cómo evitar sobrescribir filtros en DAX

0
(0)

Cualquier consultor que haya pasado suficientes horas depurando modelos de datos en Power BI se ha topado con el comportamiento estándar de CALCULATE: su agresividad para sobrescribir el contexto de filtro. Es una de las primeras lecciones en cualquier formación técnica, pero también es la fuente de errores más común en informes de producción. Cuando escribes un filtro dentro de esta función, por defecto estás indicando a DAX que ignore cualquier selección previa del usuario sobre esa columna específica y la sustituya por el valor que tú has definido.

Este comportamiento es útil cuando queremos forzar un cálculo (como comparar las ventas de una categoría contra el total), pero es desastroso cuando intentamos realizar segmentaciones dinámicas donde el filtro del usuario debería coexistir con la lógica de la medida. Aquí es donde entra KEEPFILTERS. No es una función de cálculo por sí misma, sino un modificador que altera cómo CALCULATE gestiona la transición de filtros. En lugar de reemplazar, KEEPFILTERS suma.

En este artículo analizaremos por qué ocurre esto a nivel interno del motor VertiPaq, cómo afecta el rendimiento en modelos de gran volumen (como los que gestionamos en el sector retail o energía) y bajo qué escenarios la omisión de esta función está falseando los resultados de tus cuadros de mando. No se trata de una cuestión estética, sino de rigor matemático en la intersección de conjuntos de datos.

El comportamiento por defecto: la sustitución agresiva

Para entender KEEPFILTERS, primero debemos recordar qué hace realmente una medida simple de CALCULATE. Tomemos como ejemplo una tabla de Ventas y una dimensión de Producto. Supongamos que queremos calcular las ventas de productos de color rojo.

Ventas Rojas = 
CALCULATE(
 [Importe Total],
 'Producto'[Color] = "Rojo"
)

A simple vista, parece correcto. Sin embargo, DAX transforma internamente ese filtro booleano en una función de tabla. Lo que realmente está ejecutando el motor es algo similar a esto:

Ventas Rojas (Interno) = 
CALCULATE(
 [Importe Total],
 FILTER(
 ALL('Producto'[Color]),
 'Producto'[Color] = "Rojo"
 )
)

El uso de ALL en la sintaxis expandida es la clave. Si el usuario selecciona el color «Azul» en un segmentador (slicer) de la página, la medida de Ventas Rojas seguirá devolviendo el importe de los productos rojos. CALCULATE ha detectado que hay un filtro sobre la columna 'Producto'[Color], lo ha eliminado mediante el ALL implícito y ha aplicado su propio filtro. En la mayoría de los casos de análisis comparativo, esto es lo que buscamos. Pero, ¿qué ocurre si queremos que la medida respete el filtro del usuario y solo devuelva valor si el usuario selecciona «Rojo» o no selecciona nada?

Si el usuario filtra por «Azul», la intersección lógica entre «Azul» y «Rojo» es un conjunto vacío. Sin KEEPFILTERS, la medida nos daría el total de «Rojo» (ignora al usuario). Con KEEPFILTERS, la medida devolvería BLANK (respeta la intersección vacía). Este matiz es crítico en modelos de CALCULATE, la superfunción DAX.

KEEPFILTERS y la intersección de conjuntos

La función KEEPFILTERS cambia la semántica del filtro. En lugar de ejecutar un ALL sobre la columna, mantiene los filtros existentes en el contexto de evaluación y aplica el nuevo filtro como una restricción adicional (una operación lógica AND). Es, en esencia, una intersección de conjuntos.

Si retomamos el ejemplo anterior con la sintaxis correcta:

Ventas Rojas Seguras = 
CALCULATE(
 [Importe Total],
 KEEPFILTERS('Producto'[Color] = "Rojo")
)

Ahora, el comportamiento cambia radicalmente según la interacción del usuario:

  • Sin filtros en el segmentador: La medida devuelve las ventas de productos rojos (intersección entre «todos los colores» y «Rojo»).
  • Slicer en «Rojo»: La medida devuelve las ventas de productos rojos (intersección entre «Rojo» y «Rojo»).
  • Slicer en «Azul»: La medida devuelve BLANK. No hay productos que sean azules y rojos simultáneamente.

Este patrón es vital cuando diseñamos matrices complejas. Sin KEEPFILTERS, una matriz que muestre todos los colores en las filas pero use la medida Ventas Rojas, mostraría el mismo valor de ventas rojas en todas las filas (Azul, Verde, Amarillo), lo cual es visualmente confuso y técnicamente incorrecto para un informe de desglose.

Caso práctico: Segmentación en sector Retail

Imagina un escenario en una cadena de supermercados. Queremos analizar el rendimiento de una promoción específica que solo aplica a la categoría «Bebidas». Tenemos una medida para calcular el margen de dicha promoción.

Si creamos la medida sin KEEPFILTERS, al colocarla en una tabla junto a otras categorías como «Carnicería» o «Panadería», veríamos el margen de bebidas repetido en todas las filas. Esto sucede porque CALCULATE está sobrepasando el contexto de fila de la tabla para imponer su categoría «Bebidas».

Como consultor, uno de los errores que más veo es intentar solucionar esto con instrucciones IF(ISFILTERED(...)) o lógicas similares que solo añaden complejidad y latencia. La solución elegante y eficiente es envolver el filtro en KEEPFILTERS. Esto asegura que la medida solo produzca resultados en la fila de «Bebidas», manteniendo la integridad visual del informe.

Para profundizar en cómo se evalúan estos contextos, te recomiendo leer sobre el Orden de Evaluación en anidamientos con la función CALCULATETABLE, ya que las reglas de precedencia son idénticas.

Comparativa técnica: CALCULATE estándar vs KEEPFILTERS

A continuación, presentamos una tabla que resume las diferencias de comportamiento ante distintos escenarios de filtrado externo:

Escenario de Filtro ExternoCALCULATE (Estándar)CALCULATE + KEEPFILTERS
Columna no filtrada por el usuarioAplica el filtro de la medida.Aplica el filtro de la medida.
Columna filtrada con el mismo valorDevuelve el valor (coinciden).Devuelve el valor (coinciden).
Columna filtrada con valor distintoSobrescribe al usuario y muestra el valor de la medida.Devuelve vacío (intersección nula).
Impacto en visualizaciones (Matrices)Repite el valor en todas las filas de la columna.Muestra el valor solo en la fila que cumple el filtro.
Semántica internaSustitución (Override).Intersección (And).

Consideraciones de rendimiento y el Storage Engine

Desde el punto de vista de la arquitectura de datos y la optimización, KEEPFILTERS es generalmente una operación económica. Al no tener que generar un nuevo contexto de filtro desde cero mediante un ALL implícito, a veces puede ayudar al motor de almacenamiento (Storage Engine) a generar consultas SQL (en DirectQuery) o peticiones a VertiPaq más sencillas.

Sin embargo, hay que tener cuidado cuando se usa dentro de iteradores como SUMX sobre tablas de gran cardinalidad. Al forzar una intersección constante, si el modelo no está bien normalizado o si estamos ante un esquema en estrella deficiente, podríamos aumentar el número de callbacks al motor de fórmulas. Siempre recomiendo usar el Performance Analyzer y revisar los Server Timings en DAX Studio para confirmar que la introducción de KEEPFILTERS no está penalizando la velocidad de renderizado.

En proyectos de gran escala donde el rendimiento es crítico, como explicamos en Optimización de Modelos Semánticos en Power BI: VertiPaq & Storage Engine, entender cómo cada modificador de CALCULATE afecta a la caché es la diferencia entre un informe instantáneo y uno que desespera al usuario.

KEEPFILTERS con múltiples columnas

Es posible usar KEEPFILTERS sobre una tabla completa o sobre un conjunto de columnas. Esto es especialmente útil en filtros cruzados complejos donde queremos mantener la relación existente entre, por ejemplo, País y Ciudad.

Ventas Europa = 
CALCULATE(
 [Importe Total],
 KEEPFILTERS(
 FILTER(
 ALL('Geografía'[Continente]),
 'Geografía'[Continente] = "Europa"
 )
 )
)

En este caso, si el usuario selecciona «España», la medida funcionará correctamente. Pero si el usuario selecciona «Canadá», la medida no intentará «forzar» Europa sobre Canadá, sino que devolverá vacío, que es lo lógicamente esperado en un análisis de drill-down.

Errores frecuentes al omitir KEEPFILTERS

  1. Totales de columna engañosos: En tablas o matrices, ver que el total general no coincide con la suma de las filas porque algunas filas están mostrando valores que no deberían corresponderles.
  2. Filtros cruzados rotos: Cuando un usuario selecciona un elemento en un gráfico de barras y el resto de visuales no responden como deberían porque una medida tiene un filtro «hardcoded» que ignora la interacción.
  3. Uso excesivo de filtros visuales: Intentar corregir el comportamiento de la medida aplicando filtros a nivel de objeto visual en lugar de corregir la lógica DAX en el modelo semántico. Esto hace que el mantenimiento del informe sea una pesadilla.
  4. Confusión entre KEEPFILTERS y FILTER: Recordad que FILTER es un iterador y tiene un coste computacional mayor. KEEPFILTERS es un modificador de contexto, mucho más ligero para el motor. Para entender mejor esta distinción, consulta Funciones de tabla en DAX: FILTER, ADDCOLUMNS y el coste de la materialización.

Checklist para el uso de KEEPFILTERS

  • ¿La medida se va a usar en una matriz o tabla donde la columna filtrada está presente en las filas/columnas? Si la respuesta es sí, probablemente necesites KEEPFILTERS.
  • ¿Quieres que la selección del usuario en los segmentadores prevalezca o se combine con el filtro de la medida? Si es combinación, usa KEEPFILTERS.
  • ¿Estás intentando evitar que aparezcan filas con datos irrelevantes en tus visuales? KEEPFILTERS es la solución más eficiente antes de recurrir a ISBLANK o filtros de nivel visual.
  • Revisa si el filtro es sobre una columna de alta cardinalidad. En ese caso, mide el impacto con DAX Studio.
  • Asegúrate de que no estás duplicando lógica. Si ya usas un FILTER complejo, comprueba si envolverlo en KEEPFILTERS simplifica el resultado final.

Preguntas frecuentes

¿Cuándo es mejor NO usar KEEPFILTERS?

No debes usarlo cuando el objetivo de la medida sea precisamente calcular un ratio sobre un total (como un % del total). En esos casos, necesitas que CALCULATE ignore el filtro del usuario sobre una dimensión concreta para poder obtener el denominador de la división.

¿Se puede usar KEEPFILTERS con medidas calculadas con SUMX?

Sí, de hecho es una práctica común para asegurar que la iteración de SUMX respete el contexto de filtro modificado. Si quieres saber más sobre estas funciones, echa un vistazo a Medidas de suma condicional con SUMX en Power BI.

¿Funciona KEEPFILTERS en modelos de DirectQuery?

Absolutamente. El motor traduce la intersección de filtros a cláusulas WHERE más restrictivas en la consulta SQL enviada a la base de datos de origen (Snowflake, SQL Server, Fabric Warehouse, etc.), lo cual suele ser beneficioso para el rendimiento.

¿Qué diferencia hay entre KEEPFILTERS y usar una relación activa?

Son conceptos distintos. Las relaciones definen cómo se propaga el filtro entre tablas. KEEPFILTERS define cómo se comporta un filtro específico dentro de una medida cuando ya existe otro filtro en la misma columna. No sustituye la necesidad de un buen diseño de modelo en estrella.


¿De cuánta utilidad te ha parecido este contenido?

¡Haz clic en una estrella para puntuarlo!

Puntuación media 0 / 5. Recuento de votos: 0

Hasta ahora, ¡no hay votos!. Sé el primero en puntuar este contenido.

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *