The approach I have taken in the past to do the least index customization was to make sure my call from the code to the ContentSearch API passed in all options. I would make sure my call included both the selected parent as well as possible children.
When search code would execute, I would try to find all the ones the user didn't select that would also apply. So, if the user picked "Coffee" and "Espresso" I would then try to make sure I passed "Coffee", "Espresso", and "Cappucino" into the search query.
The general approach would be this (pseudo-code, not real C#):
List<Item> GetTags(List<Tag> tags){
List<Tag> allTags = copy of tags;
//Get the children of the selected tag (and their children)
foreach(tag in tags){
if(tag has children){
allTags.Add(GetTags(tag.children))
}
}
return allTags;
}
The above was for illustration purposes of a brute-force method. In actual implementation, you would probably execute a content search for all tags that had the selected tag as a parent in the index so that you could quickly get all of the tags in a sub-tree of your taxonomy. You would then pass this tag list as the actual filters for your search instead of the ones selected by the user.
If you are already loading all of the taxonomy into memory for display on the screen, you might already have an in-memory object you could search to find the children as well.