lucene4 spatial4j
有次在一个项目中有人提出了一种基于LBS业务的搜索的技术,lucene spatial搜索。随后在网上进行了大搜索。只搜索出一些lucene3代的小例子。现在lucene已经发到4.6了,3代明显太落后了。所以,进行lucene4 spatial的例子搜索,很不幸:使用的人太少了,没有一个例子。就连官网上也没有太多的说明。
由于没有仔细观看官网关于spatial模块的说明,未发现有用东西。一次不经意找到一行。位于API_Javadocs中spatial search的index.html上“For some sample code showing how to use the API, see SpatialExample.java in the tests.”
终于找到了入门的法宝。
SpatialExample
下面对其中使用到的核心类作下说明:
SpatialContext:空间模块上下文,们于spatial4j包中,一个全局单例对象。它是spatial4j的入口。它提供读写Shape对象的通道。
Shape:形状接口。
SpatialStrategy:lucene spatial模块提供创建查询Shape对象索途径。
package com.spatial.client; import java.io.File; import java.io.IOException; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.IntField; import org.apache.lucene.document.StoredField; import org.apache.lucene.document.TextField; 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.index.Term; import org.apache.lucene.search.Filter; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TermQuery; 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 org.apache.lucene.util.Version; import com.chenlb.mmseg4j.analysis.SimpleAnalyzer; import com.spatial4j.core.context.SpatialContext; import com.spatial4j.core.distance.DistanceUtils; import com.spatial4j.core.shape.Shape; public class LuceneSpatialExample { public static void main(String[] args) throws IOException { new LuceneSpatialExample().test(); } public void test() throws IOException { init(); createIndex(); search(); } private SpatialContext ctx;//"ctx" is the conventional variable name private SpatialStrategy strategy; private Directory directory; private String indexPath = "E:\\index\\spatial\\"; protected void init() { //Typical geospatial context // These can also be constructed from SpatialContextFactory this.ctx = SpatialContext.GEO; int maxLevels = 11;//results in sub-meter precision for geohash //TODO demo lookup by detail distance // This can also be constructed from SpatialPrefixTreeFactory SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels); this.strategy = new RecursivePrefixTreeStrategy(grid, "myGeoField"); try { this.directory = FSDirectory.open(new File(indexPath)); } catch (IOException e) { e.printStackTrace(); } } private void createIndex() throws IOException { IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_40,new SimpleAnalyzer()); IndexWriter indexWriter = new IndexWriter(directory, iwConfig); //Spatial4j is x-y order for arguments|对于参数的顺序是Longitude,Latitude indexWriter.addDocument(newSampleDocument(0, "一星大饭店",ctx.makePoint(116.430360,39.939686))); indexWriter.addDocument(newSampleDocument(1, "二星大饭店",ctx.makePoint( 116.430319,39.939702))); indexWriter.addDocument(newSampleDocument(2, "三星大饭店",ctx.makePoint(116.430459,39.939802))); indexWriter.addDocument(newSampleDocument(3, "四星大饭店", ctx.makePoint(116.430449,39.939902))); indexWriter.addDocument(newSampleDocument(4, "六星大饭店",ctx.makePoint(116.430439,39.93402))); indexWriter.addDocument(newSampleDocument(5, "七星大饭店",ctx.makePoint(116.430419,39.934102))); indexWriter.addDocument(newSampleDocument(6, "五星大饭店",ctx.makePoint(116.430429,39.934202))); indexWriter.addDocument(newSampleDocument(6, "五星大酒店",ctx.makePoint(115.430429,39.934202))); indexWriter.commit(); indexWriter.close(); } private Document newSampleDocument(int id,String keyword, Shape... shapes) { Document doc = new Document(); doc.add(new IntField("id", id, Field.Store.YES)); //Potentially more than one shape in this field is supported by some // strategies; see the javadocs of the SpatialStrategy impl to see. for (Shape shape : shapes) { for (IndexableField f : strategy.createIndexableFields(shape)) { doc.add(f); } //store it too; the format is up to you doc.add(new StoredField(strategy.getFieldName(), ctx.toString(shape))); } doc.add(new TextField("keyword",keyword, Field.Store.YES)); return doc; } private void search() throws IOException { IndexReader indexReader = DirectoryReader.open(directory); IndexSearcher indexSearcher = new IndexSearcher(indexReader); { //16米范围内 SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, ctx.makeCircle(116.430459,39.939802, DistanceUtils.dist2Degrees(0.016,DistanceUtils.EARTH_MEAN_RADIUS_KM))); Filter filter = strategy.makeFilter(args); Term term = new Term("keyword","饭店"); Query query001 = new TermQuery(term); TopDocs docs = indexSearcher.search(query001,filter,1000); System.out.println(docs.totalHits); ScoreDoc[] scoreDoc = docs.scoreDocs; if(docs.totalHits>0) for (int i = 0; i < scoreDoc.length; i++) { int doc = scoreDoc[i].doc; Document mydoc = indexReader.document(doc); System.out.println(mydoc.get("myGeoField")); String value = mydoc.get("myGeoField"); String []lonlat = value.split(" "); double eLat = Double.valueOf(lonlat[1]); double eLon = Double.valueOf(lonlat[0]); System.out.println(SpatialUtils.getDistance(39.939802, 116.430459, eLat, eLon, false)+"|keyword: "+mydoc.get("keyword")); } } indexReader.close(); } }
lucene spatial 模块本身就是一个Filter的实现。核心还是lucene的全文检索。真正理解学习新框架或新开源的东西就得从TestCase看起。
相关推荐
renjinlong 2020-09-03
Jacry 2020-07-04
IceStreamLab 2020-06-26
mengyue 2020-06-09
PasserbyX 2020-05-16
mameng 2020-05-12
心丨悦 2020-05-06
编码之路 2020-05-03
mengyue 2020-05-02
qiuzhuoxian 2020-02-23
编码之路 2020-02-20
lionelf 2020-02-03
TyCoding 2020-02-01
heniancheng 2020-01-31
某某某 2020-01-30
PinkBean 2020-01-29
某某某 2020-01-12
编码之路 2020-01-01
itmale 2020-01-01