基于Solr的空间搜索 - 阿凡卢 - 博客园

Solr已经提供了3种filedType来进行空间搜索:

1)  LatLonType(用于平面坐标,而不是大地坐标)

2)  SpatialRecursivePrefixTreeFieldType(缩写为RPT)

3)  BBoxField(用于边界索引查询)

本文重点介绍使用SpatialRecursivePrefixTreeFieldType,不仅可以用点,也可以用于多边形的查询。

1、配置Solr

首先看下数据:

基于Solr的空间搜索 - 阿凡卢 - 博客园_第1张图片

Solr的schema.xml配置:

<field name="station_id" type="long" indexed="true" stored="true" required="true" multiValued="false" />
<field name="station_address" type="text_general" indexed="true" stored="true"/>
<field name="station_position" type="location_rpt" indexed="true" stored="true"/>

<uniqueKey>station_id</uniqueKey>

这里重点是station_position,它的type是location_rpt,它在Solr中的定义如下:

复制代码
<!-- A specialized field for geospatial search. If indexed, this fieldType must not be multivalued. -->
<fieldType name="location" class="solr.LatLonType" subFieldSuffix="_coordinate"/>

<!-- An alternative geospatial field type new to Solr 4.  It supports multiValued and polygon shapes.       For more information about this and other Spatial fields new to Solr 4, see:       http://wiki.apache.org/solr/SolrAdaptersForLuceneSpatial4     -->
<fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType" geo="true" distErrPct="0.025" maxDistErr="0.000009" units="degrees" />

<!-- Spatial rectangle (bounding box) field. It supports most spatial predicates, and has      special relevancy modes: score=overlapRatio|area|area2D (local-param to the query).  DocValues is required for      relevancy. -->
<fieldType name="bbox" class="solr.BBoxField"         geo="true" units="degrees" numberType="_bbox_coord" />
<fieldType name="_bbox_coord" class="solr.TrieDoubleField" precisionStep="8" docValues="true" stored="false"/>
复制代码

对solr.SpatialRecursivePrefixTreeFieldType的配置说明:

SpatialRecursivePrefixTreeFieldType

用于深度遍历前缀树的FieldType,主要用于获得基于Lucene中的RecursivePrefixTreeStrategy。

geo

默认为true,值为true的情况下坐标基于球面坐标系,采用Geohash的方式;值为false的情况下坐标基于2D平面的坐标系,采用Euclidean/Cartesian的方式。

distErrPct

定义非Point图形的精度,范围在0-0.5之间。该值决定了非Point的图形索引或查询时的level(如geohash模式时就是geohash编码的长度)。当为0时取maxLevels,即精度最大,精度越大将花费更多的空间和时间去建索引。

maxDistErr/maxLevels:maxDistErr

定义了索引数据的最高层maxLevels,上述定义为0.000009,根据GeohashUtils.lookupHashLenForWidthHeight(0.000009, 0.000009)算出编码长度为11位,精度在1米左右,直接决定了Point索引的term数。maxLevels优先级高于maxDistErr,即有maxLevels的话maxDistErr失效。详见SpatialPrefixTreeFactory.init()方法。不过一般使用maxDistErr。

units

单位是degrees。

worldBounds
世界坐标值:”minX minY maxX maxY”。 geo=true即geohash模式时,该值默认为”-180 -90 180 90”。geo=false即quad时,该值为Java double类型的正负边界,此时需要指定该值,设置成”-180 -90 180 90”。

2、建立索引

这里使用Solrj来建立索引:

复制代码
    //Index some base station data for test
    public void IndexBaseStation(){         BaseStationDb baseStationDb = new BaseStationDb();         List<BaseStation> stations = baseStationDb.getAllBaseStations();         Collection<SolrInputDocument> docList = new ArrayList<SolrInputDocument>();         for (BaseStation baseStation : stations) {             //添加基站数据到Solr索引中
            SolrInputDocument doc = new SolrInputDocument();               doc.addField("station_id", baseStation.getBaseStationId());               doc.addField("station_address", baseStation.getAddress());             String posString = baseStation.getLongitude()+" "+baseStation.getLatitude() ;             doc.addField("station_position", posString);             docList.add(doc);         }         try {             server.add(docList);             server.commit();         } catch (SolrServerException e) {             e.printStackTrace();         } catch (IOException e) {             e.printStackTrace();         }                  System.out.println("Index base station data done!");     }
复制代码

这里使用“经度 纬度”这样的字符串格式将经纬度索引到station_position字段中。

3、查询

查询语法示例:

q={!geofilt pt=45.15,-93.85 sfield=poi_location_p d=5 score=distance}

q={!bbox pt=45.15,-93.85 sfield=poi_location_p d=5 score=distance}

q=poi_location_p:"Intersects(-74.093 41.042 -69.347 44.558)" //a bounding box (not in WKT)

q=poi_location_p:"Intersects(POLYGON((-10 30, -40 40, -10 -20, 40 20, 0 0, -10 30)))" //a WKT example

涉及到的字段说明:

字段

含义

q

查询条件,如 q=poi_id:134567

fq

过滤条件,如 fq=store_name:农业

fl

返回字段,如fl=poi_id,store_name

pt

坐标点,如pt=54.729696,-98.525391

d

搜索半径,如 d=10表示10km范围内

sfield

指定坐标索引字段,如sfield=geo

defType

指定查询类型可以取 dismax和edismax,edismax支持boost函数相乘作用,dismax是通过累加方式计算最后的score.

qf

指定权重字段:qf=store_name^10+poi_location_p^5

score

排序字段根据qf定义的字段defType定义的方式计算得到score排序输出

其中有几种常见的Solr支持的几何操作:
WITHIN:在内部
CONTAINS:包含关系
DISJOINT:不相交
Intersects:相交(存在交集)

1)点查询

测试代码:查询距离某个点pt距离为d的集合

复制代码
SolrQuery params = new SolrQuery();    params.set("q", "*:*");     params.set("fq", "{!geofilt}");           //距离过滤函数
params.set("pt", "118.227985 39.410722"); //当前经纬度
params.set("sfield", "station_position"); //经纬度的字段
params.set("d", "50"); //就近 d km的所有数据 //params.set("score", "kilometers"); 
params.set("sort", "geodist() asc");  //根据距离排序:由近到远
params.set("start", "0");  //记录开始位置
params.set("rows", "100");  //查询的行数
params.set("fl", "*,_dist_:geodist(),score");//查询的结果中添加距离和score
复制代码

阅读全文……

你可能感兴趣的:(java,Lucene,search)