说明:
solr4之后支持空间搜索。
它底层使用的时Bkd树,标准的临近搜索算法。
本文是教你怎么使用,其他不多赘述,只说如何做到以下两点:
1.距离45,94经纬度300km内的所有点,按升序排列,可分页。
2.距离45,94最近的点,按升序排列,可分页,并返回距离。
你需要先做一番工作:
配置:
我们新建一个名字叫geo的core,打开它的配置文件managed-schema,里面有这样一个叫做location的fieldType
<fieldType name="location" class="solr.LatLonPointSpatialField" docValues="true"/>
接下来我们新建一个field,引入该fieldType.
<field name="loc" type="location" indexed="true"/>
你需要注意的是以下两点:
1.这个location实际上就是解析经纬度的。只要有field使用type=location,就意味着该field的值是“lat,lon”,即“纬度,经度”,比如“43.333,26.1122”;
2.loc我添加了indexed=true,该作用是将经纬度放到BKD树里,如果不使用indexed而是启用docValues=true时,纬度和经度对被比特交织成64位并放入Lucene DocValues,docValues数据的准确性约为1厘米。我还不能理解什么是比特交织,你也可能不会用到这段话,了解即可。
往里面添加数据:
此时因为geo——core里面有必填的id,以及我们设定的loc.
我用java添加数据的,添加了9999条数据:
添加的格式伪代码如下:
Random r = new Random();//随机数
for(i<<<10000){
"id" = i+"_solr";
//纬度范围是-90~90,经度范围-180~180
"loc" = (r.nextInt(180)-90)+","+(r.nextInt(360)-180));
}
添加后的数据大约长这样:

准备工作做完了,开始搜索:
1.距离45,94经纬度300km内的所有点,按升序排列,可分页。
q=*:*&fq={!geofilt}&sfield=loc&pt=45,94&d=300&sort=geodist() asc&start=0&rows=5
红字是可以替换的,蓝字是分页.
此时结果就已经排序了.
例如:
http://localhost:8983/solr/geo/select?q=*:*&fq={!geofilt}&sfield=loc&pt=45,94&d=1000&sort=geodist()%20asc&start=1&rows=5
%20是空格的URL编码
结果:

2.距离45,94最近的点,按升序排列,可分页,并返回距离。
&q={!func}geodist()&sfield=loc&pt=45,94&sort=score+asc&fl=*,score
直接上结果:

可以看到效率很高的.
这两个功能一般都足够使用了.教程至此结束.
2019.4.18
有同学更复杂的不好写,java代码粘出来,大致如下:
/**
* 搜索最近距离的商品,附带条件商品标题关键字和类型 条件
* @param keyword 商品标题关键字
* @param type 类型
* @param pt 坐标点
* @param page 分页
* @param rows 分页
* @return
*/
public SolrDocumentList queryDonations(String keyword, Integer type,String pt, int page, int rows){
/**
* 创建query对象
*/
SolrQuery query = new SolrQuery();
query.setQuery("{!func}geodist()");
query.setSort("score ", SolrQuery.ORDER.asc);
query.addField("*,score");
query.setStart((page - 1) * rows);
query.setRows(rows);
Map<String, String> map = new HashMap<>();
map.put("sfield", "loc");//loc是solr坐标字段
map.put("pt", pt);//中心坐标条件
SolrParams arg0 = new MapSolrParams(map);
query.add(arg0);
/**
* keyword条件 和type条件
*/
if (!StringUtils.isBlank(keyword)) {
query.addFilterQuery("title:" + "\"" + keyword + "\"");
}
if (type != null) {
query.addFilterQuery("type:" + type);
}
....//执行查询
....
}
|