search mobile facets autocomplete spellcheck crawler rankings weights synonyms analytics engage api customize documentation install setup technology content domains user history info home business cart chart contact email activate analyticsalt analytics autocomplete cart contact content crawling custom documentation domains email engage faceted history info install mobile person querybuilder search setup spellcheck synonyms weights engage_search_term engage_related_content engage_next_results engage_personalized_results engage_recent_results success add arrow-down arrow-left arrow-right arrow-up caret-down caret-left caret-right caret-up check close content conversions-small conversions details edit grid help small-info error live magento minus move photo pin plus preview refresh search settings small-home stat subtract text trash unpin wordpress x alert case_deflection advanced-permissions keyword-detection predictive-ai sso

Facets Guide

Facets are all about enriching your search query responses.

A facet is a tool that your users can use to further tune search results to their liking.

It will generate a count for a value or range based on a field within a schema.

We can see facets in action within a hosted Reference UI displaying the National Parks demo: https://parks.swiftype.info/.

Facets - A visual example of facets from the eyes of the Reference UI.
The Reference UI, set-up with `states` and `world_heritage_site` facets. A query is there, for

Facets are contained on the left side, next to the results.

The example link is faceting on two different fields: world_heritage_site and states.

A query like "old growth" will return many different parks. Someone browsing for parks will want to dig deeper into the result set.

A facet is added to a field to provide a count of results that share values within that field. This makes much more sense visually...

Facets - Facets, up close and personalized.
A list of facets for the two fields: `states` and `world_heritage_site`. There are many states present, and then the values true and false for the world heritage site field.

Parks with "states": ['California'], "states": ['Colorado'], "states": ['Nevada'], and so on, are counted together as a facet. A user can now click into the facet, returning only results that contain that value: California, Colorado, Nevada, or otherwise.

Facets - The "old growth" query with California as a facet.
The caption actually sums this one up pretty well.

Once within one facet, the other faceted fields are still available to us.

There are two "old growth" parks in California: one is a world heritage site and one is not.

Each time we click into a facet, the result set is refined until we reach the right result.

But what do these queries look like in the eyes of the code?

curl -X GET 'https://host-2376rb.api.swiftype.com/api/as/v1/engines/national-parks-demo/search' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer search-soaewu2ye6uc45dr8mcd54v8' \
-d '{
  "query": "old growth",
  "facets": {
    "states": [
      {
        "type": "value"
      }
    ],
    "world_heritage_site": [
      {
        "type": "value"
      }
    ]
  }
}'

It is a query to the /search endpoint with two Value Facets, which are only available within text fields.

There are three other types of field: number, date, and geolocation. What if we want to facet on those fields?

We would apply a Range Facet.

You can imagine how that might work...

If you want to find products within a certain price range, restaurants at a certain distance, or concerts on a particular date, you would apply a Range Facet.

Staying on the trail of our National Park demo, how would we sort parks by their level of busy-ness?

curl -X GET 'https://host-2376rb.api.swiftype.com/api/as/v1/engines/national-parks-demo/search' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer search-soaewu2ye6uc45dr8mcd54v8' \
-d '{
  "query": "old growth",
  "facets": {
    "visitors": [
      {
        "type": "range",
        "ranges": [
          { "from": 1, "to": 150000, "name": "Not busy" },
          { "from": 150000, "to": 500000, "name": "Somewhat busy" },
          { "from": 500000, "name": "Very busy"}
        ]
      }
    ]
  }
}'

We would facet on the visitors field, which is of type number.

We create three "buckets", each with a name indicating how busy the park is over the course of a year.

The resulting count for the "old growth" query would then look like this:

{
  "meta": {
      ## Truncated!!
    },
    "request_id": "e3e8f493cb7f8577001910ca77c3fd24"
  },
  "results": [
    ## Truncated!
  ],
  "facets": {
    "visitors": [
      {
        "type": "range",
        "data": [
          {
            "to": 150000,
            "from": 1,
            "name": "Not busy",
            "count": 2
          },
          {
            "to": 500000,
            "from": 150000,
            "name": "Somewhat busy",
            "count": 2
          },
          {
            "from": 500000,
            "name": "Very busy",
            "count": 6
          }
        ]
      }
    ]
  }
}

That looks good. But we know that facets can be combined.

A person looking for "old growth" parks wants to find the one that is the least busy, and that is the closest to where they live.

If the schema has a field of type geolocation, they can apply another Range Facet to extend the query, like so:

curl -X GET 'https://host-2376rb.api.swiftype.com/api/as/v1/engines/national-parks-demo/search' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer search-soaewu2ye6uc45dr8mcd54v8' \
-d '{
  "query": "old growth",
  "facets": {
    "visitors": [
      {
        "type": "range",
        "ranges": [
          { "from": 1, "to": 150000, "name": "Not busy" },
          { "from": 150000, "to": 500000, "name": "Somewhat busy" },
          { "from": 500000, "name": "Very busy"}
        ]
      }
    ],
    "location": [
       {
         "type": "range",
         "center": "37.386483, -122.083842",
         "unit": "m",
         "ranges": [
           { "from": 0, "to": 100000, "name": "Close" },
           { "from": 100000, "to": 300000, "name": "A weekend trip" },
           { "from": 300000, "name": "Far from home" }
         ]
       }
     ]
  }
}'

We provided the coordinates of the Elastic office in Mountain View, California as our center and distance in meters.

As expected, the full result set for the "old growth" queries appear, and so do the counts:

"facets": {
  "location": [
    {
      "type": "range",
      "data": [
        {
          "to": 100000,
          "from": 0,
          "name": "Close",
          "count": 0
        },
        {
          "to": 300000,
          "from": 100000,
          "name": "A weekend trip",
          "count": 1
        },
        {
          "from": 300000,
          "name": "Far from home",
          "count": 9
        }
      ]
    }
  ],
  "visitors": [
    {
      "type": "range",
      "data": [
        {
          "to": 150000,
          "from": 1,
          "name": "Not busy",
          "count": 2
        },
        {
          "to": 500000,
          "from": 150000,
          "name": "Somewhat busy",
          "count": 2
        },
        {
          "from": 500000,
          "name": "Very busy",
          "count": 6
        }
      ]
    }
  ]
}

In a few clicks within the search experience, a person can query for old growth parks and find the nearest, least busy park.

For a full list of potential facets, check out the Facets API Reference.

What's Next?

You are well on your way to getting a handle on search and its many... facets. Poor puns aside, there are many other features that can help you get the most out of App Search. You might want to learn how to gain insights into user search data. For that, Analytics and Clickthrough will serve you well. If you are looking to get into result tuning, consider Curations.


Stuck? Looking for help? Contact support or check out the App Search community forum!