这里 solr 这块主要说说如何实现附近功能,主要实现的方法有下面几种
1.使用LatLonType(用于平面坐标,而不是大地坐标)版本比较老 好像不怎么用了
2.SpatialRecursivePrefixTreeFieldType(缩写为RPT) 我用的就是这个 下面主要讲这个部分
3.BBoxField(用于边界索引查询) 没用这个 具体的还不太了解
因为我主要使用的是第2种方式来做的 所以主要写第2种方式RPT
首先的话需要在solr的配置文件中加上经纬度的配置 比如我的经纬度起的名称叫latitude_longitude 那么在配置中就需要加上这个的配置
<field name="latitude_longitude" type="location_rpt" indexed="true" stored="true"/>
<fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType" geo="true" distErrPct="0.025" maxDistErr="0.000009" units="degrees" />
这里的type类型为location_rpt 然后下面的class引用就是我们的第2种-——SpatialRecursivePrefixTreeFieldType
对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。
接下来经纬度的数据从数据库读取出来 会有一个精度和一个纬度的字段,而在solr当中我们需要把这2个字段组合在一起 可以使用2种表达方式 比如114.31,30.52 或者114.31 30.52 一种是使用逗号隔开,另一种是使用空格的方式隔开 这里要记住一点 精度和纬度不要弄反了 不然会报错的 我之前就是因为把这2个值组合在一起写反了 然后报的异常信息:
Can't parse point '30.570000 114.020000' because: Bad Y value 114.02 is not in boundary Rect(minX=-180.0,maxX=180.0,minY=-90.0,maxY=90.0)
报错也非常的明显 就是超出了正常范围的值。所以在这里提一个醒 注意一下就行了。
接下来看代码
Map<String, Object> params = new HashMap<String, Object>(); // 查询参数 solrServer = SolrServerClient.getInstance(ConstantUtil.getResourceString("solr_core_map2")); params.put("keyword", queryString); params.put("pageNo", pageNo); params.put("pageSize", pageSize); params.put("facet", true); // 分类统计数量 params.put("facet.mincount", 1); // 至少有一条记录的分类才返回 params.put("facet.field", new String[] {"instrSort"}); if (!StringUtil.isNull(Latitude_longitude)) { params.put("fq", "{!geofilt}");//距离过滤函数 params.put("pt", Latitude_longitude);//当前经纬度 params.put("sfield", "latitude_longitude"); //经纬度的字段 params.put("d", 30+""); //就近 30 km的所有数据 params.put("sort", "geodist() asc");//距离排序 params.put("fl","*,dist:geodist()");//返回的距离数据 } params.put("defType", "edismax"); params.put("qf", "instrName^1.5 text^1"); params.put("mm", "2<70% 4<-45% 7<-30%"); params.put("pf", "instrName^1.5"); // 高亮 params.put("hl", true); params.put("hl.fl", "instrName"); params.put("hl.simple.pre", "<em style=\"color: #e72028;font-style: normal;\">"); params.put("hl.simple.post", "</em>"); params.put("resultClass", SearchOrgnInstr.class); // 指定返回结果的类型 Map queryResult = solrServer.query(params); return queryResult;
主要是这段代码
if (!StringUtil.isNull(Latitude_longitude)) { params.put("fq", "{!geofilt}");//距离过滤函数 params.put("pt", Latitude_longitude);//当前经纬度 params.put("sfield", "latitude_longitude"); //经纬度的字段 params.put("d", 30+""); //就近 30 km的所有数据 params.put("sort", "geodist() asc");//距离排序 params.put("fl","*,dist:geodist()");//返回的距离数据 }
最后返回的应该就是你需要的数据了。数据出来了,那怎么在地图上去绘制点了。请看下一章节