@@ -3,8 +3,9 @@ namespace LuceneExample
#region Namespaces
using System ;
using System . Globalization ;
using Lucene . Net . Analysis ;
using Lucene . Net . Analysis . Standard ;
using Lucene . Net . Documents ;
using Lucene . Net . Index ;
using Lucene . Net . Search ;
@@ -13,64 +14,106 @@ namespace LuceneExample
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 static class Program
public class SpatialSearch
{
private static readonly SpatialContext context = new SpatialContext ( true ) ;
private readonly SpatialContext ctx ;
private readonly Directory directory ;
private static PointVectorStrategy strategy ;
private readonly PointVectorStrategy strategy ;
private static void AddPoint ( IndexWriter writer , string name , double lng , double lat )
public SpatialSearch ( )
{
Point shape = context . MakePoint ( lng , lat ) ;
var doc = new Document ( ) ;
foreach ( var fld in strategy . CreateIndexableFields ( shape ) )
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 ) )
{
doc . Add ( fld ) ;
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 ( ) ;
}
doc . Add ( new Field ( "Name" , name , Field . Store . YES , Field . Index . NOT_ANALYZED_NO_NORMS ) ) ;
writer . AddDocument ( doc ) ;
}
private static void Main ( )
private Document newGeoDocument ( int id , String name , Shape shape )
{
strategy = new PointVectorStrategy ( context , "Location" ) ;
var doc = new Document ( ) ;
using ( var dir = new RAMDirectory ( ) )
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 ) ) ;
using ( var writer = new IndexWriter ( dir , new SimpleAnalyzer ( ) , true , IndexWriter . MaxFieldLength . UNLIMITED ) )
{
AddPoint ( writer , "London" , - 81.233040 , 42.983390 ) ;
AddPoint ( writer , "East New York" , - 73.882360 , 40.666770 ) ;
AddPoint ( writer , "Manhattan" , - 73.966250 , 40.783430 ) ;
AddPoint ( writer , "New York City" , - 74.005970 , 40.714270 ) ;
AddPoint ( writer , "Oslo" , 10.746090 , 59.912730 ) ;
AddPoint ( writer , "Bergen" , 5.324150 , 60.392990 ) ;
AddPoint ( writer , "Washington, D. C." , - 77.036370 , 38.895110 ) ;
}
// Origin point - Oslo Spektrum
const double lat = 59.9138688 ;
const double lng = 10.752245399999993 ;
const double radius = 180 ;
var query = strategy . MakeQuery ( new SpatialArgs ( SpatialOperation . IsWithin , context . MakeCircle ( lng , lat , radius ) ) ) ;
using ( var searcher = new IndexSearcher ( dir ) )
{
var results = searcher . Search ( query , null , 100 ) ;
foreach ( var topDoc in results . ScoreDocs )
{
var name = searcher . Doc ( topDoc . Doc ) . Get ( "Name" ) ;
Console . WriteLine ( name ) ;
}
}
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 ( ) ;
}
}
}