In my last blog post i explained about Geospatial Radial Search using Lucene 4.x.
In continuation with this i am going to explain how to implement GeoSpatial Bounding Box Search using Lucene 4.x.
Problem I am trying to Implement :
Finding All Places Within Given Bounding Box.
Sample Input Places Data :
id name latitude longitude
//Bangalore places
1 Bangalore 12.9558 77.620979
2 Cubbon Park 12.974045 77.591995
3 Tipu Palace 12.959365 77.573792
4 Bangalore Palace 12.998095 77.592041
5 Monkey Bar 12.97018 77.61219
//Chennai places
6 Chennai 13.060422 80.249583
7 Elliot's Beach 12.998976 80.271286
8 Kapaleeshwar Temple 13.033889 80.269722
Code :
In continuation with this i am going to explain how to implement GeoSpatial Bounding Box Search using Lucene 4.x.
Problem I am trying to Implement :
Finding All Places Within Given Bounding Box.
Sample Input Places Data :
id name latitude longitude
//Bangalore places
1 Bangalore 12.9558 77.620979
2 Cubbon Park 12.974045 77.591995
3 Tipu Palace 12.959365 77.573792
4 Bangalore Palace 12.998095 77.592041
5 Monkey Bar 12.97018 77.61219
//Chennai places
6 Chennai 13.060422 80.249583
7 Elliot's Beach 12.998976 80.271286
8 Kapaleeshwar Temple 13.033889 80.269722
Code :
import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.spatial.SpatialStrategy;
import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy;
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.query.SpatialOperation;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
import com.spatial4j.core.shape.Point;
import com.spatial4j.core.shape.Shape;
public class SpatialSearch {
private IndexWriter indexWriter;
private IndexReader indexReader;
private IndexSearcher searcher;
private SpatialContext ctx;
private SpatialStrategy strategy;
public SpatialSearch(String indexPath) {
StandardAnalyzer a = new StandardAnalyzer(Version.LUCENE_43);
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_43, a);
Directory directory;
try {
directory = new SimpleFSDirectory(new File(indexPath));
indexWriter = new IndexWriter(directory, iwc);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.ctx = SpatialContext.GEO;
SpatialPrefixTree grid = new GeohashPrefixTree(ctx, 11);
this.strategy = new RecursivePrefixTreeStrategy(grid, "location");
}
public void indexDocuments() throws IOException {
indexWriter.addDocument(newGeoDocument(1, "Bangalore", ctx.makePoint(12.9558, 77.620979)));
indexWriter.addDocument(newGeoDocument(2, "Cubbon Park", ctx.makePoint(12.974045, 77.591995)));
indexWriter.addDocument(newGeoDocument(3, "Tipu palace", ctx.makePoint(12.959365, 77.573792)));
indexWriter.addDocument(newGeoDocument(4, "Bangalore palace", ctx.makePoint(12.998095, 77.592041)));
indexWriter.addDocument(newGeoDocument(5, "Monkey Bar", ctx.makePoint(12.97018, 77.61219)));
indexWriter.addDocument(newGeoDocument(6, "Chennai", ctx.makePoint(13.060422, 80.249583)));
indexWriter.addDocument(newGeoDocument(7, "Elliot's Beach", ctx.makePoint(12.998976, 80.271286)));
indexWriter.addDocument(newGeoDocument(8, "Kapaleeshwar Temple", ctx.makePoint(13.033889, 80.269722)));
indexWriter.commit();
indexWriter.close();
}
private Document newGeoDocument(int id, String name, Shape shape) {
FieldType ft = new FieldType();
ft.setIndexed(true);
ft.setStored(true);
Document doc = new Document();
doc.add(new IntField("id", id, Store.YES));
doc.add(new Field("name", name, ft));
for(IndexableField f:strategy.createIndexableFields(shape)) {
doc.add(f);
}
doc.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
return doc;
}
public void setSearchIndexPath(String indexPath) throws IOException{
this.indexReader = DirectoryReader.open(new SimpleFSDirectory(new File(indexPath)));
this.searcher = new IndexSearcher(indexReader);
}
public void searchBBox(Double minLat, Double minLng, Double maxLat,
Double maxLng) throws IOException {
SpatialArgs args = new SpatialArgs(SpatialOperation.IsWithin,
ctx.makeRectangle(minLat, maxLat, minLng, maxLng));
Filter filter = strategy.makeFilter(args);
int limit = 10;
TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), filter,
limit);
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc s : scoreDocs) {
Document doc = searcher.doc(s.doc);
System.out.println(doc.get("id") + "\t" + doc.get("name"));
}
}
}
Output :
Places WithIn Chennai Bounding Box
6 Chennai
7 Elliot's Beach
8 Kapaleeshwar Temple
Places WithIn Bangalore Bounding Box
1 Bangalore
2 Cubbon Park
3 Tipu palace
4 Bangalore palace
5 Monkey Bar
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
String indexPath = "/home/vishnu/lucene_practices/geo_spatial_index";
SpatialSearch s = new SpatialSearch(indexPath);
//Indexes sample documents
s.indexDocuments();
s.setSearchIndexPath(indexPath);
//Get Places Within Chennai Bounding Box.
System.out.println("Places WithIn Chennai Bounding Box\n");
s.searchBBox(12.9673, 80.184631, 13.15148, 80.306709);
//Get Places Within Bangalore Bounding Box.
System.out.println("Places WithIn Bangalore Bounding Box");
s.searchBBox(12.76805, 77.465202, 13.14355, 77.776749);
}
}
Places WithIn Chennai Bounding Box
6 Chennai
7 Elliot's Beach
8 Kapaleeshwar Temple
Places WithIn Bangalore Bounding Box
1 Bangalore
2 Cubbon Park
3 Tipu palace
4 Bangalore palace
5 Monkey Bar
Hi,
ReplyDeleteSir i m very thankful to you...this is really helpful for us thanks to your details and again thanks
god bless you
Import Procedure Chennai