Skip to content

Instantly share code, notes, and snippets.

@Mark-Broadhurst
Last active March 9, 2020 21:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save Mark-Broadhurst/8931898 to your computer and use it in GitHub Desktop.
Save Mark-Broadhurst/8931898 to your computer and use it in GitHub Desktop.
Lucence Spatial Search 3.0.3
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();
}
}
}
Copy link

ghost commented Apr 30, 2014

Have you been able to implement sorting by distance already? I'm interested in the implementation for sorting by distance.

@fmmsilva
Copy link

fmmsilva commented Jul 3, 2015

I'm also interested...

@geomcr
Copy link

geomcr commented Nov 7, 2019

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