Skip to content

Instantly share code, notes, and snippets.

@mocobeta
Last active August 29, 2015 14:07
Show Gist options
  • Save mocobeta/7bf66c343904520f0662 to your computer and use it in GitHub Desktop.
Save mocobeta/7bf66c343904520f0662 to your computer and use it in GitHub Desktop.
(Lucene) Spatial search のサンプル
package indexer;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexableField;
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.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.shape.Point;
public class SpatialIndexSample {
static Map<String, double[]> data = new HashMap<String, double[]>();
static {
data.put("東京都写真美術館", new double[]{139.713549, 35.641653});
data.put("国立西洋美術館", new double[]{139.776318, 35.715431});
data.put("東京都現代美術館", new double[]{139.808303, 35.679762});
data.put("東京国立近代美術館", new double[]{139.754704, 35.690631});
data.put("東京都庭園美術館", new double[]{139.721043, 35.635801});
data.put("東京都美術館", new double[]{139.773606, 35.717152});
data.put("上野の森美術館", new double[]{139.775612, 35.712703});
data.put("芸術大学美術館", new double[]{139.773540, 35.719622});
data.put("板橋区立美術館", new double[]{139.644651, 35.784251});
data.put("練馬区立美術館", new double[]{139.636560, 35.737093});
data.put("世田谷美術館", new double[]{139.622305, 35.631598});
data.put("山種美術館", new double[]{139.714445, 35.653333});
data.put("戸栗美術館", new double[]{139.693766, 35.661412});
data.put("bunkamura", new double[]{139.696291, 35.661136});
data.put("ワタリウム美術館", new double[]{139.713683, 35.670585});
data.put("太田記念美術館", new double[]{139.705276, 35.669407});
data.put("森美術館", new double[]{139.729526, 35.660448});
data.put("国立新美術館", new double[]{139.726750, 35.665225});
data.put("根津美術館", new double[]{139.718088, 35.662264});
data.put("サントリー美術館", new double[]{139.730589, 35.666177});
data.put("竹久夢二美術館", new double[]{139.763913, 35.714908});
data.put("弥生美術館", new double[]{139.763884, 35.714958});
data.put("礫川浮世絵美術館", new double[]{139.752347, 35.708757});
data.put("ブリヂストン美術館 ", new double[]{139.772651, 35.678805});
data.put("相田みつを美術館", new double[]{139.764297, 35.676995});
data.put("出光美術館", new double[]{139.762252, 35.676740});
data.put("東京ステーションギャラリー", new double[]{139.768371, 35.681757});
data.put("ニューオータニ美術館", new double[]{139.735518, 35.681039});
data.put("羽田空港ディスカバリーミュージアム", new double[]{139.788095, 35.552128});
data.put("龍子記念館", new double[]{139.716176, 35.582408});
}
private static String idxdir = "geoindex";
private SpatialContext ctx;
private SpatialStrategy strategy;
private int maxLevels = 11; // Geohash の精度
private Directory directory;
public static void main(String[] args) throws IOException {
SpatialIndexSample indexer = new SpatialIndexSample();
IndexWriter writer = indexer.getWriter();
indexer.doIndexPoints(writer);
writer.close();
}
public SpatialIndexSample() throws IOException {
// SpatialStrategy の初期化
// 緯度経度は Geohash を使ってエンコード
this.ctx = SpatialContext.GEO;
SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels);
this.strategy = new RecursivePrefixTreeStrategy(grid, "geofield");
this.directory = FSDirectory.open(new File(idxdir));
}
private void doIndexPoints(IndexWriter writer) throws IOException {
int id = 1;
for (Map.Entry<String, double[]> entry : data.entrySet()) {
Document doc = new Document();
doc.add(new IntField("id", id, Store.YES));
doc.add(new StringField("name", entry.getKey(), Store.YES));
// Point オブジェクトからIndexableFieldを作る
// makePoint() は引数にX座標(経度)、Y座標(緯度)をとる
Point pt = ctx.makePoint(entry.getValue()[0], entry.getValue()[1]);
for (IndexableField field : strategy.createIndexableFields(pt)) {
// フィールド追加
doc.add(field);
}
// (option) 経度、緯度は表示のためストアしておく
doc.add(new StoredField(strategy.getFieldName(), pt.getX() + "," + pt.getY()));
writer.addDocument(doc);
id++;
}
}
private IndexWriter getWriter() throws IOException {
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_0,
new WhitespaceAnalyzer());
return new IndexWriter(this.directory, config);
}
}
package spacial;
import java.io.File;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
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.store.Directory;
import org.apache.lucene.store.FSDirectory;
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
import com.spatial4j.core.shape.Point;
public class SpatialSearchSample {
private static String idxdir = "geoindex";
private static SpatialContext ctx = SpatialContext.GEO;
private static int maxLevels = 11;
public static void main(String[] args) {
try {
Directory dir = FSDirectory.open(new File(idxdir));
IndexReader r = DirectoryReader.open(dir);
IndexSearcher searcher = new IndexSearcher(r);
SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels);
SpatialStrategy strategy = new RecursivePrefixTreeStrategy(grid, "geofield");
// 品川駅(139.740419, 35.630418)から近い順に5件を検索
Point pt = ctx.makePoint(139.740419, 35.630418);
ValueSource source = strategy.makeDistanceValueSource(pt, DistanceUtils.DEG_TO_KM);
Sort sort = new Sort(source.getSortField(false).rewrite(searcher));
TopDocs hits = searcher.search(new MatchAllDocsQuery(), 5, sort);
for (int i = 0; i < hits.scoreDocs.length; i++) {
int docid = hits.scoreDocs[i].doc;
Document doc = searcher.doc(docid);
System.out.println(doc.get("name") + " (" + doc.get(strategy.getFieldName()) + ")");
}
dir.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package spacial;
import java.io.File;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
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.FSDirectory;
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
public class SpatialSearchSample2 {
private static String idxdir = "geoindex";
private static SpatialContext ctx = SpatialContext.GEO;
private static int maxLevels = 11;
public static void main(String[] args) {
try {
Directory dir = FSDirectory.open(new File(idxdir));
IndexReader r = DirectoryReader.open(dir);
IndexSearcher searcher = new IndexSearcher(r);
SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels);
SpatialStrategy strategy = new RecursivePrefixTreeStrategy(grid, "geofield");
// 品川駅(139.740419, 35.630418)から半径5km圏内でフィルタする
SpatialArgs sargs = new SpatialArgs(SpatialOperation.Intersects,
ctx.makeCircle(139.740419, 35.630418,
DistanceUtils.dist2Degrees(5, DistanceUtils.EARTH_MEAN_RADIUS_KM)));
Filter filter = strategy.makeFilter(sargs);
TopDocs hits = searcher.search(new MatchAllDocsQuery(), filter, 100);
// 座標 (139.5, 35.5) を左上, 座標 (139.7, 35.8) を右下とする長方形の範囲でフィルタする
/*
SpatialArgs sargs = new SpatialArgs(SpatialOperation.Intersects,
ctx.makeRectangle(139.5, 139.7, 35.5, 35.8));
Filter filter = strategy.makeFilter(sargs);
TopDocs hits = searcher.search(new MatchAllDocsQuery(), filter, 100);
*/
for (int i = 0; i < hits.scoreDocs.length; i++) {
int docid = hits.scoreDocs[i].doc;
Document doc = searcher.doc(docid);
System.out.println(doc.get("name") + " (" + doc.get(strategy.getFieldName()) + ")");
}
dir.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment