Hierarchical Facets Guide

edit

Hierarchical Facets Guide

edit

We also have a more basic Facets Guide.

App Search supports facets.

By combining them with filters, you can build hierarchical facets.

Consider how facets work in the National Parks demo: https://parks.swiftype.info.

A typical list of facets has one dimension.

If we query the above demo site for "parks", we see our two facets:

States
World Heritage Site

With hierarchical facets, facet counts - and results - get more granular as they are selected:

States
  World Heritage Site

A prototypical example is an ecommerce store:

Shirts
    T-shirts
    Sweatshirts
        Hoodies
    Collared Shirts
        Polo shirts
        Dress shirts
Footwear
    Sandals
    Sneakers
Accessories
    Scarves
    Belts

Continuing with parks, we will demonstrate how to write hierarchical facet queries.

In motion, here is how they work:

After searching for "parks", the state facet appears...

California (8)
Alaska (5)
...

We click into one, and then the "second dimension", the child facet, appears:

California (8)
  World Heritage Site (6)
  Regular Site (2)
Alaska (5)

Our results also reflect what we have clicked.

We only see parks from "California".

Now we choose whether or not we want to visit a World Heritage Site.

We make our choice, and then...

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

The results show only "California" parks that are "World Heritage Sites".

And the second child - "third dimension" - appears: open or closed?

And we can go on, and on!

We create fields, and then apply facets and filters to implement this.

We would model our document fields like this:

{
  // ... Truncated!
  "description": "I am a park! You know, for nature.",
  "dimension1": "California",
  "dimension2": "World_Heritage_Site",
  "dimension3": "Open"
}

The "why" will become apparent as we build the queries:

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

For our first query, we request results, plus a facet count of the first dimension.

In this case, that dimension gives US state names, and so we return a count of states:

{
  // ... Truncated!
  "facets": {
      "dimension1": [
          {
              "type": "value",
              "data": [
                  {
                      "value": "California",
                      "count": 8
                  },
                  {
                      "value": "Alaska",
                      "count": 5
                  },
                  // .. Truncated!
              ]
          }
      ]
  }
}

Looks as we would except — it is, after all, a typical facet query.

Now, when a user clicks a parent, a first dimension facet, we apply a facet and a filter.

Imagine that a user clicked on "California".

It would invoke this query:

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

A filter is applied on dimension1 to match on "California".

And a facet count is requested for the child field, dimension2.

That field - dimension2 - tells us whether or not the park is a World Heritage Site.

The narrowed results appear, as does the count we expect:

{
  // ... Truncated!
  "facets": {
      "dimension2": [
          {
              "type": "value",
              "data": [
                  {
                      "value": "World_Heritage_Site",
                      "count": 6
                  },
                  {
                      "value": "Regular_Site",
                      "count": 2
                  }
              ]
          }
      ]
  }
}

In our path, we are here, returning only one faceted dimension:

  World Heritage Site (6)
  Regular Site (2)

With the next decision, the user will click further down the hierarchy.

If they click "World Heritage Site", then the next query requires two parts:

  1. Facet on dimension3: whether the park is Open or Closed.
  2. Add filters for dimension1 and dimension2 to narrow results.
{
    "query": "parks",
    "facets": {
        "dimension3": [{ "type": "value"}]
    },
    "filters": {
        "all": [
            {"dimension1": ["California"]},
            {"dimension2": ["World_Heritage_Site"]}
        ]
    }
}

Again, we return narrowed results and the right facet count:

{
  // ... Truncated!
  "facets": {
      "dimension3": [
          {
              "type": "value",
              "data": [
                  {
                      "value": "Open",
                      "count": 4
                  },
                  {
                      "value": "Closed",
                      "count": 2
                  }
              ]
          }
      ]
  }
}

Great! But one thing to consider is that the example only returned the dimension3 count.

Our facets would look like this:

    Open (4)
    Closed (2)

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.

That’s the hierarchical facets pattern! You can get as deep as you’d like.

You should now be well equipped to start building.

Read more: Facets Guide | Facets API Reference