Dev guideRecipesAPI ReferenceChangelog
Dev guideRecipesUser GuidesNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev guide

Fuzzy search

Explanation and examples on how to support fuzzy search matching in Optimizely Graph.

Site visitors often misspell query terms and miss the content they want. Fuzzy search in Optimizely Graph returns relevant results even when the query has typos, which keeps the search experience useful for visitors who do not remember exact spellings.

Optimizely applies approximate string matching to both the query terms and the terms in the content items you have synchronized to Optimizely Graph. For example, when you enter the query Arnodl Schwarzeneggerr with fuzzy matching enabled, the system returns content items that have Arnold Schwarzenegger.

The Optimizely Graph query language supports fuzzy search for searchable string fields, including the _fulltext field. Enable fuzzy search by setting the Boolean fuzzy operator option, similar to boost and synonym. The default value is false, which disables fuzzy search. The following operators support fuzzy:

  • eq and notEq
  • in and notIn
  • contains
  • match
📘

Note

With contains, the fuzzy option works on each word. Optimizely extracts words from a string value using a non-word boundary, so special characters such as @ or - act as tokenization splits.

For example, the system splits Sn@pdragon into two words, sn and pdragon. Applying fuzzy with sn@pdragon on those words does not retrieve results when the actual value is Snapdragon because the edit distance for each word is too great.

Optimizely Graph uses the Damerau–Levenshtein distance (the minimum number of single-character edits required to transform one string into another) to measure the distance between two strings. The system derives the edit distance automatically from the length of the query term. The system calculates the distance as follows:

  • For contains, the edit distance is determined by each word. The distance is calculated for the whole value for eq and in (and their inverses).
  • The edit distance is calculated with the following heuristics:
    • If a word is between zero and two characters long, it must be exact (distance of zero).
    • If a word is between three and five characters long, the edit distance is one.
    • If a word is six or more characters long, the edit distance is two.
📘

Note

Fuzzy search does not apply to synonyms. Synonyms expand only exact, case-insensitive values.

Examples

The following examples show how fuzzy search recovers results for misspelled queries and where it stops working.

A misspelled name with eq matching returns correct results when fuzzy: true. Without fuzzy: true, the query returns no results.

{
  BiographyPage(where: { Name: { eq: "Arnodl Schwarzeneggerr", fuzzy: true } }) {
    items {
      Name
    }
  }
}

Similarly for the contains operator for searchable string fields, Optimizely Graph returns results with the following query:

{
  BiographyPage(where: { Name: { contains: "Swarzenegger", fuzzy: true } }) {
    items {
      Name
      Die
      Born
      Language {
        DisplayName
        Name
      }
    }
  }
}

The following query does not return results with contains and the value Xiaomi Youpin Lydsto because Optimizely does a fuzzy match on each word, and the distance for XiaomiYoupin is too great to match on any of the words.

{
  TemporaryPage(
    locale: ALL
    where: { Product: { contains: "XiaomiYoupin Lydsto", fuzzy: true } }
    orderBy: { Product: ASC }
    limit: 100) {
  	total
  	items {
    	Product
  	}
	}
}

However, the following query returns results with the value ferrari-purosangue because it matches the word purosanqe, where the edit distance is two. Fuzzy matching does not affect ferrary when the content is synchronized to the English locale, because the system applies stemming and resolves ferrary to ferrari.

{
  TemporaryPage(
    locale: ALL
    where: { Product: { contains: "ferrary-purosanqe", fuzzy: true } }
    orderBy: { Product: ASC }
    limit: 100) {
    total
    items {
      Product
    }
  }
}