Transforming Index Results

115 views
Skip to first unread message

Ben

unread,
Jul 4, 2012, 7:21:09 PM7/4/12
to rav...@googlegroups.com
I have the following index (simplified for this question):

        public Jobs_Search()
        {
            Map = vacancies => from v in vacancies
                               from c in v.Campaigns
                               where c.Status == CampaignStatus.Active
                               select new
                               {
                                   Id = v.Id,
                                   DateSubmitted = v.DateSubmitted,
                                   JobCategoryId = v.JobCategoryId,
                                   Salary = v.Salary.From,
                                   Location = new {
                                        v.Location.TownCity,
                                        v.Location.County
                                   },
                                   Keywords = new {
                                       c.Title,
                                       c.Keywords,
                                       c.Summary,
                                       c.Description
                                   },
                                   JobTypes = v.JobTypes,
                                   IsFeatured = c.IsFeatured
                               };

            Index(x => x.Location, Raven.Abstractions.Indexing.FieldIndexing.Analyzed);
            Index(x => x.Keywords, Raven.Abstractions.Indexing.FieldIndexing.Analyzed);

            TransformResults = (store, results) =>
                               // ommitted for brevity
                               select new
                               {
// view model class fields
                               };
        }

        public class Index
        {
            public string Id { get; set; }
            public DateTime DateSubmitted { get; set; }
            public string JobCategoryId { get; set; }
            public decimal Salary { get; set; }
            public string Location { get; set; }
            public string Keywords { get; set; }
            public string[] JobTypes { get; set; }
            public bool IsFeatured { get; set; }
        }
    }

Within "TransformResults" we retrieve some additional information from the database and build up our ViewModel class (JobSummary).

When querying this index we do the following:

                var jobs = session.Query<JobSummary, Jobs_Search>()
                    .Statistics(out stats)
                    .OrderBy(j => j.DateSubmitted)
                    .Skip((page - 1) * pageSize)
                    .Take(pageSize)
                    .ToList();

Notice here that we are asking raven to return "JobSummary" (our ViewModel) rather than the Jobs_Search.Index class. 

We found a bug in the index (our fault) and needed to add criteria for two additional fields. To do this we would need to add the fields to both the Jobs_Search.Index class and the JobSummary ViewModel class. 

I don't like this since we don't care about presenting these fields we only want them for querying.

So my question.

Does "AsProjection<T>" achieve the same thing? This way I can just do:

 session.Query<Jobs_Search.Index, Jobs_Search>() 

and then call

 .AsProjection<JobSummary>()

at the very end.

I'm using similar code in a number of places so wanted to verify this behaviour before I swap it out.

Thanks,
Ben

Itamar Syn-Hershko

unread,
Jul 4, 2012, 7:44:01 PM7/4/12
to rav...@googlegroups.com
AsProjection means those values will be fetched from the index, and they got there either because they existed in the original class you indexed or you took data from that class and dropped it under that field name

Unless the data for those fields is already available to you in the current dataset that you are indexing, I don't think you have much choice

Ben

unread,
Jul 4, 2012, 7:59:37 PM7/4/12
to rav...@googlegroups.com
To verify then, does AsProjection include the properties returned from TransformResults?

So take the following index class, view model and transform function:

public class Index {
public string CustomerId {get; set;}
public string OrderId {get; set;}
public string OrderDate {get; set;}
}
public class CustomerOrder {
public string CustomerName {get; set;}
public string OrderValue {get; set;}
}
TransformResults = (store, results) =>
  from result in results
  let customer = store.Load<Customer>(result.CustomerId)
  let order = store.Load<Order>(result.OrderId)
  select new
  {
  CustomerName = customer.Name,
  OrderValue = order.Value
  };

Can I then do:

session.Query<OrderSearch.Index, OrderSearch>()
.Where(o => o.OrderDate < DateTime.UtcNow)
.AsProjection<CustomerOrder>();

Or do I need to ensure that the properties in the transform result also exist in the index class?

Oren Eini (Ayende Rahien)

unread,
Jul 5, 2012, 4:44:22 AM7/5/12
to rav...@googlegroups.com
No, you don't need to do that.  

Ben

unread,
Jul 5, 2012, 5:37:30 AM7/5/12
to rav...@googlegroups.com
Is there a difference between using As<T> and AsProjection<T> ?

Oren Eini (Ayende Rahien)

unread,
Jul 5, 2012, 5:43:46 AM7/5/12
to rav...@googlegroups.com
Yes, As<T> just tells the client "expect something with this shape".
AsProjection<T> tells the client "expect something with this shape" and tell the server "I want you to try to load just those fields" 

Ben

unread,
Jul 5, 2012, 6:02:32 AM7/5/12
to rav...@googlegroups.com
So in most cases, AsProjection<T> should be faster?

Also, is there a way to project a LuceneQuery to a type without having to name each individual property?

Oren Eini (Ayende Rahien)

unread,
Jul 5, 2012, 6:03:31 AM7/5/12
to rav...@googlegroups.com
In 1.2, you can do SelectFields<T>() and it would work.

And I won't comment on "should be faster".

Ben

unread,
Jul 5, 2012, 6:11:20 AM7/5/12
to rav...@googlegroups.com
:) okay, I realize the answer is probably "it depends".

In my case I don't think there is any difference in performance since the contents of my index and what I am projecting to are largely the same. In fact, As<T> and AsProjection<T> return exactly the same amount of data from the server.

It seems that AsProjection<T> is another way of using Select<T> to project to another type (both create Fetch commands).
Reply all
Reply to author
Forward
0 new messages