A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Mark Stott
Nov 19, 2021
  3628
(4 votes)

Optimizely Search Wildcard Queries and Best Bets

In a recent client build, I have been tasked with updating their search to use wild card searches.  I had read a number of posts pointing to the same solution as detailed by Joel Abrahamsson's 2012 blog post, Wildcard Queries with Episerver Find and Drew Null's post Episerver Find Wildcard Queries and Best Bets. These solutions included building an extension method that built a bool query wrapping a wild card query. This included complications in how to get best bets to work with wildcards.

While the solution did work, after reviewing the performance of the query and the structure of the query being sent to Optimizely Search and Navigation, I discovered that the solution was actually much simpler and did not need any new scaffolding of custom query building.  The For method has overloads which exposes the QueryStringQuery object that allows you to customise the query behaviour.

private ITypeSearch<T> GetQuerySearch<T>(
	string query, 
	bool isWildCardSearch) where T : MyVariant
{
	var specificQuery = isWildCardSearch ? $"*{query}*" : query;
	return _findClient.Search<T>()
                      .For(query, options =>
                      {
                          options.Query = specificQuery;
                          options.AllowLeadingWildcard = isWildCardSearch;
                          options.AnalyzeWildcard = isWildCardSearch;
                          options.RawQuery = query;
                      })
                      .InField(f => f.FieldOne, _settings.FieldOneBoost)
                      .InField(f => f.FieldTwo, _settings.FieldTwoBoost)
                      .InField(f => f.FieldThree, _settings.FieldThreeBoost)
                      .InField(f => f.FieldFour)
                      .InField(f => f.FieldFive)
                      .InField(f => f.FieldSix)
                      .InField(f => f.FieldSeven)
                      .InField(f => f.FieldEight)
                      .UsingSynonyms()
                      .UsingAutoBoost(TimeSpan.FromDays(_settings.AutoBoostTimeSpanDays))
                      .ApplyBestBets()
                      .FilterForVisitor();
}

By passing in the wild card version of the query string into options.Query and setting options.AllowLeadingWildcard and options.AnalyzeWildcard to true was all I needed for wildcard search to be functional.  I also passed in the unaltered query into options.RawQuery but this was not required in order to make Best Bets work.

The main downside to this approach is that synonym functionality no longer worked.  The query with the wildcards would never match a synonym but it would work with best bets.  I resolved this by using a Multi Search query and passed in the unaltered query and then the wild card query.  In Multi Search, each result set is returned in the same order in which it has been defined and they are packaged in a single API call.  It was then a simple case of selecting the first result set with at least one match.

var searchResult _findClient.MultiSearch<DentalVariantProjectionModel>()
                                            .Search<MyVariant, MyProjectionModel>(x => GetQuerySearch(query, false))
                                            .Search<MyVariant, MyProjectionModel>(x => GetQuerySearch(query, true))
                                            .GetResult();

var resultToUse = searchResult.FirstOrDefault(x => x.TotalMatching > 0) ?? searchResult.First();

Performance wise, the difference in sending two queries in a multi search request was negligable compared to a sending a single query.

Nov 19, 2021

Comments

Please login to comment.
Latest blogs
Looking back at Optimizely in 2025

Explore Optimizely's architectural shift in 2025, which removed coordination cost through a unified execution loop. Learn how agentic Opal AI and...

Andy Blyth | Dec 17, 2025 |

Cleaning Up Content Graph Webhooks in PaaS CMS: Scheduled Job

The Problem Bit of a niche issue, but we are building a headless solution where the presentation layer is hosted on Netlify, when in a regular...

Minesh Shah (Netcel) | Dec 17, 2025

A day in the life of an Optimizely OMVP - OptiGraphExtensions v2.0: Enhanced Search Control with Language Support and Synonym Slots

Supercharge your Optimizely Graph search experience with powerful new features for multilingual sites and fine-grained search tuning. As search...

Graham Carr | Dec 16, 2025

A day in the life of an Optimizely OMVP - Optimizely Opal: Specialized Agents, Workflows, and Tools Explained

The AI landscape in digital experience platforms has shifted dramatically. At Opticon 2025, Optimizely unveiled the next evolution of Optimizely Op...

Graham Carr | Dec 16, 2025

Optimizely CMS - Learning by Doing: EP09 - Create Hero, Breadcrumb's and Integrate SEO : Demo

  Episode 9  is Live!! The latest installment of my  Learning by Doing: Build Series  on  Optimizely Episode 9 CMS 12  is now available on YouTube!...

Ratish | Dec 15, 2025 |

Building simple Opal tools for product search and content creation

Optimizely Opal tools make it easy for AI agents to call your APIs – in this post we’ll build a small ASP.NET host that exposes two of them: one fo...

Pär Wissmark | Dec 13, 2025 |