Skip to main content

Multi-Map Indexes

AddMap & AddMapForAll

The AddMap method is used to map fields from a single collection, e.g. Dogs.
AddMapForAll gives you the ability to specify what fields will be indexed from a base class.

Let's assume that we have Dog and Cat classes, both inheriting from the class Animal:

public class Dog : Animal
{

}

We can define our index using AddMap or AddMapForAll and query it as follows:

public class Animals_ByName : AbstractMultiMapIndexCreationTask
{
public Animals_ByName()
{
AddMap<Cat>(cats => from c in cats select new { c.Name });

AddMap<Dog>(dogs => from d in dogs select new { d.Name });
}
}
IList<IAnimal> results = session
.Query<IAnimal, Animals_ByName>()
.Where(x => x.Name == "Mitzy")
.ToList();

Searching across multiple collections

Another great usage of Multi-Map indexes is smart-search.

To search for products, companies, or employees by their name, you need to define the following index:

public class Smart_Search : AbstractMultiMapIndexCreationTask<Smart_Search.Result>
{
public class Result
{
public string Id { get; set; }

public string DisplayName { get; set; }

public object Collection { get; set; }

public string[] Content { get; set; }
}

public class Projection
{
public string Id { get; set; }

public string DisplayName { get; set; }

public string Collection { get; set; }
}

public Smart_Search()
{
AddMap<Company>(companies => from c in companies
select new Result
{
Id = c.Id,
Content = new[]
{
c.Name
},
DisplayName = c.Name,
Collection = MetadataFor(c)["@collection"]
});

AddMap<Product>(products => from p in products
select new Result
{
Id = p.Id,
Content = new[]
{
p.Name
},
DisplayName = p.Name,
Collection = MetadataFor(p)["@collection"]
});

AddMap<Employee>(employees => from e in employees
select new Result
{
Id = e.Id,
Content = new[]
{
e.FirstName,
e.LastName
},
DisplayName = e.FirstName + " " + e.LastName,
Collection = MetadataFor(e)["@collection"]
});

// mark 'Content' field as analyzed which enables full text search operations
Index(x => x.Content, FieldIndexing.Search);

// storing fields so when projection (e.g. ProjectInto)
// requests only those fields
// then data will come from index only, not from storage
Store(x => x.Id, FieldStorage.Yes);
Store(x => x.DisplayName, FieldStorage.Yes);
Store(x => x.Collection, FieldStorage.Yes);
}
}

and query it using:

IList<Smart_Search.Projection> results = session
.Query<Smart_Search.Result, Smart_Search>()
.Search(x => x.Content, "Lau*")
.ProjectInto<Smart_Search.Projection>()
.ToList();

foreach (Smart_Search.Projection result in results)
{
Console.WriteLine(result.Collection + ": " + result.DisplayName);
// Companies: Laughing Bacchus Wine Cellars
// Products: Laughing Lumberjack Lager
// Employees: Laura Callahan
}

Remarks

Remember that all map functions must output objects with an identical shape (the field names have to match).