RavenDB trouble adding wherein to spatial intersect query - ravendb

I have an object Partner that looks like this:
public class Partner
{
public double Latitude { get; set; }
public double Longitude { get; set; }
public string ServiceKeyIds { get; set; }
public double WorkingRadius { get; set; }
public float Rating { get; set; }
}
I then have a projection LocalPartner that looks like this:
public class LocalPartner : Partner
{
public string WorkingRadiusShape { get; set; }
}
My index PartnersByLocation looks like this:
public class PartnersByLocation : AbstractIndexCreationTask<Partner,LocalPartner>
{
public PartnersByLocation()
{
Map = partners => from doc in partners
where doc.ServiceKeyIds != null
select new
{
doc.ServiceKeyIds,
WorkingRadiusShape = string.Format("Circle({0},{1}, d={2})", doc.Latitude, doc.Longitude, doc.WorkingRadius)
}.Boost((float)doc.Rating);
Spatial(x => x.WorkingRadiusShape, options => options.Geography.Default());
Index(x => x.ServiceKeyIds, FieldIndexing.NotAnalyzed);
}
}
I try to query the index as follows:
public LocalPartnerList GetNearbyPartners(double lat, double lng, string serviceIds, double rad = 25, int page = 0, int resultsPerPage = 10)
{
RavenQueryStatistics stats;
var point = string.Format(CultureInfo.InvariantCulture, "POINT ({0} {1})", lng, lat);
var query = session.Advanced.LuceneQuery<LocalPartner, PartnersByLocation>().Statistics(out stats).Spatial(x => x.WorkingRadiusShape, c => c.Intersects(point));
if (serviceIds != null && serviceIds.Any())
{
query = query.AndAlso().WhereIn("ServiceKeyIds", serviceIds.SafeSplit());
}
var raw = query.ToString();
query = query.Skip(page * resultsPerPage).Take(resultsPerPage);
var result = new LocalPartnerList();
result.LocalPartners = query.SelectFields<LocalPartner>().ToList();
result.Results = stats.TotalResults;
result.Page = page;
result.NumberPages = (int)Math.Ceiling((double)result.Results / (double)resultsPerPage);
result.Radius = (int)rad;
return result;
}
This query works if I call the method and serciceIds is null. It returns the expected results, but as soon as I apply the .AndAlso().WhereIn() clause the query returns an empty set.
I am certain that there are matching records. I should note that the ServiceKeyIds property of Partner holds a string of comma-separated strings, and the serviceIds passed to the method is the same, and SafeSplit() is an extension method that returns an array of strings.

Related

Take function doesn't work and cannot be sent to RavenDB for query

Query Code:
var query = session.IndexQuery<App_OrgSearch.IndexResult, App_OrgSearch>();
var organizationUnitResults = query.Statistics(out stats)
.Skip(0)
.Take(5)
.AsProjection<Org>().ToList();
public static IRavenQueryable<TResult> IndexQuery<TResult, TIndex>(this IDocumentSession session)
where TIndex : AbstractIndexCreationTask, new()
{
return session.Query<TResult, TIndex>();
}
App_OrgSearch is the index I defined as below:
public class App_OrgSearch : AbstractIndexCreationTask<Org, App_OrgSearch.IndexResult>
{
public class IndexResult
{
public string Id { get; set; }
public string BusinessName { get; set; }
public string ShortName { get; set; }
public IList<string> Names { get; set; }
public List<string> PhoneNumbers { get; set; }
public List<OrganizationUnitPhone> OrganizationUnitPhones { get; set; }
}
public App_OrganizationUnitSearch()
{
Map = docs => from doc in docs
select new
{
Id = doc.Id,
Names = new List<string>
{
doc.BusinessName,
doc.ShortName,
},
BusinessName = doc.BusinessName,
ShortName = doc.ShortName,
PhoneNumbers = doc.OrganizationUnitPhones.Where(x => x != null && x.Phone != null).Select(x => x.Phone.Number),
};
Indexes.Add(x => x.Names, FieldIndexing.Analyzed);
}
}
I have 27 records in database. I want to take 5, but after query, all 27 records are returned. Why does Take function not work?
Your sample code seems wrong.
var query = session.IndexQuery<App_OrgSearch.IndexResult, App_OrgSearch>();
var organizationUnitResults = organizationUnitsQuery.Statistics(out stats)
What is organizationUnitsQuery ? You have the query as query, but there is no IndexQuery method on the session

RavenDB - How to merge related docs of same type into an index projection

