When a search action returns no results, an on-empty
block can be used to modify the search constraints, typically by replacing an input value with a less-restrictive one, or by dropping an input value to loosen constraints. This is referred to as relaxing the search constraints.
A node that has been relaxed by an on-empty
effect will return true
if tested with the relaxed()
Expression Language function.
Instead of dropping an input that has cardinality Many
, you might want to reduce it to size 1
. For example, if Bixby is struggling to find events that overlap many topics, it might be reasonable to focus on just one topic:
output (event.Event) {
on-empty {
if (exists(topic) && size(topic).length > 1) {
replace(topic) {
intent{
goal: Event
value: $expr(topic[0])
}
}
}
}
}
When searching for a local business, the user might not explicitly search for a "Restaurant". However, they might mention other food-related inputs, like "course" or "cuisine". With these inputs, you can modify the search to explicitly look for "Restaurant". This is what the first block of this relaxation strategy shows.
The second block of this relaxation strategy shows how to increase the distance radius for the search if no results were found in the vicinity. Essentially, if no results were found within, say 5 miles, then look within 20 miles.
output (Business) {
on-empty {
if ("!relaxed(restaurantStyle) && ((exists(restaurantStyle) && (!contains(restaurantStyle, 'Restaurant') || size(restaurantStyle) > 1)) || exists(allergy) || exists(course) || exists(cuisineAttribute) || exists(cuisineStyle) || exists(diet) || exists(meal) || exists(menuItem) || exists(restaurantAmenities) || exists(restaurantQualities))") {
// If we have reason to believe this is a restaurant query, make that explicit and simple
replace (restaurantStyle) {
intent{
goal { Restaurant }
value { restaurant.RestaurantStyle(Restaurant) }
}
}
} else-if (!relaxed(searchRegion) && searchRegion.searchType == 'PointRadius' && searchRegion.pointRadius.radius.magnitude < 20) {
// Increase search radius
replace (searchRegion) {
intent {
goal { geo.SearchRegion }
value { $expr (searchRegion.pointRadius.centroid) }
value {
geo.SearchRadius {
unit: $expr (searchRegion.pointRadius.radius.unit)
magnitude { geo.DistanceMagnitude(20.0) }
}
}
}
}
}
}
}
The FindRecipes
action attempts to find recipes fulfilling a number of user inputs. However, in some cases there might be no results satisfying all these inputs at once. Instead of going to the NoResults
state, you can use drop
effects to loosen and repeat the search.
This example checks for the presence of several different constraints and repeats the search without them. Wrapping them inside an ordered-effects
block allows multiple inputs to be dropped at once. By grouping drop
effects together like this, it reduces the number of relaxation passes and allows Bixby to get results faster.
output (Recipe) {
on-empty {
if (exists(servings)) {
drop (servings)
} else-if (exists(course) || exists(meal) || exists(cuisine)) {
ordered-effects {
drop (course)
drop (meal)
drop (cuisine)
}
}
}
}