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

The open source HPCC Systems platform is a proven, easy to use solution for managing data at scale. Visit our Easy Guide to learn more about this completely free platform, test drive some code in the online Playground, and get started today.

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


Managing data at scale doesn’t have to be hard. Find out how the completely free, open source HPCC Systems platform makes it easier to update, easier to program, easier to integrate data, and easier to manage clusters. Download and get started today.

Topics:

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}