Skip to main content

Query for suggestions with index

Configure the index for suggestions

  • In order to be able to ask for suggested terms when querying an index field,
    that field must first be configured for suggestions in the index definition.

  • See the following sample index:
    (This index will be used in the examples ahead).

public class Products_ByName : AbstractIndexCreationTask<Product, Products_ByName.IndexEntry>
{
// The IndexEntry class defines the index-fields
public class IndexEntry
{
public string ProductName { get; set; }
}

public Products_ByName()
{
// The 'Map' function defines the content of the index-fields
Map = products => from product in products
select new IndexEntry
{
ProductName = product.Name
};

// Configure index-field 'ProductName' for suggestions
Suggestion(x => x.ProductName);

// Optionally: set 'Search' on this field
// This will split the field content into multiple terms allowing for a full-text search
Indexes.Add(x => x.ProductName, FieldIndexing.Search);
}
}

Increased indexing time:

  • When configuring an index for suggestions, then during the indexing process,
    in addition to the regular breakdown of the data into terms (tokenization),
    RavenDB will scramble the terms to simulate common errors.

  • This can impact indexing speed but the cost of querying suggestions is Not impacted.

The index terms

Based on the Northwind sample data,
these are the terms generated for the above index Products/ByName:

Figure 1. Index terms

  1. The index-field name - as defined in the index definition.
    In this example the field name is ProductName.

  2. The terms that were generated for this index-field from the documents in the Products collection.

    • The image shows a partial view out of the 163 terms in this list.
    • The terms were generated by RavenDB's default search analyzer since full-text search was set on this field.

Suggest terms - for a single term

Based on the Northwind sample data,
the following query on the index Products/ByName from above has no resulting documents,
since the term chokolade does Not exist in the index terms for index-field ProductName.

// This query on index 'Products/ByName' has NO resulting documents
List<Product> products = session
.Query<Products_ByName.IndexEntry, Products_ByName>()
.Search(x => x.ProductName, "chokolade")
.OfType<Product>()
.ToList();

If you suspect that the term chokolate in the query criteria is written incorrectly,
you can ask RavenDB to suggest similar terms from the index, as follows:

// Query the index for suggested terms for single term:
// ====================================================

Dictionary<string, SuggestionResult> suggestions = session
// Query the index
.Query<Products_ByName.IndexEntry, Products_ByName>()
// Call 'SuggestUsing'
.SuggestUsing(builder => builder
// Request to get terms from index-field 'ProductName' that are similar to 'chokolade'
.ByField(x => x.ProductName, "chokolade"))
.Execute();
// The resulting suggested terms:
// ==============================

Console.WriteLine("Suggested terms in index-field 'ProductName' that are similar to 'chokolade':");
foreach (string suggestedTerm in suggestions["ProductName"].Suggestions)
{
Console.WriteLine("\t{0}", suggestedTerm);
}

// Suggested terms in index-field 'ProductName' that are similar to 'chokolade':
// schokolade
// chocolade
// chocolate

Suggest terms - for multiple terms

// Query the index for suggested terms for multiple terms:
// =======================================================

Dictionary<string, SuggestionResult> suggestions = session
// Query the index
.Query<Products_ByName.IndexEntry, Products_ByName>()
// Call 'SuggestUsing'
.SuggestUsing(builder => builder
// Request to get terms from index-field 'ProductName' that are similar to 'chokolade' OR 'syrop'
.ByField(x => x.ProductName, new[] { "chokolade", "syrop" }))
.Execute();
// The resulting suggested terms:
// ==============================

// Suggested terms in index-field 'ProductName' that are similar to 'chokolade' OR to 'syrop':
// schokolade
// chocolade
// chocolate
// sirop
// syrup

Suggest terms - for multiple fields

// Query the index for suggested terms in multiple fields:
// =======================================================

Dictionary<string, SuggestionResult> suggestions = session
// Query the index
.Query<Companies_ByNameAndByContactName.IndexEntry, Companies_ByNameAndByContactName>()
// Call 'SuggestUsing' to get suggestions for terms that are
// similar to 'chese' in first index-field (e.g. 'CompanyName')
.SuggestUsing(builder => builder
.ByField(x => x.CompanyName, "chese" ))
// Call 'AndSuggestUsing' to get suggestions for terms that are
// similar to 'frank' in an additional index-field (e.g. 'ContactName')
.AndSuggestUsing(builder => builder
.ByField(x => x.ContactName, "frank"))
.Execute();
// The resulting suggested terms:
// ==============================

// Suggested terms in index-field 'CompanyName' that is similar to 'chese':
// cheese
// chinese

// Suggested terms in index-field 'ContactName' that are similar to 'frank':
// fran
// franken

Suggest terms - customize options and display name

// Query the index for suggested terms - customize options and display name:
// =========================================================================

Dictionary<string, SuggestionResult> suggestions = session
// Query the index
.Query<Products_ByName.IndexEntry, Products_ByName>()
// Call 'SuggestUsing'
.SuggestUsing(builder => builder
.ByField(x => x.ProductName, "chokolade")
// Customize suggestions options
.WithOptions(new SuggestionOptions
{
Accuracy = 0.3f,
PageSize = 5,
Distance = StringDistanceTypes.NGram,
SortMode = SuggestionSortMode.Popularity
})
// Customize display name for results
.WithDisplayName("SomeCustomName"))
.Execute();
// The resulting suggested terms:
// ==============================

Console.WriteLine("Suggested terms:");
// Results are available under the custom name entry
foreach (string suggestedTerm in suggestions["SomeCustomName"].Suggestions)
{
Console.WriteLine("\t{0}", suggestedTerm);
}

// Suggested terms:
// chocolade
// schokolade
// chocolate
// chowder
// marmalade