Geo-Spatial API
The Distributed Lucene supports indexing the documents with the Geo-Spatial coordinates and later on querying these indexed documents for location-based searching. For this purpose, the Distributed Lucene uses the Spatial4n
library.
Prerequisites
- To learn about the standard prerequisites required to work with all NCache client-side features, please refer to the given page on Client-Side API Prerequisites.
- Make sure that you have created and started a Lucene cache through the NCache Management Center or Command Line Interface.
- Make sure that your application is not using any native Lucene DLL/Reference.
- For API details, refer to: SpatialDocument, Spatial Strategy, GeohashPrefixTree, RecursivePrefixTreeStrategy, NCacheDirectory, IndexWriterConfig, LuceneVersion, StandardAnalyzer, IndexWriter, SpatialContext, ReadShapeFromWkt, IndexSearcher, IndexReader, DirectoryReader, Class SortField, SortFieldType, SpatialArgs, SpatialOperation, DistanceUtils, MakeCircle, Dist2Degrees, MakeFilter, TopDocs, MatchAllDocsQuery, Dispose.
Spatial Document
The spatial documents are created using the SpatialDocument
class. These documents are later used for indexing purposes. This class is specific to the Distributed Lucene. The SpatialDocument
consists of the shapes of the IShape
class along with a Document
. These shapes will then transform into the indexable fields on the server-side via a Strategy
. The indexable fields will be added to the Document
via IndexWriter
.
In the following example, a method for a spatial document is created with the return type of the SpatialDocument
class, this method is then used in the next example.
public static SpatialDocument CreateSpatialDocument(int id, SpatialStrategy strategy, params IShape[] shapes)
{
Document doc = new Document();
doc.Add(new Int32Field("id", id, Field.Store.YES));
foreach (IShape shape in shapes)
{
IPoint pt = (IPoint)shape;
doc.Add(new StoredField(strategy.FieldName,
pt.X.ToString(CultureInfo.InvariantCulture) + " " +
pt.Y.ToString(CultureInfo.InvariantCulture)));
}
return new SpatialDocument()
{
Document = doc,
Shapes = shapes
};
}
Spatial API Example
The SpatialStrategy
class encapsulates an approach to indexing and searching the documents based on the shapes. The Distributed Lucene supports all the spatial strategies supported by the Lucene. The working of the spatial API is the same in both, the Distributed Lucene and the Lucene, except for the concept of a SpatialDocument
class that is present in the Distributed Lucene only.
In the following example, spatial documents are defined using the CreateSpatialDocument
method created in the earlier example and then added to the IndexWriter
with the SpatialStrategy
defined. The documents are later searched with the IndexSearcher
, and the results are verified afterward.
// Precondition: Lucene cache is already connected
string cache = "luceneCache";
string index = "normalIndex";
IndexReader indexReader = null;
IndexSearcher indexSearcher = null;
// Initialize prefix tree with depth level
var maxLevels = 11;
var grid = new GeohashPrefixTree(SpatialContext.GEO,
maxLevels);
// Define strategy
var strategy = new RecursivePrefixTreeStrategy(grid,
"myGeoField");
// Open NCache directory on index
var directory = NCacheDirectory.Open(cache, index);
// Configure and initalize index writer
var indexWriterConfig = new IndexWriterConfig
(LuceneVersion.LUCENE_48, new StandardAnalyzer
(LuceneVersion.LUCENE_48));
IndexWriter writer = new IndexWriter(directory,
indexWriterConfig);
// Add spatial documents to document with index writer
writer.AddDocument(CreateSpatialDocument(2, strategy,
SpatialContext.GEO.MakePoint(-80.93, 33.77)), strategy);
writer.AddDocument(CreateSpatialDocument(4, strategy,
SpatialContext.GEO.ReadShapeFromWkt("POINT(60.9289094
-50.7693246)")), strategy);
writer.AddDocument(CreateSpatialDocument(20,
strategy, SpatialContext.GEO.MakePoint(0.1, 0.1),
SpatialContext.GEO.MakePoint(0, 0)), strategy);
// Open index reader on directory
indexReader = DirectoryReader.Open(directory);
// Open index searcher on index reader
indexSearcher = new IndexSearcher(indexReader);
// Define sorting strategy
Sort idSort = new Sort(new SortField("id",
SortFieldType.INT32));
// Define spatial arguments
SpatialArgs args = new SpatialArgs(SpatialOperation.
Intersects, SpatialContext.GEO.MakeCircle(-80.0, 33.
0, DistanceUtils.Dist2Degrees(200, DistanceUtils.
EARTH_MEAN_RADIUS_KM)));
// Define the filter with spatial arguments
Filter filter = strategy.MakeFilter(args);
// Search top docs
TopDocs docs = indexSearcher.Search(new
MatchAllDocsQuery(), filter, 10, idSort);
if (indexSearcher != null) indexSearcher.Dispose();
if (indexReader != null) indexReader.Dispose();
Note
Not disposing of the NCacheDirectory
, IndexReader
, IndexWriter
, IndexSearcher
, and DirectoryTaxonomyReader
will lead to extra memory consumption on the server-side.
Additional Resources
NCache also provides a sample application for the Geo-Spatial API in the Distributed Lucene on GitHub
See Also
.NET: DistributedLucene.Net.Spatial namespace.