diff --git a/docs/documents/full-text.md b/docs/documents/full-text.md index f5e3956cd4..8124f3424d 100644 --- a/docs/documents/full-text.md +++ b/docs/documents/full-text.md @@ -402,3 +402,56 @@ var result = await session ``` snippet source | anchor + +## NGram Search Across Multiple Properties +In many cases, you may want to perform partial text search across multiple fields like `UserName`, `FirstName`, and `LastName`. + +A naive approach might be to apply individual Ngram indexes and search each field separately: + +::: danger Don't do this +This results in multiple indexes per document and requires complex `LINQ` queries to combine the results — inefficient and hard to maintain. +::: +```csharp +// Inefficient and verbose +var store = DocumentStore.For(_ => +{ + _.Connection(ConnectionSource.ConnectionString); + + // Too many indexes + _.Schema.For().NgramIndex(d => d.UserName); + _.Schema.For().NgramIndex(d => d.FirstName); + _.Schema.For().NgramIndex(d => d.LastName); +}); + +var result = await session + .Query() + .Where(x => x.UserName.NgramSearch(term) + || x.FirstName.NgramSearch(term) + || x.LastName.NgramSearch(term)) + .ToListAsync(); +``` +Instead, define a computed property that concatenates the values into a single field, and index that: +```csharp +public class User +{ + public Guid Id { get; set; } + public string UserName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + + // Combine searchable fields + public string SearchString => $"{UserName} {FirstName} {LastName}"; +} +``` +Then configure the Ngram index on that property: + +```csharp + _.Schema.For().NgramIndex(x => x.SearchString); +``` +This simplifies querying: +```csharp +var result = await session + .Query() + .Where(x => x.SearchString.NgramSearch(term)) + .ToListAsync(); +``` \ No newline at end of file