Solr 地理空间搜索实践(Spatial Search)

来源:互联网 发布:java trace 编辑:程序博客网 时间:2024/06/04 18:26

        在移动开发中越来越多的App都有周边搜索,有找附近的人的,附近的酒店,附近的餐馆的。。越来越多的人和企业都使用位置感知的搜索服务。创建位置感知搜索服务通常属于昂贵的专用解决方案的一部分,并且一般由地理空间专家完成。。本文实现了搜索服务器solr的地理感知这批数据。

         构建一个常见的业务场景:

         搜索周边5KM以内的宾馆,且按照距离排序。


        利用Solr来实现空间搜索,我总结了3种方式

        本人使用为版本为solr4.10。采用solr自带的   空间查询类型,配置schema.xml 

<fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType" geo="true" distErrPct="0.025" maxDistErr="0.000009" units="degrees" />
<field name="job_coordinate" type="location_rpt" indexed="true" stored="true" omitNorms="true"  multiValued="false" required="false" />

/** * 空间搜索 */if(!isEmpty(map, "longitude")&&!isEmpty(map, "latitude")){//--由于 于空格形式,所以必须设置到queryBean中,让pt 为主查询,让之后所有空间搜索字段 为过滤查询//注:pt 不影响查询String job_coordinate=map.get("longitude").toString().trim()+" "+map.get("latitude").toString().trim();queryBean.setParam("pt", job_coordinate);//当前经纬度 //默认为100公里以内if(isEmpty(map, "distance")){map.put("distance", "100"); }query+=" {!geofilt score=distance sfield=job_coordinate d="+map.get("distance")+"} ";//加入 过滤器}

相关测试代码:

  public static void queryTest(String solrServer)throws Exception {          HttpSolrServer server = IndexerUtil.getHttpSolrServer(solrServer);         SolrQuery params=new SolrQuery();         params.setParam("q", "*:*");  //        params.put("fq", "{!geofilt}");//距离过滤函数         params.setParam("pt", "116.425397 40.037791");//当前经纬度 //        params.put("sfield", "job_coordinate");//经纬度的字段 //        params.put("d", "100");//就近2公里的所有酒店  //        params.setParam("fq", "{!geofilt score=distance sfield=job_coordinate d=5}");//        params.setParam("sort", "score desc");//根据距离排序         params.setParam("start", "0");//记录开始位置          params.setParam("rows", "10");//查询的行数          String query=" {!geofilt score=distance sfield=job_coordinate  d=5 }  ";        params.addFilterQuery(query);                QueryResponse resp = server.query(params);          SolrDocumentList docs = resp.getResults();          for(int i=0;i<docs.size();i++){          SolrDocument sid=docs.get(i);            System.out.println(sid);          }      } 


排序规则:

1) 按距离排序,距离越近排名越高,加上score=distance,其中distance是索引点到坐标点之间的弧度值,系统根据弧度值排序。

&fl=*,score&sort=score asc&q={!geofilt score=distance sfield=poi_location_p pt=54.729696,-98.525391 d=10}。

2) 按距离排序,距离越远排名越高,加上score=reciDistance,其中reciDistance 范围是0~1 采用倒数的方式计算,故与distance的排序刚好相反

&fl=*,score&sort=score asc&q={!geofilt score=reciDistance sfield=poi_location_p pt=54.729696,-98.525391 d=10} 

3) 距离仅作排序不做过滤,在条件中设置filter=false,其中d只是确定形状的作用,不起限制作用。

&fl=*,score&sort=score asc&q={!geofilt score=distance filter=false sfield=poi_location_p pt=54.729696,-98.525391 d=10}

4) 结合关键词查询和距离排序,此时关键字只能作为过滤条件(fq)不能作为查询条件,仅作为过滤域。

&fl=*,score& fq=store_name:农业&sort=score asc&q={!geofilt score=distance sfield=poi_location_p pt=54.729696,-98.525391 d=10}

5) 当关键字和距离都作为排序条件时,可以用qf参数设置权重

&fl=*,score& fq=store_name:农业&sort=score asc&q={!geofilt score=distance sfield=poi_location_p pt=54.729696,-98.525391

方式二:引入spatial4j/jts实现的:

   SpatialContext: 用于获得距离计算Calculator以及解析形状等。其属于spatial4j包中,该包中还有各种Shape及判断各Shape间的

交情况。JtsSpatialContext(jts包)用于处理多边形等情况。

  引入该包的spatialContextFactory, spatialContextFactory="com.spatial4j.core.context.jts.JtsSpatialContextFactory"

   <fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType" spatialContextFactory="com.spatial4j.core.context.jts.JtsSpatialContextFactory" distErrPct="0.025" maxDistErr="0.000009" units="degrees"/>

方式三:采用LatLonType去计算  注意必须指定动态字段,subFieldSuffix=“_coordinate”,这一个会默认去检索这样结尾的字段。

<fieldType name="location" class="solr.LatLonType" subFieldSuffix="_coordinate"/><dynamicField name="*_coordinate" type="double" indexed="true" stored="true"/><!--  默认subFieldSuffix="_coordinate"  必须要指定该坐标类型的动态字段 --><field name="job_coordinate" type="location" indexed="true" stored="true"  />

注意:这3种搜索方式 ,都必须把空间函数写在q中,才能返回计算的距离score和排序。  

个人另外用了一种取巧的方式把搜索词keyword放在 q中。把空间计算放在 fq过滤查询中。query.setParam("fq", "{!geofilt

 score=distance sfield=job_coordinate d=5}");最后用geodist方法计算空间距离,最后安装距离值作排序。。感觉很nice。

2 0
原创粉丝点击