Bixby Developer Center

Guides

Relaxation

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.

Example: Replace Input

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])
}
}
}
}
}

Example: Complex Replace Input

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) }
}
}
}
}
}
}
}

Example: Drop Input

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)
}
}
}
}