Multi value multi level hierarchical facets using App Search

I have a form where user can select their favorite food. Options like below -

Options

Vegetables
	- Tomato
	- Pumpkin
	- Carrot
Fruits
	- Apple
	- Banana
	- Orange
Meats and Poultry
 	- Lean meats
 		- Beef
 		- Lamb
 		- Pork
	- Poultry
		- Chicken
		- Turkey
	- Fish and Seafood
		- Fish
		- Prawns
		- Lobster
	- Eggs
		- Chicken eggs
 		- Duck eggs

Users can select any number of option from any level.

What should be the ideal Engine Schema in App Search and how to manage search query in API?

Reference from: https://swiftype.com/documentation/app-search/guides/hierarchical-facets

Thank you.

Welcome to the community! :tada:

Ideal, hmm -- you will be the best person to determine which is ideal, but how about this for a starting point? :slight_smile:

"vegetables": text,
"fruits": text,
"lean_meats": text,
"poultry": text,
"seafood": text,
"eggs": text

You can then filter or facet on any those fields.

There is too much missing information about your search use case to give a more concrete answer, but those fields would be versatile.

Kellen

Thanks Kellen :slight_smile:

Let me explain my search use case.

Goal
Assuming we are collecting food habits of different people. So we build a form where a user can input basic details and select their favorite foods. The favorite food selection is a hierarchical list of checkbox (same as the options list I have given in my main post). Our target is to search users with hierarchical facets filter on favorite food field. So we can filter the search results from higher level to lower level.

In SwiftType documentation I found an example of single value hierarchy as I given the reference earlier. So I followed the same data schema as below -

"id": text,
"email": text,
"dimension1": text,
"dimension2": text,
"dimension3": text

Now consider the below data we got from user. And we stored the food choice in different dimension as per hierarchy level.

[
  {
    "id": "user1",
    "email": "a@a.com",
    "dimension1": ["Vegetables", "Fruits", "Meats and Poultry"],
    "dimension2": ["Tomato", "Pumpkin", "Apple", "Lean meats"],
    "dimension3": ["Beef"]
  },
  {
    "id": "user2",
    "email": "b@b.com",
    "dimension1": ["Vegetables", "Fruits"],
    "dimension2": ["Carrot", "Pumpkin", "Banana"]
  }
]

Now we query on this data with facets on "dimension1"
``

{
  "query": "",
  "facets": {
    "dimension1": [{ "type": "value"}]
  }
}

With results we got the below facets

...
"facets": {
    "dimension1": [
      {
        "type": "value",
        "data": [
          {
            "value": "Fruits",
            "count": 2
          },
          {
            "value": "Vegetables",
            "count": 2
          },
          {
            "value": "Meats and Poultry",
            "count": 1
          }
        ]
      }
    ]
  }
...

We filter the result set selecting facet "Vegetables" and query for next level facets -

{
  "query": "",
  "facets": {
    "dimension2": [{ "type": "value"}]
  },
  "filters": {
    "dimension1": ["Vegetables"]
  }
}

In response we got the below facets set

...
"facets": {
  "dimension2": [
    {
      "type": "value",
      "data": [
        {
          "value": "Pumpkin",
          "count": 2
        },
        {
          "value": "Apple",
          "count": 1
        },
        {
          "value": "Banana",
          "count": 1
        },
        {
          "value": "Carrot",
          "count": 1
        },
        {
          "value": "Lean meats",
          "count": 1
        },
        {
          "value": "Tomato",
          "count": 1
        }
      ]
    }
  ]
}
...

And here comes the problem. :worried:
Now from this returned facets how can we figure out which are the second level facets of "Vegetables" in the hierarchy? :roll_eyes:

Any idea how we can solve this problem?

I wonder if we could apply filter on facets query also!

Thanks,
Abhishek

Abhishek -- thank you!

I appreciate the detail.

The Hierarchical Facets guide mentions this at the end:


If we want the facet menu to include the correct counts for all dimensions, like so:

California (8)
  World Heritage Site (6)
    Open (4)
    Closed (2)
Alaska (5)

We would use multiple queries:

  1. Request dimension1 facets.
  2. Request dimension2 facets, filter on dimension1 .
  3. Request dimension3 facets, filter on dimension1 and dimension2 .

Your flow looks like so:

  1. Request dimension1 facets.
  2. Request dimension2 facets, filter on dimension1.
  3. ...

It is returning the correct facet counts for dimension2.

The filter will not impact the facet -- it will impact the result set.

So, anytime you are faceting on dimension2, it will return all of dimension2.


Remember that you have full control over the schema.

For example, you could break up dimension2 and establish separate hierarchies.

  • Vegetables are a 2 dimensional hierarchy.
  • Fruits are a 2 dimensional hierarchy.
  • Meats and Poultry is a 3 dimensional hierarchy.

If your schema were more "broken apart", such as this:

"id": text,
"email": text,
"dimension1": text,
"dimension2_veg": text
"dimension2_fruit": text,
"dimension2_meats": text,
"dimension3":  ...

You would be able to...

  1. more precisely apply single queries
  2. apply multiple queries when you need to represent multiple dimensions

Request 1:

{
  "query": "",
  "facets": {
    "dimension1": [{ "type": "value"}]
  }
}

Will return the count of Vegetables/Fruits/Meats&Poultry:

Vegetables (8)
Fruits (5)
Meats & Poultry (5)

Request 2:

{
  "query": "",
  "facets": {
    "dimension2_veg": [{ "type": "value"}]
  }
}

Will return:

Vegetables (8)
   Etc (1)
   Etc (2)
Fruits (5)
Meats & Poultry (5)

Request 3:

{
  "query": "",
  "facets": {
    "dimension2_fruits": [{ "type": "value"}]
  }
}

Will return:

Vegetables (x)
   Etc (x)
   Etc (x)
Fruits (x)
   Etc (x)
   Etc (x)
Meats & Poultry (x)

"Dimension" is just an example placeholder that can be replaced with your own symbols. :smile:

This isn't a "correct answer" for your case, but a demonstration that there is great flexibility.

Another thing that might help is our open source library, Search UI.

Search UI can help build search from a great set of foundational components, like faceting.

I hope this is helpful,

Kellen

Thank you for you help Kallen :slightly_smiling_face:.

This technique can solve my search use case.

Abhishek

You are welcome! Enjoy your week. :wave:

Hi, just wanted to provide this link: https://swiftype.github.io/swiftype-app-search-hierarchical-facets-example/.

It is a live example I put together a while back.

The code for this repository can be found here: https://github.com/swiftype/swiftype-app-search-hierarchical-facets-example