SearchExtensions

repository·master·Indexed 43 days ago

https://github.com/ninjanye/searchextensions

A library of extension methods for IQueryable and IEnumerable providing a fluent API for complex searches. It supports operations such as Containing, StartsWith, and EndsWith, as well as ranked searches via ToRanked(). Specialized packages are available for Levenshtein and Soundex phonetic searches.

Tokens
2.2K
Snippets
6
Records
8
Agent score
6%

What's inside SearchExtensions

  1. How IQueryable searching works

    master
    The IQueryable extension methods build expression trees based on your command chain. This request is sent to the data provider (e.g., Entity Framework), ensuring that the data provider restricts the records at the database level rather than pulling all records into memory for filtering.
  2. Perform Ranked Searches with `ToRanked()`

    master

    You can use the ToRanked() method on both IQueryable and IEnumerable collections to perform a search that returns not just the matched items, but also a hit count for each item. This is useful for ordering results by relevance.

    When using ToRanked(), the result is wrapped in an IRanked<T> object. The ToRanked() method uses the search terms provided in methods like Containing() and the selected properties to calculate these hit counts.

    Note: The fluent ToRanked() method is the replacement for the now-deprecated RankedSearch method.

    // Example: Retrieve top 10 most relevant users based on name matches
    var result = context.Users.Search(x => x.FirstName, x => x.LastName, x => x.MiddleName)
                              .Containing("John")
                              .ToRanked()
                              .OrderByDescending(r => r.Hits)
                              .Take(10);
  3. Perform complex AND searches with IQueryable

    master

    You can chain multiple .Search() calls to create complex AND logic between different property groups.

    • Property AND Property: Chain .Search(prop1).Containing(term1).Search(prop2).Containing(term2).
    • (Prop1 OR Prop2) AND (Prop3 OR Prop4): Chain .Search(prop1, prop2).Containing(term).Search(prop3, prop4).Containing(term).
    • (Prop1 OR Prop2) AND (Multiple terms in Prop3): Chain .Search(prop1, prop2).Containing(term).Search(prop3).Containing(term1, term2).
    // Search where (Property1 OR Property2) contains 'searchTerm' 
    // AND (Property3 OR Property4) contains 'searchTerm'
    var result = queryableData.Search(x => x.Property1, x => x.Property2)
                              .Containing("searchTerm")
                              .Search(x => x.Property3, x => x.Property4)
                              .Containing("searchTerm");
  4. Install SearchExtensions NuGet packages

    master

    SearchExtensions is distributed via three NuGet packages depending on your requirements:

    • NinjaNye.SearchExtensions: Provides a fluent API for complex searches across IEnumerable and IQueryable collections.
    • NinjaNye.SearchExtensions.Levenshtein: Specialized for performing Levenshtein distance searches across IEnumerable collections.
    • NinjaNye.SearchExtensions.Soundex: Specialized for performing Soundex searches across IEnumerable collections.

    Note: If you are upgrading from version 2.2 or lower, Levenshtein and Soundex functionality has been migrated to these dedicated packages.

  5. Perform Soundex searches

    master

    Using the NinjaNye.SearchExtensions.Soundex package, you can perform phonetic searches using the Soundex algorithm. This allows you to find words that 'sound like' a given term.

    These methods (SoundexOf and ReverseSoundexOf) can be applied to both IEnumerable and IQueryable. For IQueryable, the library attempts to reduce the record count at the data source, but be aware that the actual Soundex comparison is performed on the in-memory collection.

    // Search where a single property sounds like a single search term
    var result = data.SoundexOf(x => x.Property1).Matching("test");
    
    // Search where multiple properties sound like multiple search terms
    var result = data.SoundexOf(x => x.Property1, x => x.PropertyTwo)
                     .Matching("test", "another");
    
    // Using Reverse Soundex
    var result = data.ReverseSoundexOf(x => x.Property1).Matching("test");
  6. Perform searches on IEnumerable (in-memory)

    master

    You can perform searches on in-memory IEnumerable collections using the same fluent API as IQueryable. IEnumerable searching includes additional methods:

    • EndsWith: Target property ends with search term or terms.
    • SetCulture: Sets the StringComparison culture for subsequent searches.

    Important: When performing in-memory searches, you should specify the culture using SetCulture. If SetCulture is not specified, StringComparison.CurrentCulture is used by default.

    // Example of in-memory search with culture specification
    var result = enumerableData.Search(x => x.Property1)
                               .SetCulture(StringComparison.OrdinalIgnoreCase)
                               .StartsWith("abc")
                               .EndsWith("xyz")
                               .Containing("mno");
    
    // You can switch the culture context multiple times
    var result = enumerableData.Search(x => x.Property1)
                               .SetCulture(StringComparison.OrdinalIgnoreCase)
                               .StartsWith("abc")
                               .SetCulture(StringComparison.Ordinal)
                               .EndsWith("xyz")
                               .SetCulture(StringComparison.CurrentCulture)
                               .Containing("mno");
  7. Perform searches on IQueryable

    master

    Use the .Search() method followed by one of the following search actions to filter IQueryable data:

    • Containing: Target property contains search term or terms.
    • IsEqual: Target property equals search term or terms.
    • StartsWith: Target property starts with search term or terms.

    You can target a single property, multiple properties, or use multiple search terms within a single property or across multiple properties.

    // Single term, single property
    var result = queryableData.Search(x => x.Property1).Containing("searchTerm");
    
    // Multiple terms, multiple properties
    var result = queryableData.Search(x => x.Property1, x => x.Property2, x => x.Property3)
                               .Containing("searchTerm1", "searchTerm2", "searchTerm3");
    
    // Combining instructions (AND logic)
    var result = queryableData.Search(x => x.Property1)
                               .StartsWith("abc")
                               .Containing("mno");
  8. Use the `IRanked<T>` interface

    master

    The IRanked<T> interface is the return type when using the ToRanked() method. It provides access to the original item and the number of hits that item accumulated during the search.

    public interface IRanked<out T>
    {
        int Hits { get; }
        T Item { get; }
    }