I’ve been playing with RavenDb’s pre-defined indexes today. They use a map reduce model with Linq, which is very nice. A recent new feature is the ability to define them in your application code. Here a couple I’ve just created:
public class Child_ByName : AbstractIndexCreationTask<Child> { public Child_ByName() { Map = children => from child in children select new { child.Name }; } } public class Child_ByPendingSchedule : AbstractIndexCreationTask<Child> { public Child_ByPendingSchedule() { Map = children => from child in children from schedule in child.Account.PaymentSchedules select new { schedule.NextRun }; } }
You register them with the RavenDb document store (a bit like a session factory in NHibernate) like this:
IndexCreation.CreateIndexes(typeof(Child_ByName).Assembly, store);
When you want to use them, you have to use a rather nasty magic string (RavenDb converts the underscore in the class name to a forward slash ‘/’).
var results = session.Advanced.LuceneQuery<Child>("Child/ByName").WhereEquals("Name", "two").ToList();
It would be much nicer if you could write something like this instead:
var results = session.Advanced.LuceneQuery<Child_ByName>().WhereEquals("Name", "two").ToList();
Here a couple of tests showing them at work:
[TestFixture] public class RavenDbSchedulingWithIndex : LocalClientTest { IDocumentStore store; Parent parent; DateTime now; [SetUp] public void SetUp() { store = NewDocumentStore(); IndexCreation.CreateIndexes(typeof(Child_ByName).Assembly, store); parent = new Parent("Dad", "mike@mike.com", "xxx"); now = new DateTime(2010, 4, 5); // create some children with accounts and schedules using (var session = store.OpenSession()) { session.Store(CreateChildWithSchedule("one", 1M, now.AddDays(-2))); session.Store(CreateChildWithSchedule("two", 2M, now.AddDays(-1))); session.Store(CreateChildWithSchedule("three", 3M, now)); session.Store(CreateChildWithSchedule("four", 4M, now.AddDays(1))); session.Store(CreateChildWithSchedule("five", 5M, now.AddDays(2))); session.SaveChanges(); } } [Test] public void Select_child_using_ByName_index() { using (var session = store.OpenSession()) { var results = session.Advanced.LuceneQuery<Child>("Child/ByName").WhereEquals("Name", "two").WaitForNonStaleResults().ToList(); results.Count().ShouldEqual(1); results[0].Name.ShouldEqual("two"); } } [Test] public void Select_child_using_ByPendingSchedule() { using (var session = store.OpenSession()) { var results = session.Advanced .LuceneQuery<Child>("Child/ByPendingSchedule") .WhereLessThan("NextRun", now) .WaitForNonStaleResults().ToList(); results.Count().ShouldEqual(2); results[0].Name.ShouldEqual("one"); results[1].Name.ShouldEqual("two"); } } Child CreateChildWithSchedule(string name, decimal amount, DateTime startDate) { var child = parent.CreateChild(name, name, "xxx"); child.Account.AddPaymentSchedule(startDate, Interval.Week, amount, "Pocket Money"); return child; } }
This is some spike code from Tardis Bank. You can checkout the complete project here:
3 comments:
Um, you can do Query
And LuceneQuery, at least I know you can in the unstable branch, I don't know if that's been moved to stable yet.
Okay, so Blogger strips out angle brackets, I was trying to say you can specify the index
http://codeofrob.com/archive/2010/10/24/ravendbndashthe-image-gallery-project-xv-improving-tag-search-with-autocomplete.aspx
Example is there, works in a similar fashion with the Lucene stuff too
Hi Rob,
Yes, I've been using Query as a first choice. For what I wanted to do here, there are some missing corners of the Linq implementation, so it's nice to be able to fall back on indexes. Here's the discussion on the mailing list:
http://groups.google.com/group/ravendb/browse_thread/thread/c5400e00d289a5f8
Post a Comment