Permalink
Browse files

Merge branch 'spatial'

  • Loading branch information...
2 parents f4939ff + baa55d4 commit 6ca2ecd68bd4702261bb7d02f0f3b060962bfac8 @synhershko synhershko committed May 21, 2012
@@ -7,6 +7,8 @@ public static class Constants
public const string LastModified = "Last-Modified";
public const string DefaultDatabase = "<default>";
public const string TemporaryScoreValue = "Temp-Index-Score";
+ public const string SpatialFieldName = "__spatial";
+ public const string SpatialShapeFieldName = "__spatialShape";
public const string DistanceFieldName = "__distance";
public const string RandomFieldName = "__random";
public const string NullValueNotAnalyzed = "[[NULL_VALUE]]";
@@ -26,7 +26,7 @@ public class SpatialIndexQuery : IndexQuery
/// <summary>
/// Gets or sets the radius.
/// </summary>
- /// <value>The radius.</value>
+ /// <value>The radius, in miles.</value>
public double Radius { get; set; }
/// <summary>
@@ -4,18 +4,14 @@
// </copyright>
//-----------------------------------------------------------------------
using System;
-using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Search;
-using Lucene.Net.Util;
using Raven.Abstractions.Data;
using Raven.Abstractions.Indexing;
-using Raven.Database.Data;
-using Raven.Database.Indexing;
using Raven.Database.Indexing.Sorting;
using Constants = Raven.Abstractions.Data.Constants;
@@ -41,25 +37,6 @@ public static Analyzer CreateAnalyzerInstance(string name, string analyzerTypeAs
}
}
- public static Filter GetFilter(this IndexQuery self)
- {
- var spatialIndexQuery = self as SpatialIndexQuery;
- if(spatialIndexQuery != null)
- {
- var dq = new Lucene.Net.Spatial.Tier.DistanceQueryBuilder(
- spatialIndexQuery.Latitude,
- spatialIndexQuery.Longitude,
- spatialIndexQuery.Radius,
- SpatialIndex.LatField,
- SpatialIndex.LngField,
- Lucene.Net.Spatial.Tier.Projectors.CartesianTierPlotter.DefaltFieldPrefix,
- true);
-
- return dq.Filter;
- }
- return null;
- }
-
public static Field.Index GetIndex(this IndexDefinition self, string name, Field.Index defaultIndex)
{
if (self.Indexes == null)
@@ -107,11 +84,13 @@ public static Field.Store GetStorage(this IndexDefinition self, string name, Fie
}
}
- public static Sort GetSort(this IndexQuery self, Filter filter, IndexDefinition indexDefinition)
+ public static Sort GetSort(this IndexQuery self, IndexDefinition indexDefinition)
{
if (self.SortedFields == null || self.SortedFields.Length <= 0)
return null;
- var isSpatialIndexQuery = self is SpatialIndexQuery;
+
+ var spatialQuery = self as SpatialIndexQuery;
+
return new Sort(self.SortedFields
.Select(sortedField =>
{
@@ -122,9 +101,9 @@ public static Sort GetSort(this IndexQuery self, Filter filter, IndexDefinition
return new RandomSortField(Guid.NewGuid().ToString());
return new RandomSortField(parts[1]);
}
- if (isSpatialIndexQuery && sortedField.Field == Constants.DistanceFieldName)
+ if (spatialQuery != null && sortedField.Field == Constants.DistanceFieldName)
{
- var dsort = new Lucene.Net.Spatial.Tier.DistanceFieldComparatorSource((Lucene.Net.Spatial.Tier.DistanceFilter)filter);
+ var dsort = new SpatialDistanceFieldComparatorSource(spatialQuery.Latitude, spatialQuery.Longitude);
return new SortField(Constants.DistanceFieldName, dsort, sortedField.Descending);
}
var sortOptions = GetSortOption(indexDefinition, sortedField.Field);
@@ -28,6 +28,7 @@
using Raven.Database.Plugins;
using Raven.Database.Storage;
using Raven.Json.Linq;
+using Spatial4n.Core.Query;
using Version = Lucene.Net.Util.Version;
namespace Raven.Database.Indexing
@@ -723,11 +724,10 @@ public IEnumerable<IndexQueryResult> IntersectionQuery()
intersectionCollector = new IntersectionCollector(indexSearcher, search.ScoreDocs);
}
- Filter filter = indexQuery.GetFilter();
for (int i = 1; i < subQueries.Length; i++)
{
var luceneSubQuery = ApplyIndexTriggers(GetLuceneQuery(subQueries[i]));
- indexSearcher.Search(luceneSubQuery, filter, intersectionCollector);
+ indexSearcher.Search(luceneSubQuery, null, intersectionCollector);
}
var currentIntersectResults = intersectionCollector.DocumentsIdsForCount(subQueries.Length).ToList();
@@ -838,9 +838,21 @@ private void AssertQueryDoesNotContainFieldsThatAreNotIndexes()
public Query GetLuceneQuery()
{
- return GetLuceneQuery(indexQuery.Query);
+ var q = GetLuceneQuery(indexQuery.Query);
+ var spatialIndexQuery = indexQuery as SpatialIndexQuery;
+ if (spatialIndexQuery != null)
+ {
+ var dq = SpatialIndex.MakeQuery(spatialIndexQuery.Latitude, spatialIndexQuery.Longitude, spatialIndexQuery.Radius);
+ if (q is MatchAllDocsQuery) return dq;
+
+ var bq = new BooleanQuery();
+ bq.Add(q, BooleanClause.Occur.MUST);
+ bq.Add(dq, BooleanClause.Occur.MUST);
+ return bq;
+ }
+ return q;
}
-
+
private Query GetLuceneQuery(string query)
{
Query luceneQuery;
@@ -890,23 +902,23 @@ private static void DisposeAnalyzerAndFriends(List<Action> toDispose, PerFieldAn
private TopDocs ExecuteQuery(IndexSearcher indexSearcher, Query luceneQuery, int start, int pageSize,
IndexQuery indexQuery)
{
- Filter filter = indexQuery.GetFilter();
- Sort sort = indexQuery.GetSort(filter, parent.indexDefinition);
+ var sort = indexQuery.GetSort(parent.indexDefinition);
if (pageSize == Int32.MaxValue) // we want all docs
{
var gatherAllCollector = new GatherAllCollector();
- indexSearcher.Search(luceneQuery, filter, gatherAllCollector);
+ indexSearcher.Search(luceneQuery, gatherAllCollector);
return gatherAllCollector.ToTopDocs();
}
var minPageSize = Math.Max(pageSize + start, 1);
// NOTE: We get Start + Pagesize results back so we have something to page on
if (sort != null)
{
- return indexSearcher.Search(luceneQuery, filter, minPageSize, sort);
+ var ret = indexSearcher.Search(luceneQuery, null, minPageSize, sort);
+ return ret;
}
- return indexSearcher.Search(luceneQuery, filter, minPageSize);
+ return indexSearcher.Search(luceneQuery, null, minPageSize);
}
}
@@ -0,0 +1,158 @@
+using System;
+using System.Diagnostics;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Raven.Abstractions.Data;
+using Spatial4n.Core.Exceptions;
+using Spatial4n.Core.Shapes;
+
+namespace Raven.Database.Indexing.Sorting
+{
+ public class SpatialDistanceSortField : SortField
+ {
+ private readonly double lng, lat;
+
+ public SpatialDistanceSortField(string field, bool reverse, SpatialIndexQuery qry) : base(field, CUSTOM, reverse)
+ {
+ lat = qry.Latitude;
+ lng = qry.Longitude;
+ }
+
+ public override FieldComparator GetComparator(int numHits, int sortPos)
+ {
+ return new SpatialDistanceFieldComparatorSource.SpatialDistanceFieldComparator(lat, lng, numHits);
+ }
+
+ public override FieldComparatorSource GetComparatorSource()
+ {
+ return new SpatialDistanceFieldComparatorSource(lat, lng);
+ }
+ }
+
+ public class SpatialDistanceFieldComparatorSource : FieldComparatorSource
+ {
+ protected readonly double lng, lat;
+
+ public SpatialDistanceFieldComparatorSource(double lat, double lng)
+ {
+ this.lat = lat;
+ this.lng = lng;
+ }
+
+ public override FieldComparator NewComparator(string fieldname, int numHits, int sortPos, bool reversed)
+ {
+ return new SpatialDistanceFieldComparator(lat, lng, numHits);
+ }
+
+ public class SpatialDistanceFieldComparator : FieldComparator
+ {
+ private readonly double[] values;
+ private double[] currentReaderValues;
+ private double bottom;
+ private readonly Point originPt;
+
+ public SpatialDistanceFieldComparator(double lat, double lng, int numHits)
+ {
+ values = new double[numHits];
+ originPt = SpatialIndex.RavenSpatialContext.MakePoint(lng, lat);
+ }
+
+ public override int Compare(int slot1, int slot2)
+ {
+ double a = values[slot1];
+ double b = values[slot2];
+ if (a > b)
+ return 1;
+ if (a < b)
+ return -1;
+
+ return 0;
+ }
+
+ public override void SetBottom(int slot)
+ {
+ bottom = values[slot];
+ }
+
+ public override int CompareBottom(int doc)
+ {
+ var v2 = currentReaderValues[doc];
+ if (bottom > v2)
+ {
+ return 1;
+ }
+
+ if (bottom < v2)
+ {
+ return -1;
+ }
+
+ return 0;
+ }
+
+ public override void Copy(int slot, int doc)
+ {
+ values[slot] = currentReaderValues[doc];
+ }
+
+ public override void SetNextReader(IndexReader reader, int docBase)
+ {
+ currentReaderValues = ComputeDistances(reader);
+ }
+
+ public override IComparable Value(int slot)
+ {
+ return values[slot];
+ }
+
+ protected internal double[] ComputeDistances(IndexReader reader)
+ {
+ double[] retArray = null;
+ var termDocs = reader.TermDocs();
+ var termEnum = reader.Terms(new Term(Constants.SpatialShapeFieldName));
+ try
+ {
+ do
+ {
+ Term term = termEnum.Term();
+ if (term == null)
+ break;
+
+ Debug.Assert(Constants.SpatialShapeFieldName.Equals(term.Field()));
+
+ Shape termval;
+ try
+ {
+ termval = SpatialIndex.RavenSpatialContext.ReadShape(term.Text()); // read shape
+ }
+ catch (InvalidShapeException)
+ {
+ continue;
+ }
+
+ var pt = termval as Point;
+ if (pt == null)
+ continue;
+
+ var distance = SpatialIndex.RavenSpatialContext.GetDistCalc().Distance(pt, originPt);
+
+ if (retArray == null)
+ // late init
+ retArray = new double[reader.MaxDoc()];
+ termDocs.Seek(termEnum);
+ while (termDocs.Next())
+ {
+ retArray[termDocs.Doc()] = distance;
+ }
+ } while (termEnum.Next());
+ }
+ finally
+ {
+ termDocs.Close();
+ termEnum.Close();
+ }
+ return retArray ?? new double[reader.MaxDoc()];
+ }
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit 6ca2ecd

Please sign in to comment.