Options

A part of Limbo Search uses a concept around options classes that may be used to build up search queries. The general idea is than an options class can wrap all the Examine specific search logic such that other parts of your code can be implemented without requiring to interact directly with Examine.

For instance for a hypotetical site, you could have an EmployeeSearchOptions class that wraps up the logic for searching specifically for employees, and then another NewsSearchOptions class that wraps up the logic for searching for news articles.

Limbo Search comes with a bunch of options related interfaces and base classes that you can implement and extend in order to control how the search is performed.

ISearchOptions

At the center is the ISearchOptions interface. It does nothing more than requiring you to implement a GetBooleanOperation method, which returns an instance of Examine's IBooleanOperation.

To start out simple, an EmployeeSearchOptions class could limit the search to all nodes where the node type alias is employee. Eg. such as:

public class EmployeeSearchOptions : ISearchOptions {

    public IBooleanOperation GetBooleanOperation(ISearchHelper searchHelper, ISearcher searcher, IQuery query) {

        return query.NativeQuery("__NodeTypeAlias:employee");

    }

}

Since the options class implements the ISearchOptions interface, it can be passed on to ISearchHelper.Search method, which will then return an instance of SearchResultList representing the overall result.

Each item is an instance of Examine's ISearchResult.

@inject ISearchHelper SearchHelper

@{

    // Make the search via the search helper
    SearchResultList  result = SearchHelper.Search(new EmployeeSearchOptions())

    <pre>Total: @result.Total</pre>

    foreach (ISearchResult item in result.Items) {

        <pre>@item.Id</pre>

    }

}

ISearcherOptions

If your options class both implements ISearchOptions and ISearcherOptions, the ISearchHelper.Search method will ask the ISearcherOptions.Searcher property for which ISearcher to be used for the search (opposed to the external index, which is default).

The property being a property doesn't really allow for advanced logic, so usage may be limited. But other code may set the property:

public class EmployeeSearchOptions : ISearchOptions, IGetSearcherOptions {

    public ISearcher? Searcher { get; set; }

    public IBooleanOperation GetBooleanOperation(ISearchHelper searchHelper, ISearcher searcher, IQuery query) {
        return query.NativeQuery("__NodeTypeAlias:employee");
    }

}

IGetSearcherOptions

The IGetSearcherOptions.GetSearcher method works in the same way as the ISearcherOptions.Searcher property, but since it's a method, a few useful dependencies are passed along via the methods's parameter.

For instance, the IExamineManager instance as shown in the example below can be used to get a reference to the members index, which we then can use to get the searcher for the index.

The GetSearcher return value is nullable, meaning if a null is returned, the ISearchHelper.Search will default back to the external index.

public class EmployeeSearchOptions : ISearchOptions, IGetSearcherOptions {

    public IBooleanOperation GetBooleanOperation(ISearchHelper searchHelper, ISearcher searcher, IQuery query) {
        return query.NativeQuery("__NodeTypeAlias:employee");
    }

    public ISearcher? GetSearcher(IExamineManager examineManager, ISearchHelper searchHelper) {
        if (examineManager.TryGetIndex("MemberIndex", out IIndex? index)) return index.Searcher;
        return null;
    }

}

ILeadingWildcardSearchOptions

Eg. when extended a class like SearchOptionsBase, the Text property onyl supports trailing wildcards - a wildcard at the end of each work. This means that when searching for a bike, your search will also match words like bikes and biker.

Leading wildcards - a wildcard at the start of each word - are not supported by default. Among other things, this may require a bit more performance as Lucene indexes aren't optimized for this. But by having your search options class implement the ILeadingWildcardSearchOptions interface, you can set it's AllowLeadingWildcard to true, and a search for ike will match bike as well as bikes and biker. But also Mike and hike - so be careful that your search isn't search too broad.

public class EmployeeSearchOptions : SearchOptionsBase {

    public bool? AllowLeadingWildcard { get; set; }

    public EmployeeSearchOptions() {
        AllowLeadingWildcard = true;
    }

}

When using SearchOptionsBase and enabling leading wildcards, this will apply to all text fields returned by the SearchOptionsBase.GetTextFields method.

SearchOptionsBase

This package very much works by creating an options class that then implements the interfaces for the specific features that you need. In a new solution, this can be a bit cumbersome, so to get going more quickly, the package also features the SearchOptionsBase class, that you can extend to get the most basic logic right away.

Read more about the SearchOptionsBase class