package lia.tools;
/**
* Copyright Manning Publications Co.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific lan
*/
import java.io.IOException;
import java.util.Map;
import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.spatial.tier.DistanceQueryBuilder;
import org.apache.lucene.spatial.tier.DistanceFieldComparatorSource;
import org.apache.lucene.spatial.tier.projections.CartesianTierPlotter;
import org.apache.lucene.spatial.tier.projections.IProjector;
import org.apache.lucene.spatial.tier.projections.SinusoidalProjector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
// From chapter 9
public class SpatialLuceneExample {
String latField = "lat";
String lngField = "lon";
String tierPrefix = "_localTier";
private Directory directory;
private IndexWriter writer;
SpatialLuceneExample() throws IOException {
directory = new RAMDirectory();
writer = new IndexWriter(directory, new WhitespaceAnalyzer(),
MaxFieldLength.UNLIMITED);
}
private void addLocation(IndexWriter writer, String name, double lat,
double lng) throws IOException {
Document doc = new Document();
doc.add(new Field("name", name, Field.Store.YES,
Field.Index.ANALYZED));
doc.add(new Field(latField, NumericUtils.doubleToPrefixCoded(lat), // #A
Field.Store.YES, Field.Index.NOT_ANALYZED)); // #A
doc.add(new Field(lngField, NumericUtils.doubleToPrefixCoded(lng), // #A
Field.Store.YES, Field.Index.NOT_ANALYZED)); // #A
doc.add(new Field("metafile", "doc", Field.Store.YES,
Field.Index.ANALYZED));
IProjector projector = new SinusoidalProjector(); // #B
int startTier = 5; // #C
int endTier = 15; // #C
for (; startTier <= endTier; startTier++) {
CartesianTierPlotter ctp;
ctp = new CartesianTierPlotter(startTier, // #D
projector, tierPrefix); // #D
double boxId = ctp.getTierBoxId(lat, lng); // #D
System.out.println("Adding field " + ctp.getTierFieldName() + ":"
+ boxId);
doc.add(new Field(ctp.getTierFieldName(), NumericUtils // #E
.doubleToPrefixCoded(boxId), Field.Store.YES,
Field.Index.NOT_ANALYZED_NO_NORMS));
}
writer.addDocument(doc);
System.out.println("===== Added Doc to index ====");
}
/*
#A Encode lat/lng as doubles
#B Use sinusoidal projection
#C Index around 1 to 1000 miles
#D Compute bounding box ID
#E Add tier field
*/
public void findNear(String what, double latitude, double longitude,
double radius) throws CorruptIndexException, IOException {
IndexSearcher searcher = new IndexSearcher(directory);
DistanceQueryBuilder dq;
dq = new DistanceQueryBuilder(latitude, // #A
longitude, // #A
radius, // #A
latField, // #A
lngField, // #A
tierPrefix, // #A
true); // #A
Query tq;
if (what == null)
tq = new TermQuery(new Term("metafile", "doc")); // #B
else
tq = new TermQuery(new Term("name", what));
DistanceFieldComparatorSource dsort; // #C
dsort = new DistanceFieldComparatorSource( // #C
dq.getDistanceFilter()); // #C
Sort sort = new Sort(new SortField("foo", dsort)); // #C
TopDocs hits = searcher.search(tq, dq.getFilter(), 10, sort);
Map<Integer,Double> distances = // #D
dq.getDistanceFilter().getDistances(); // #D
System.out.println("Number of results: " + hits.totalHits);
System.out.println("Found:");
for (ScoreDoc sd : hits.scoreDocs) {
int docID = sd.doc;
Document d = searcher.doc(docID);
String name = d.get("name");
double rsLat = NumericUtils.prefixCodedToDouble(d.get(latField));
double rsLng = NumericUtils.prefixCodedToDouble(d.get(lngField));
Double geo_distance = distances.get(docID);
System.out.printf(name +": %.2f Miles\n", geo_distance);
System.out.println("\t\t("+ rsLat +","+ rsLng +")");
}
}
/*
#A Create distance query
#B Match all documents
#C Create distance sort
#D Get distances map
*/
public static void main(String[] args) throws IOException {
SpatialLuceneExample spatial = new SpatialLuceneExample();
spatial.addData();
spatial.findNear("Restaurant", 38.8725000, -77.3829000, 8);
}
private void addData() throws IOException {
addLocation(writer, "McCormick & Schmick's Seafood Restaurant",
38.9579000, -77.3572000);
addLocation(writer, "Jimmy's Old Town Tavern", 38.9690000, -77.3862000);
addLocation(writer, "Ned Devine's", 38.9510000, -77.4107000);
addLocation(writer, "Old Brogue Irish Pub", 38.9955000, -77.2884000);
addLocation(writer, "Alf Laylah Wa Laylah", 38.8956000, -77.4258000);
addLocation(writer, "Sully's Restaurant & Supper", 38.9003000, -77.4467000);
addLocation(writer, "TGIFriday", 38.8725000, -77.3829000);
addLocation(writer, "Potomac Swing Dance Club", 38.9027000, -77.2639000);
addLocation(writer, "White Tiger Restaurant", 38.9027000, -77.2638000);
addLocation(writer, "Jammin' Java", 38.9039000, -77.2622000);
addLocation(writer, "Potomac Swing Dance Club", 38.9027000, -77.2639000);
addLocation(writer, "WiseAcres Comedy Club", 38.9248000, -77.2344000);
addLocation(writer, "Glen Echo Spanish Ballroom", 38.9691000, -77.1400000);
addLocation(writer, "Whitlow's on Wilson", 38.8889000, -77.0926000);
addLocation(writer, "Iota Club and Cafe", 38.8890000, -77.0923000);
addLocation(writer, "Hilton Washington Embassy Row", 38.9103000,
-77.0451000);
addLocation(writer, "HorseFeathers, Bar & Grill", 39.01220000000001,
-77.3942);
writer.close();
}
}