Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly build a RavenDB spatial index, while also checking if any List<objects> match?

Tags:

c#

linq

ravendb

Following the example on the RevenDB site, I came up with this:

public class Place_ByLocationsAndCategoryId : AbstractIndexCreationTask<Place> {
    public Place_ByLocationsAndCategoryId() {
        Map = places => from p in places
                                select new { p.Categories, _ = Raven.Database.Indexing.SpatialIndex.Generate(p.Location.Lat, p.Location.Lng) };
    }
}

Places look something like this:

Place {
    string Id;
    List<Category> Categories;
    ...
}

Categories look something like this:

Category {
    string Id;
    string Name;
    ...
}

How can I build my index so that I may query by places within a given radius of a lat/lng, and contains a given category?

I attempted to query the index above like so:

 var placesFromDb = RavenSession.Advanced.LuceneQuery<Place>("Place/ByLocationsAndCategoryId").WhereIn("Id", new []{cat.Id}).WithinRadiusOf(radius: 5, latitude: Lat, longitude: Lng).ToList<Place>();

The query processes, but returns no results (when I know there are results to be returned. My error is probably in the .WhereIn() statement, but when I tried to use .Where(x => x.Categories.Any(c => c.Id == id)) I got a build error stating it was obsolete.


--Update--

I switched my index to this (as Ayende recommended)

public Place_ByLocationsAndCategoryId() {
    Map = places => from p in places
                    select new { Categories_Id = p.Categories.Select(x => x.Id), _ = Raven.Database.Indexing.SpatialIndex.Generate(p.Location.Lat, p.Location.Lng) };
}

I create the index on the document store like so:

IndexCreation.CreateIndexes(typeof(Place_ByLocationsAndCategoryId).Assembly, Store);

I query it like so:

var placesFromDb = RavenSession.Advanced.LuceneQuery<Place>("Place/ByLocationsAndCategoryId").WhereEquals("Categories_Id ", cat.Id).WithinRadiusOf(radius: 15, latitude: Lat, longitude: Lng).ToList<Place>();

This is what the index looks like on RavenDB itself:

docs.Places
    .Select(p => new {Categories_Id = p.Categories
    .Select(x => x.Id), _ = SpatialIndex.Generate(((System.Double)(p.Location.Lat)), ((System.Double)(p.Location.Lng)))})

The query seems to run, but returns 0 results (I know there are places to be found). One thing I noticed is that the Lat and Lng data types in my model are floats, while it appears the index is set to Double.

Trying to cast the coordinates in the index like so, also does not work:

public Place_ByLocationsAndCategoryId() {
    Map = places => from p in places
                    select new { Categories_Id = p.Categories.Select(x => x.Id), _ = Raven.Database.Indexing.SpatialIndex.Generate((float)p.Location.Lat, (float)p.Location.Lng) };
}

So I switched my model to use doubles; still returns 0 results.


--Update 2--

If I remove the category part of the index, and query just the spatial part, it returns places. It appears the category part isn't functioning as planned.

In case it helps, here's how partially how a stored document looks (JSON view):

{
  "Id": "4dca6d56d22da18f4e626f54",
  "Name": "焼肉",
  "Categories": [
    {
      "PlaceCategories": null,
      "Name": "Korean Restaurant",
      "Icon": "korean.png",
      "Id": "4bf58dd8d48988d113941735",
      "IsPrimary": true
    }
  ],
  "Location": {
    "Lat": "35.6709824",
    "Lng": "139.374588"
  },
  ...
}

(note: Categories is the List, categories can have subcategories, in their own List property named PlaceCategories)


--Update 3--

Here's the index error from the management studio:

Places/ByLocationsAndCategoryId 
Cannot convert type 'string' to 'float' 
6/27/2012 
places/1025
... and repeats 50 times

I have already changed my model from float to double, because it looked like the spatial generator wanted doubles. Good chance that there are some errors in the log (can't see past 50), stating `Cannot convert type 'string' to 'float'

I'm curious, in my model previously, my Lat/Lng were floats. Where is the string coming from?

like image 806
Chaddeus Avatar asked Jun 26 '12 14:06

Chaddeus


1 Answers

You want it like this:

Index:

public class Place_ByLocationsAndCategoryId : AbstractIndexCreationTask<Place> {
    public Place_ByLocationsAndCategoryId() {
        Map = places => from p in places
                                select new { Categories_Id =  p.Categories.Select(x=>x.Id), _ = Raven.Database.Indexing.SpatialIndex.Generate(p.Location.Lat, p.Location.Lng) };
    }
}

Query:

 var placesFromDb = RavenSession.Advanced.LuceneQuery<Place>("Place/ByLocationsAndCategoryId").WhereEquals("Categories_Id ", cat.Id).WithinRadiusOf(radius: 5, latitude: Lat, longitude: Lng).ToList<Place>();
like image 92
Ayende Rahien Avatar answered Oct 21 '22 11:10

Ayende Rahien