Solr 空間搜索配置 1. 在solr目錄下的找到conf文件夾下的schema.xml. <fields> <!-- 在fields元素中添加如下代碼 --> <field name="store_lat_lon" type="location" indexed="true" stored="true"/> <dynamicField name="*_coordinate" type="double" indexed="true" stored="false" multiValued="false"/> </fields> 2. 在solr目錄下的找到conf文件夾下的db-data.config.xml . 把dataConfig標簽內的script標簽的內容做如下修改。 <script><![CDATA[ function f1(row){ row.put('$docBoost', 1); var lat_coordinate = row.get("GPS_Y "); var log_coordinate = row.get("GPS_X "); if( lat_coordinate != null && log_coordinate != null ){ if( lat_coordinate*1 >= -90 && lat_coordinate*1 <= 90 ) { var store_lat_lon = lat_coordinate + "," + log_coordinate; var arr = new java.util.ArrayList() arr.add(lat_coordinate); arr.add(log_coordinate); row.put("store_lat_lon",store_lat_lon); row.put("item",arr); } } return row; } ]]></script> 3. 重新啟動solr. 重建索引:http://localhost:8080/solr/dataimport?command=full-import 4. 查詢示例: http://localhost:8080/solr/select/?q=*:*&fq={!geofilt}&sfield=store_lat_lon&pt=86.13909901,41.770741&d=5&fl=name,gps_x,gps_y,store_lat_lon&sort=geodist() asc 參數 描述 示例 d 距離(單位:km) &d=10.0 pt 搜索過濾的中心點,緯度,經度坐標點 &pt=33.4,29.0 sfield 空間搜索類型的字段(eg: solr.LatLonType) &sfield=store_lat_lon fq 設置查詢過濾器 fq={!geofilt} sort 根據字段或者函數排序 &sort=geodist() asc geofilt 函數: 使結果集約束在到中心點位置的最大距離(km)圓形區域內。 geodist 函數: 計算兩點之間的距離。 注意:solr 3.4版本以上才支持geodist等空間搜索函數。 參考:http://wiki.apache.org/solr/SpatialSearch Script形式的轉換只在JDK1.6版本或以上才支持,下面是通用的空間搜索轉換的實現,支持JDK1.5及其以上版本。 新建一個類如下所示,該類可以不繼承或實現任何其他接口或者抽象類,但是transformRow方法必須定義成下面所示,SOLR dataimport插件會通過反射的方式去調用這個方法。 package com.besttone.transformer; import java.util.ArrayList; import java.util.Map; public class LocationTransformer { // 參考資料 http://wiki.apache.org/solr/DIHCustomTransformer public Object transformRow(Map<String, Object> row) { // TODO Auto-generated method stub row.put("$docBoost", 1); Object lat_coordinate = row.get("GPS_Y"); Object log_coordinate = row.get("GPS_X"); if (lat_coordinate != null && log_coordinate != null) { if (Double.parseDouble(lat_coordinate.toString()) * 1 >= -90 && Double.parseDouble(lat_coordinate.toString()) * 1 <= 90) { String store_lat_lon = lat_coordinate.toString() + "," + log_coordinate.toString(); ArrayList arr = new ArrayList(); arr.add(lat_coordinate); arr.add(log_coordinate); row.put("store_lat_lon", store_lat_lon); row.put("item", arr); } } return row; } } 第二步在db-data-config.xml中的entity節點上配置轉換類: <entity name="zbs" transformer="com.besttone.transformer.LocationTransformer" ……….. 這個類必須以全路徑配置。 第三步將上面的類用jdk1.5編譯並打成JAR包,放在solr/home的lib下面,然后再solr.xml中配置全局共享lib: <solr persistent="false" sharedLib="lib"> 這樣dataimport就能找到這個轉換類,並通過反射的方式調用transformRow實現轉換. 也可以繼承Transformer抽象類來實現更高級的自定義轉換類應用。 參考資料 http://wiki.apache.org/solr/DIHCustomTransformer 若要返回距離,4.0版本可以參照第一種方法,4.0以下版本可參照下面第二種方法,score返回的就是距離。 Returning the distance <!>Solr4.0 You can use the pseudo-field feature to return the distance along with the stored fields of each document by addingfl=geodist() to the request. Use an alias like fl=_dist_:geodist() to make the distance come back in the_dist_ pseudo-field instead. Here is an example of sorting by distance ascending and returning the distance for each document in_dist_. ...&q=*:*&sfield=store&pt=45.15,-93.85&sort=geodist() asc&fl=_dist_:geodist() As a temporary workaround for older Solr versions, it's possible to obtain distances by using geodist or geofilt as the only scoring part of the main query. ...&sfield=store&pt=45.15,-93.85&sort=score%20asc&q={!func}geodist() 若要顯示距離並按某些字段比如名字來查詢的話,那查詢條件只能寫在fq中,如果寫在q中則會影響得分,導致score字段返回的不是距離,寫法如下: http://localhost:8089/solr/select/?q={!func}geodist()&fq={!geofilt}&fq=address:興華南街&sfield=store_lat_lon&pt=41.78101895,123.36067849&d=5&sort=score%20asc&fl=score 查找5公里范圍內並且地址在興華南街的數據(fq=address:興華南街)。
