Last active
March 9, 2020 21:37
-
-
Save Mark-Broadhurst/8931898 to your computer and use it in GitHub Desktop.
Lucence Spatial Search 3.0.3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace LuceneExample | |
{ | |
#region Namespaces | |
using System; | |
using System.Globalization; | |
using Lucene.Net.Analysis.Standard; | |
using Lucene.Net.Documents; | |
using Lucene.Net.Index; | |
using Lucene.Net.Search; | |
using Lucene.Net.Spatial.Queries; | |
using Lucene.Net.Spatial.Vector; | |
using Lucene.Net.Store; | |
using Spatial4n.Core.Context; | |
using Spatial4n.Core.Distance; | |
using Spatial4n.Core.Shapes; | |
using Directory = Lucene.Net.Store.Directory; | |
using Version = Lucene.Net.Util.Version; | |
#endregion | |
public class SpatialSearch | |
{ | |
private readonly SpatialContext ctx; | |
private readonly Directory directory; | |
private readonly PointVectorStrategy strategy; | |
public SpatialSearch() | |
{ | |
directory = new RAMDirectory(); | |
ctx = SpatialContext.GEO; | |
strategy = new PointVectorStrategy(ctx, "location"); | |
} | |
public void indexDocuments() | |
{ | |
var a = new StandardAnalyzer(Version.LUCENE_30); | |
using (var indexWriter = new IndexWriter(directory, a, IndexWriter.MaxFieldLength.UNLIMITED)) | |
{ | |
indexWriter.AddDocument(newGeoDocument(1, "London", ctx.MakePoint(51.5286416, -0.1015987))); | |
indexWriter.AddDocument(newGeoDocument(2, "Watford", ctx.MakePoint(51.6613588, -0.4055098))); | |
indexWriter.AddDocument(newGeoDocument(3, "Birmingham", ctx.MakePoint(52.4774376, -1.8636314))); | |
indexWriter.AddDocument(newGeoDocument(4, "Edinburgh", ctx.MakePoint(55.9412034, -3.2053834))); | |
indexWriter.AddDocument(newGeoDocument(5, "Leeds", ctx.MakePoint(53.8060026, -1.5357323))); | |
indexWriter.AddDocument(newGeoDocument(6, "Norwich", ctx.MakePoint(52.640143, 1.2868495))); | |
indexWriter.AddDocument(newGeoDocument(7, "New York", ctx.MakePoint(40.7056307, -73.9780035))); | |
indexWriter.AddDocument(newGeoDocument(8, "Dubai", ctx.MakePoint(25.073858, 55.2298445))); | |
indexWriter.Commit(); | |
indexWriter.Optimize(); | |
} | |
} | |
private Document newGeoDocument(int id, String name, Shape shape) | |
{ | |
var doc = new Document(); | |
doc.Add(new Field("id", id.ToString(CultureInfo.InvariantCulture), Field.Store.YES, Field.Index.ANALYZED)); | |
doc.Add(new Field("name", name, Field.Store.YES, Field.Index.ANALYZED)); | |
foreach (AbstractField field in strategy.CreateIndexableFields(shape)) | |
{ | |
doc.Add(field); | |
} | |
doc.Add(new Field(strategy.GetFieldName(), ctx.ToString(shape), Field.Store.YES, Field.Index.NOT_ANALYZED)); | |
return doc; | |
} | |
public void search(Double lat, Double lng, int distance) | |
{ | |
var indexReader = IndexReader.Open(directory, true); | |
var searcher = new IndexSearcher(indexReader); | |
Point p = ctx.MakePoint(lat, lng); | |
var args = new SpatialArgs(SpatialOperation.Intersects, ctx.MakeCircle(lat, lng, DistanceUtils.Dist2Degrees(distance, DistanceUtils.EARTH_MEAN_RADIUS_KM))); | |
Filter filter = strategy.MakeFilter(args); | |
//ValueSource valueSource = strategy.MakeDistanceValueSource(p); | |
var field = new SortField("score", SortField.SCORE, true); | |
var sort = new Sort(field); | |
const int limit = 10; | |
Query q = strategy.MakeQueryDistanceScore(args); | |
TopDocs topDocs = searcher.Search(q, filter, limit, sort); | |
ScoreDoc[] scoreDocs = topDocs.ScoreDocs; | |
foreach (ScoreDoc s in scoreDocs) | |
{ | |
Document doc = searcher.Doc(s.Doc); | |
var docPoint = (Point)ctx.ReadShape(doc.Get(strategy.GetFieldName())); | |
double docDistDEG = ctx.GetDistCalc().Distance(args.Shape.GetCenter(), docPoint); | |
double docDistInKM = DistanceUtils.Degrees2Dist(docDistDEG, DistanceUtils.EARTH_EQUATORIAL_RADIUS_KM); | |
Console.WriteLine("{0}\t{1}\t{2} km ({3})", doc.Get("id"), doc.Get("name"), docDistInKM, s.Score); | |
} | |
} | |
public static void Main() | |
{ | |
var s = new SpatialSearch(); | |
//Indexes sample documents | |
s.indexDocuments(); | |
//Get Places Within 200 kilometers from 20 Aldermanbury Square. | |
s.search(51.516941, -0.0923343, 200); | |
Console.ReadLine(); | |
} | |
} | |
} |
I'm also interested...
Thanks for your code, very helpful. I realized that ctx.MakeCircle(lat, lng) shoud be ctx.MakeCircle(lng,lat). Thanks!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Have you been able to implement sorting by distance already? I'm interested in the implementation for sorting by distance.