Assuming the following class:
public class Thing
{
public string Id { get; set; }
public string Title{ get; set; }
public string KeyId { get; set; }
public CultureInfo Culture { get; set; }
}
and the following result class:
public class ProjectedThing
{
public string Id { get; set; }
public string Title{ get; set; }
public string KeyId { get; set; }
public CultureInfo Culture { get; set; }
public IEnumerable<Thing> Things { get; set; }
}
How can I build an index that holds the result class?
The closest I've come is with the following index definition:
public class ProjectedThings : AbstractIndexCreationTask<Thing,ProjectedThing>
{
public ProjectedThings()
{
Map = docs => from doc in docs
select new
{
Title = doc.Title,
KeyId = doc.KeyId,
Culture = doc.Culture,
Things = new[] {
new Thing{
Id = doc.Id,
Title = doc.Title,
KeyId = doc.KeyId,
Culture = doc.Culture,
TitlePluralized = doc.TitlePluralized
}
}
};
Reduce = results => from r in results
group r by r.KeyId into g
select new
{
Title = g.FirstOrDefault(x => x.Id == x.KeyId).Title,
KeyId = g.Key,
Culture = g.FirstOrDefault(x => x.Id == x.KeyId).Culture,
Things = from thing in g.SelectMany(x => x.Things).Where(x => x.Id != x.KeyId)
select new
{
Id = thing.Id,
Title = thing.Title,
KeyId = thing.Key,
Culture = thing.Culture
}
};
}
}
That's almost doing the trick, but I can't collect the Title, KeyId, and Culture in the reduction. Only the Things property is being populated.
Look at your code:
g.FirstOrDefault(x => x.Id == x.KeyId)
I don't understand this, but this is likely to be always false.
You probably want:
g.FirstOrDefault().Title,

Can I use an index as the source of an index in RavenDB

I'm trying to define an index in RavenDb that uses the output of another index as it's input but I can't get it to work.
I have the following entities & indexes defined.
SquadIndex produces the result I expect it to do but SquadSizeIndex doesn't even seem to execute.
Have I done something wrong or is this not supported?
class Country
{
public string Id { get; private set; }
public string Name { get; set; }
}
class Player
{
public string Id { get; private set; }
public string Name { get; set; }
public string CountryId { get; set; }
}
class Reference
{
public string Id { get; set; }
public string Name { get; set; }
}
class SquadIndex : AbstractIndexCreationTask<Player, SquadIndex.Result>
{
public SquadIndex()
{
Map = players => from player in players
let country = LoadDocument<Country>(player.CountryId)
select new Result
{
Country = new Reference
{
Id = country.Id,
Name = country.Name
},
Players = new[]
{
new Reference
{
Id = player.Id,
Name = player.Name
}
}
};
Reduce = results => from result in results
group result by result.Country
into g
select new Result
{
Country = g.Key,
Players = g.SelectMany(x => x.Players)
};
}
internal class Result
{
public Reference Country { get; set; }
public IEnumerable<Reference> Players { get; set; }
}
}
class SquadSizeIndex : AbstractIndexCreationTask<SquadIndex.Result, SquadSizeIndex.Result>
{
public SquadSizeIndex()
{
Map = squads => from squad in squads
select new Result
{
Country = squad.Country,
PlayerCount = squad.Players.Count()
};
Reduce = results => from result in results
group result by result.Country
into g
select new Result
{
Country = g.Key,
PlayerCount = g.Sum(x => x.PlayerCount)
};
}
internal class Result
{
public Reference Country { get; set; }
public int PlayerCount { get; set; }
}
}
No, you can't. The output of indexes are not documents to be indexed.
You can use the scripted index results to chain indexes, but that isn't trivial.

RavenDb : Search occurrences in text is slow

