Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Implementing Geospatial Bounding Box Search in Lucene 4.x

DZone's Guide to

Implementing Geospatial Bounding Box Search in Lucene 4.x

· Big Data Zone
Free Resource

Find your next Big Data job at DZone Jobs. See jobs focused on Big Data or create your profile and have the employers come to you!

In this article 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")); 
   } 
 }
  
}

 /**
  * @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);

 }

}



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


Find your next Big Data job at DZone Jobs. See jobs focused on Big Data or create your profile and have the employers come to you!

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}