Sphinx SetGeoAnchor 经纬度查找附近地点
Post by
yaohuaq
  2011-07-26 15:14:17 Tuesday Tags:Sphinx,PHP

Sphinx 的 SetGeoAnchor方法,

coreseek提供的中文翻译手册:

function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long )

为地表距离计算设置锚点,并且允许使用它们。$attrlat 和$attrlong 是字符串,分别指定了对应经度和纬度的属性名称。$lat 和$long 是浮点值,
指定了锚点的经度和纬度值,以角度为单位。一旦设置了锚点,您就可以在您的过滤器和/或排序表达式中使用@geodist 特殊属性。Sphinx 将在每一次全文检索中计算给定经纬度与锚点之前的地表距离,并把此距离附加到匹配结果
上去。SetGeoAnchor 和索引属性数据中的经纬度值都是角度。而结果会以米为单位返回,因此地表距离 1000.0 代表 1 千米。一英里大约是 1609.344 米。

 

以下是Sphinx官网原文:

6.4.5. SetGeoAnchor

Prototype: function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long )

Sets anchor point for and geosphere distance (geodistance) calculations, and enable them.

$attrlat and $attrlong must be strings that contain the names of latitude and longitude attributes, respectively. $lat and $long are floats that specify anchor point latitude and longitude, in radians.

Once an anchor point is set, you can use magic "@geodist" attribute name in your filters and/or sorting expressions. Sphinx will compute geosphere distance between the given anchor point and a point specified by latitude and lognitude attributes from each full-text match, and attach this value to the resulting match. The latitude and longitude values both in SetGeoAnchor and the index attribute data are expected to be in radians. The result will be returned in meters, so geodistance value of 1000.0 means 1 km. 1 mile is approximately 1609.344 meters.

coreseek这部分翻译有个问题,原文说的是弧度,而coreseek翻译成了角度,这是个错误。

 

一般由GPS提供的经纬度格式(角度)如:longitude:111.177579, latitude:53.051679  ,转换成弧度,公式为 (角度*Pi)/180,

 

首先在做索引的时候 ,得将经纬度数据源转换成弧度。

SQL数据源,如下转换:

SQL代码
  1. select id, radians(longitude) as longitude, radians(latitude) as latitude from locations  

 

如果使用coreseek 提供的Python数据源,如下转换,math.radians:

Python代码
  1. # -*- coding:utf-8 -*-  
  2. # 地点索引数据源  
  3. import os, pymongo, math  
  4. class MainSource(object):  
  5.     def __init__(self, conf):  
  6.         self.conf = conf  
  7.         self.idx = 0  
  8.         self.data = []  
  9.   
  10.     def GetScheme(self):  
  11.         return [  
  12.             ('_id', {'docid':True, }),  
  13.             ('name', {'type':'text'}),  
  14.             ('address', {'type':'text'}),  
  15.             ('created_at', {'type':'integer'}),  
  16.             ('updated_at', {'type':'integer'}),  
  17.             ('deleted_at', {'type':'integer'}),
  18.             ('longitude', {'type':'float'}),  
  19.             ('latitude', {'type':'float'}),  
  20.         ]  
  21.   
  22.     def GetFieldOrder(self):  
  23.         return [('name''address')]  
  24.   
  25.     def Connected(self):  
  26.         conn = pymongo.Connection(self.conf['dbhost'], int(self.conf['dbport']))  
  27.         db = conn[self.conf['dbname']]  
  28.         collection = db[self.conf['collection']]  
  29.         cur = collection.find()  
  30.         self.data = [ row for row in cur ]  
  31.         pass  
  32.   
  33.     def NextDocument(self):  
  34.         if self.idx < len(self.data):  
  35.             item = self.data[self.idx]  
  36.             self._id = int(item["_id"])  
  37.             self.name = item["name"].encode('utf-8')  
  38.             if item.has_key('coordinates'):  
  39.                 self.longitude = math.radians(item["coordinates"]["longitude"])  
  40.                 self.latitude  = math.radians(item["coordinates"]["latitude"])  
  41.             if item.has_key('address'):  
  42.                 self.address = item["address"].encode('utf-8')  
  43.             if item.has_key('created_at'):  
  44.                 self.created_at = item['created_at']  
  45.             if item.has_key('updated_at'):  
  46.                 self.updated_at = item['updated_at']  
  47.             if item.has_key('deleted_at'):  
  48.                 self.deleted_at = item['deleted_at']  
  49.             self.idx += 1  
  50.             return True  
  51.         else:  
  52.             return False  
  53.   
  54. if __name__ == '__main__':  
  55.     conf = {}  
  56.     source = MainSource(conf)  
  57.     source.Connected()  
  58.     while source.NextDocument():  
  59.         pass  

 

PHP搜索代码示例:

PHP代码
  1. $long  = (float)$_GET['longitude'];  
  2. $lat   = (float)$_GET['latitude'];  
  3. $radius = (float) 10000.0 * 1.61;       //搜索10公里以内的地点  
  4.   
  5. $cl = new SphinxClient();    
  6. $cl->SetServer("localhost", 3312);    
  7. $cl->SetMatchMode(SPH_MATCH_ANY);    
  8. $cl->SetArrayResult(true);    
  9. $cl->SetLimits(0, 100);    
  10. $cl->SetGeoAnchor('latitude''longitude', (float) deg2rad($long), (float) deg2rad($lat));    //角度转换成弧度  
  11.   
  12. $cl->SetSortMode(SPH_SORT_EXTENDED, '@geodist asc');    // 按距离正向排序  
  13. $cl->SetFilterFloatRange('@geodist', 0.0, $radius);     // 过滤掉大于10公里的地点  
  14.   
  15. $result = $cl->Query('''*');    

 

 

 

评论:
发表评论:
姓名:
联系方法:(选填)
评论内容: