Tutorials / Building Search UI / Structured results

Structured Results

Why use Structured Results?

Structured results 0

One of the most interesting recent additions to search result pages are what is commonly called “structured results.”

Different companies use different names:

Traditional search, which consists of displaying long lists of search results once users press “Enter” on their keyboard, usually falls short of piquing their curiosity and triggering engagement. This is when new ways of searching emerge.

Instead, a successful search should attempt to communicate clearly and cleanly with a user on multiple levels when applicable, where different types of results help guide users to the information they want. Sometimes, it is desirable to showcase a particular piece of relevant content against the rest of a user’s standard query search results. This is why many believe in the value of leveraging “structured results”.

How about your search?

Uses for Structured Results

You’ll want to use structured results whenever there is a singular piece of information you want to stand out from the rest for a given query.

Here are a few examples:

  • Movie titles on an entertainment website
  • User details and avatar on a CRM
  • Sponsored brands on an eCommerce search (see example and code on GitHub).

We see a common thread among these examples - a need to search two different types of structured data - and Algolia happens to handle these cases out of the box.

An example

Let’s first take a look at the e-commerce example mentioned above. You can view the code and follow along here.

Imagine a scenario where certain brands within our e-commerce site have requested that their brand will be displayed if it happens to match a user’s query. In our search, if we determine that someone is searching for a particular brand name, we embed a section displaying the brand and its name within the main search interface.

How will the data look?

One index will be the main index to host traditional results - in our case, tech products - regardless of a match on the brand. Another index will be used to store our brands as records like so:

1
2
3
4
5
{
  "name": "Bosch",
  "url": "https://logo.clearbit.com/bosch.com",
  "objectID": "3414165441"
}

Tweaking the Relevance

Now that we’ve added a new index for structured results to use in conjunction with our main index, let’s now outline what we’d like to emphasize in our structured results:

  • Only display a single result that matches a user’s search
  • Continue to handle typos, but be more stringent
  • Ensure that we have all words matching in order (so “The Bad News” and “The Bad News Bears” would match but “Bears Bad News” would not)

Let’s determine the corresponding settings that would be configured in Algolia.

We only care about results that have a minimal number of typos, especially if we only render one result:

Structured results 2

The corresponding code for this dashboard configuration above would be:

1
2
3
4
5
index.setSettings({
  typoTolerance: 'min'
}).then(() => {
  // done
});

Next, let’s decrease our typo tolerance by increasing the minimum characters from 4 to 5 for a single typo:

Structured results 1

And the corresponding code for this dashboard configuration above would be:

1
2
3
index.setSettings({ minWordSizefor1Typos: 5}).then(() => {
  // done
});

These settings changes to our index address being more stringent when a result should show with respect to typos, but our last bullet point (ensuring that all words match in order) will be addressed at query time, in the section below.

Displaying the Data

Federated Search makes it easy to perform a single query against several datasets. We can leverage it with respect to our structured brand result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const searchClient = algoliasearch(YourApplicationID, YourSearchOnlyAPIKey);

const search = instantsearch({
  searchClient,
  indexName: 'mainIndex'
});

search.addWidgets([
  // Add your widgets here
  index({ indexName: 'structuredIndex' }).addWidgets([
    configure({
      page: 0,
      hitsPerPage: 1,
      getRankingInfo: true
    })
    // We'll add the structured results widget here
  ])
]);

search.start();

In the above snippet, we’re taking advantage of the index widget to nest multiple indices that share the same UI state (or “search state”). When a user searches in the app, it searches in both the main and the structured indices.

We use the configure widget to:

  • Stay on the first page (0 since page is zero-based) because the main index can be paginated, and the structured index would then “inherit” from its pagination state.
  • Set hitsPerPage to 1 because we only show the first result.
  • Set getRankingInfo to true so that Algolia returns metadata about the hit’s ranking.

When rendering results, we take the first result with the connectHits connector and do a conditional check:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const structuredResults = connectHits(({ hits, widgetParams }) => {
  const result = hits[0];
  const { container } = widgetParams;

  if (
    result &&
    result._rankingInfo.words - 1 === result._rankingInfo.proximityDistance
  ) {
    // Render the result
    container.innerHTML = `
      <div>
        <img src="${result.url}" alt=${result.name}>
        <h3>${result.name}</h3>
      </div>
    `;
    return;
  }

  // Render nothing
  container.innerHTML = '';
});

search.addWidgets([
  // Add your widgets here
  index({ indexName: 'structuredIndex' }).addWidgets([
    configure({
      page: 0,
      hitsPerPage: 1,
      getRankingInfo: true
    }),
    structuredResults({
      container: document.querySelector('#structured-results')
    })
  ])
]);

// ...

By comparing the number of exact word matches to 1 + the total distance between all the words in the match, we make sure that all matched words are sorted. In other terms, when all matching words against a user’s query are sequential and adjacent, the proximity (or distance between search terms) is always equal to exact word matches - 1

There’s no requirement as to when to display your content, this part is up to you.

Another constraint that we may impose on the rendering of the structured result could be to check that the count of exact word matches is equal to the number of words in the value of the attribute being queried. For example, we may only want to show a brand when all words of that brand have been typed. You can find more information on the ranking info documentation to learn about other useful metrics you can access in the results.

Another example, a different use case

Let’s now imagine we’re iterating on an entertainment website that displays structured results on movies: if we can determine that someone is searching for a specific movie, we will embed a section displaying the movie details within the main search interface. That is, we’d like to communicate to the user that there might be a salient piece of content worth showcasing.

How will the data look?

Let’s again consider how we should structure our data. We first need a main index, as with the e-commerce example. This is where people will always see traditional results even if there’s no structured data match.

Think about a major search engine when you search a new movie: you might get structured results with the cast, showtimes, and video clips at the same time. In Algolia, that would require three extra indices—one for each result type.

Our example is a bit simpler, as we only have a single data type to show structured results: movies. Yet, we can imagine a circumstance where we would match on actors, directors, etc.

Here’s how a sample movie record could look like:

1
2
3
4
5
6
7
8
9
10
{
  "title": "The Shawshank Redemption",
  "year": 1994,
  "image": "https://image.tmdb.org/t/p/w154/9O7gLzmreU0nGkIB6K3BsJbzvNv.jpg",
  "color": "#8C634B",
  "score": 9.97764206054169,
  "rating": 5,
  "actors": ["Tim Robbins", "Morgan Freeman", "Bob Gunton"],
  "objectID": "439817390"
}

Records with this structure would be stored in another index. Keep in mind though that if our new index doesn’t contain any new data, it could be a replica of our primary index. (for example, searchable attributes or custom ranking order).

You can display the data and render the result exactly the same way as in the previous e-commerce example.

Conclusion

The movie and e-commerce examples we went over are just two scenarios among many that may call for structured data, all of which follow a similar pattern of giving users the ability to search through multiple indices and showcase results accordingly.

Search paradigms continue to evolve, and the rise of “structured results” is part of an ongoing itch to enrich a user’s process of discovery while browsing content. Algolia enables users the flexibility to roll out their own flavor of “structured results” by making simple the ability to search against multiple types of content and customizing how the search is performed.

Did you find this page helpful?