default_filter
Definition
A default_filter
is a filter expression for a class that is applied by default if no conflicting filter was already explicitly asked for in a question.
With it you are able to model more accurately the language inside your company. An example is when we have subscriptions in the data, but it contains also cancelled ones. Yet, when people ask about subscriptions, they intuitively expect to see only "active" ones. With default_filter
, you don't need to pass the burden to the user of remembering to ask for "active", while not limiting their experience, if asking for "inactive" subscriptions is also a common use case.
Whenever you set a default_filter
, the users will see it clearly in the answer with the possibility to remove it by clicking on it.
Usage
Boolean Filter
Let's take the example above. We have a class kb.Subscription
with a boolean is_Active
. This is how you would define it, using the VQL (Veezoo Query Language) syntax:
kb {
class Subscription {
name.en: "Subscription"
...
default_filter: """
this.is_Active = true
"""
boolean is_Active { ... }
}
}
Notice the usage of this
, which refers to the Subscription
class.
What if you have two filters? Just create a list of all of them to create multiple independent default filters.
kb {
class Subscription {
name.en: "Subscription"
...
/* Create a list using [...] */
default_filter: [
"this.is_Active = true",
"this.is_Valid = true"
]
boolean is_Active { ... }
boolean is_Valid { ... }
}
}
We recommend you keep the default filters simple, and split them up into multiple filters instead of one big filter for the best experience. Combining multiple default filters into one filter will make them interact in unexpected ways. If the example above was a single default filter instead of two it would for example not add the active filter if a valid filter is already present.
Entity Filter
Now, maybe there is no is_Active
flag, but rather a Status
which can be 'Active'.
kb {
class Subscription {
name.en: "Subscription"
...
default_filter: """
this.Status = kb.Subscription.Status.Active # Tip: Let the Editor's Autocomplete help you find the right way to refer to the Status Active here
"""
/** This is a class Status with entities like kb.Status.Active. */
class Status { ... }
}
}
In this case, if you would ask "how many subscriptions per status", Veezoo is smart enough to know not to apply the default_filter
.
For negations, do it like this:
default_filter: """
this.Status != kb.Subscription.Status.Cancelled
"""
Finally, maybe there are multiple statuses that you need to consider. For this case, we use a union
:
default_filter: """
this.Status = union(kb.Subscription.Status.Active, kb.Subscription.Status.On_Hold)
"""
Numeric filters
Let's say instead that we want to keep only those subscriptions by default with a positive subscription amount.
default_filter: """
this.Amount > 0
"""
For numeric filters, we support: <
, <=
, >
and >=
. We also support numeric operators like *
, +
, /
and -
.
Filters across classes
What if we need to filter out subscriptions that have a inactive customer (according to a separate class and table)?
This is how the default filter would change:
kb {
class Subscription {
...
relationship from_Customer { ... }
default_filter: """
var c: kb.Customer # think of this like the following SQL: FROM customers c
this.from_Customer = c
c.is_Active = true
"""
}
}
This can be made shorter:
default_filter: """
this.from_Customer.is_Active = true
"""
Now, let's go a bit wild.
Let's say we have subscriptions and actual orders. And subscriptions should by default include only those with customers that had at least 2 orders at any point in time.
default_filter: """
var c: kb.Customer
# c is this subscription's customer
this.from_Customer = c
var o: kb.Order # these are orders from the same customer
o.from_Customer = c
# let's count these orders here for each customer
var number_of_orders = count(o) by c
# only those customers with at least 2 orders
number_of_orders >= 2
"""
Refactoring
Now this could get unnecessarily complicated and usually you will want to push certain definitions down to the data warehouse as part of your transformation layer (e.g. using dbt), especially if other applications or data consumers would benefit from it. This will allow you to have just a simple boolean flag and then we are back to the first example.
If for whatever reason you don't want to do so, you can also define a boolean
in Veezoo with the code from your more complicated default_filter
.
Let's take it from the last example:
kb {
class Subscription {
...
default_filter: "this.is_Active = true"
boolean is_Active {
name.en: "Active"
description.en:
"A subscription is active if it is from a customer that made at least two orders."
definition: """
var c: kb.Customer
# c is this subscription's customer
this.from_Customer = c
var o: kb.Order # these are orders from the same customer
o.from_Customer = c
# let's count these orders here for each customer
var number_of_orders = count(o) by c
# only those customers with at least 2 orders
number_of_orders >= 2
"""
}
}
}
Or better, defining it in the kb.Customer
class.
kb {
class Customer {
...
default_filter: "this.is_Active = true"
boolean is_Active {
name.en: "Active"
description.en: "A customer that made at least two orders is deemed active."
definition: """
var o: kb.Order
o.from_Customer = this
var number_of_orders = count(o)
number_of_orders >= 2
"""
}
}
}
Now, you can define the default_filter
for Subscription
as simply:
kb {
class Subscription {
...
relationship from_Customer { ... }
default_filter: "this.from_Customer"
}
}
This may seem a bit less intuitive at first sight, but it means that the subscription has by default a customer set, which is itself by default active.
Ok, now that you know how to do all of this, remember the golden rule: Keep It Simple, Stupid.
Conditional Default Filters
With a condition
it is possible to have a default_filter
which only applies in certain situations. It also enables you to add a default_filter
attribute on concepts like integers
or measures
which normally wouldn't allow to have one directly.
kb {
class Subscription {
...
default_filter: {
filter: "this.is_Active = true"
condition: "kb.Subscription.ClickThroughRate(this)"
}
measure ClickThroughRate { ... }
boolean is_Active { ... }
}
}
The condition
works similarly to the one found in rules. It is one or more lines of VQL code, which if present in the question, tell Veezoo to add the filter. In the example above it simply states If the ClickThroughRate is present in the question, add the filter that is_Active has to be true.
As with default filters without a condition, it is possible to have multiple ones with:
kb {
class Subscription {
...
default_filter: [
{
filter: "this.is_Active = true"
condition: "kb.Subscription.ClickThroughRate(this)"
},
{
filter: "this.is_Trial_Account = false"
condition: "average(this.SubscriptionFee)"
}
]
measure ClickThroughRate { ... }
integer SubscriptionFee { ... }
boolean is_Active { ... }
}
}
Here, in this second filter, Veezoo is told to add a filter excluding trial accounts if the average subscription fee is calculated. Note that the filter would not be added, if asked about subscription fees more generally.
The condition
can also be negative. With a @missing {...}
block, a default filter can be added, when a VQL expression does not appear in the question. This is a very common use case.
kb {
class Subscription {
...
default_filter: {
filter: "this.is_Active = true"
condition: "@missing { this.cancellation_Date }"
}
boolean is_Active { ... }
date cancellation_Date { ... }
}
}
In this case here, the filter is_Active
is always added, except in questions about about the cancellation date, in which case it wouldn't make much sense to talk about active accounts.