I would like to find the occurrences of a word in a text.
I have a class like this
public class Page
{
public string Id { get; set; }
public string BookId { get; set; }
public string Content { get; set; }
public int PageNumber { get; set; }
}
I have my index like this :
class Pages_SearchOccurrence : AbstractIndexCreationTask<Page, Pages_SearchOccurrence.ReduceResult>
{
public class ReduceResult
{
public string PageId { get; set; }
public int Count { get; set; }
public string Word { get; set; }
public string Content { get; set; }
}
public Pages_SearchOccurrence()
{
Map = pages => from page in pages
let words = page.Content
.ToLower()
.Split(new string[] { " ", "\n", ",", ";" }, StringSplitOptions.RemoveEmptyEntries)
from w in words
select new
{
page.Content,
PageId = page.Id,
Count = 1,
Word = w
};
Reduce = results => from result in results
group result by new { PageId = result.PageId, result.Word } into g
select new
{
Content = g.First().Content,
PageId = g.Key.PageId,
Word = g.Key.Word,
Count = g.ToList().Count()
};
Index(x => x.Content, Raven.Abstractions.Indexing.FieldIndexing.Analyzed);
}
}
Finally, my query is like this :
using (var session = documentStore.OpenSession())
{
RavenQueryStatistics stats;
var occurence = session.Query<Pages_SearchOccurrence.ReduceResult, Pages_SearchOccurrence>()
.Statistics(out stats)
.Where(x => x.Word == "works")
.ToList();
}
But I realize that RavenDb is very slow (or my query is not good  )
stats.IsStale = true and raven studio take too much time and give only few results.
I have 1000 document “Pages” with a content of 1000 words per Page .
Why is my query not okay and how can I find the occurrences in a page ?
Thank you for your help!
You are doing it wrong. You should set the Content field as Analyzed and use RavenDB's Search() operator. The slowness is most likely because of the amount of un-optimized work your index code is doing.
I had found a partial result.
Perhaps I'm not clear : my goal is to find the occurrences of a word in the page.
I search the hits count of a word in the page and I would like to order by this count.
I changed my index like this :
class Pages_SearchOccurrence : AbstractIndexCreationTask<Page, Pages_SearchOccurrence.ReduceResult>{
public class ReduceResult
{
public string Content { get; set; }
public string PageId { get; set; }
public string Count { get; set; }
public string Word { get; set; }
}
public Pages_SearchOccurrence()
{
Map = pages => from page in pages
let words = page.Content.ToLower().Split(new string[] { " ", "\n", ",", ";" }, StringSplitOptions.RemoveEmptyEntries)
from w in words
select new
{
page.Content,
PageId = page.Id,
Count = 1,
Word = w
};
Index(x => x.Content, Raven.Abstractions.Indexing.FieldIndexing.Analyzed);
Index(x => x.PageId, Raven.Abstractions.Indexing.FieldIndexing.NotAnalyzed);
}
Finally, my new query looks like this :
using (var session = documentStore.OpenSession())
{
var query = session.Query<Pages_SearchOccurrence.ReduceResult, Pages_SearchOccurrence>()
.Search((x) => x.Word, "works")
.AggregateBy(x => x.PageId)
.CountOn(x => x.Count)
.ToList()
.Results
.FirstOrDefault();
var listFacetValues = query.Value.Values;
var finalResult = listFacetValues.GroupBy(x => x.Hits).OrderByDescending(x => x.Key).Take(5).ToList();
}
The finalResult gives me a group of Facetvalue which have a property Hits
( the properties Hits and Count of my FacetValue are the same here )
The Hits property gives me the result that I want but for me this code is not correct and ravendb studio doesn't like this too.
Do you have a better solution ?

Problem retrieving results from an index in an embedded RavenDB

I have an index that works great when I query it using the .Net client API with a server based RavenDb.
However, if I change the RavenDb to an embedded type then I cannot query the index directly unless I first query the document that the index uses.
For instance if I have the following document objects which reside as separate collections in the RavenDb:
private class TestParentDocument
{
public string Id { get { return GetType().Name + "/" + AggregateRootId; } }
public Guid AggregateRootId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
private class TestChildProductFlagDocument
{
public string TestParentDocumentId { get; set; }
public short ProductFlagTypeId { get; set; }
}
Then I have the following object which represents the output document that the index maps to:
private class TestJoinIndexOutput
{
public string TestParentDocumentId { get; set; }
public string Name { get; set; }
public short ProductFlagTypeId { get; set; }
}
Here is the index definition:
private class TestJoinIndex : AbstractIndexCreationTask<TestChildProductFlagDocument, TestJoinIndexOutput>
{
public TestJoinIndex()
{
Map = docs => from doc in docs
select new
{
TestParentDocumentId = doc.TestParentDocumentId,
ProductFlagTypeId = doc.ProductFlagTypeId
};
TransformResults = (database, results) =>
from result in results
let parentDoc = database.Load<TestParentDocument>(result.TestParentDocumentId)
select new
{
TestParentDocumentId = result.TestParentDocumentId,
ProductFlagTypeId = result.ProductFlagTypeId,
Name = parentDoc.Name
};
}
My code to call the index looks like so:
var theJoinIndexes = ravenSession.Query<TestJoinIndexOutput, TestJoinIndex>().ToList();
This returns almost immediately and fails unless I do the following:
var theParentDocuments = ravenSession.Query<TestParentDocument>().ToList();
var theJoinIndexes = ravenSession.Query<TestJoinIndexOutput, TestJoinIndex>().ToList();
My Ravendb embedded definition looks like so:
docStore = new EmbeddableDocumentStore
{
UseEmbeddedHttpServer = false,
RunInMemory = true
};
docStore.Configuration.Port = 7777;
docStore.Initialize();
IndexCreation.CreateIndexes(typeof(TestJoinIndex).Assembly, docstore);
You aren't waiting for indexing to complete, call WaitForNonStaleResultsAsOfNow