zoukankan      html  css  js  c++  java
  • app后端设计(6)-- LBS

    在LBS的应用中,一个基本的需求是查找附近的用户,现在有两种做法:

    1. 使用mysql的空间数据库,具体做法参考:http://blog.sina.com.cn/s/blog_a48af8c001018q1p.html 。

    2.  使用geohash编码,这个是本文需要讨论的。

        geohash编码,可以把球面上的经纬度转换成一个值,简单点来说就是把二维坐标转换成一维坐标。查找附近的时候,非常方便,用SQL中,LIKE ‘w23yr3%’可查询附近的所有地点。

        geohash的详细介绍,可参考 http://www.wubiao.info/372

             在以前的产品中,一个需求是查找用户附近的商铺,发现用mysql LIKE ‘w23yr3%’这种方式检索geohash性能上的瓶颈很大,检索130万行的数据,平均花费了8秒,这是响应速度是无法忍受的。

        后来经过不断优化,确定了如下使用coreseek+redis+mysql解决方案,一下子就把响应速度减少到平均1 秒,这个方案的如下:

    1. 用每个商铺的坐标值计算geohash,把geohash作为key,商铺的作为value,放到redis的set集中。

    $this->cache->redis->select(1);//不能使用0,因为这里有大量的数据,需要独立
    $this->cache->redis->set('place:geohash:'.$geohash,$place_id);

    2. 根据用户的坐标,在redis中查找附近的商铺id

    <?php
    
        /**
         * 获取附近的地标公共处理方法
         * @param $lat
         * @param $lng
         * @param $n geohash值的长度,一般来说,当n=6,是获取当前附近1千米范围内的用户
         */
        function getLocalPlace($lat, $lng, $n)
        {
    
            $lat = (float) $lat;
            $lng = (float) $lng;
            $nowGeohash = $this->geohash->encode($lng, $lat);
            $likeGeohash = substr($nowGeohash, 0, $n);
            $placeIds = array();
    
    		$this->_loadDriver('cache', array('adapter' => 'redis'));
    		 
    		//不能使用0,因为这里有大量的数据,需要独立
    		$this->cache->redis->select(1);
    		
    		//*表示模糊匹配,例如有key werewfs,werewfw,那么使用“werewf*”,则能同时匹配werewfs,werewfw
    		$geohashKeys = $this->cache->redis->keys('place:geohash:' . $likeGeohash . '*');
    		$hashlen = strlen($nowGeohash);
    		if ($geohashKeys)
    		{
    			$searchKeys = array();
    			
    			//对坐标进行排序
    			foreach ($geohashKeys as $k => $v) {
    				$v = ltrim($v, 'place:geohash:');
    				for ($i = $n; $i < $hashlen; $i++) {
    					$compare_hash = substr($nowGeohash, 0, $i);
    					$cur_hash = substr($v, 0, $i);
    					if ($compare_hash != $cur_hash)
    					{
    						$nofst = str_pad(($i - 1) . $k, 6, '0');
    						$searchKeys[$nofst] = 'place:geohash:' . $v;
    						break 1;
    					}
    				}
    			}
    			if ($searchKeys)
    			{
    				krsort($searchKeys);
    				
    				//mget表示返回所有特殊keys的values
    				$placeIds = $this->cache->redis->mget($searchKeys);
    		 
    			}
    		}
               
    		return $placeIds;
        }
    


    3. 如果需要查找关键字或商铺的类型,则用把2中$placeIds 作为filter调戏 ,在coreseek中继续查找。

    app后端系列文章总目录

     如果您觉得这系列的文章对你有所帮助,欢迎打赏。
    支付宝账号:190678908@qq.com 收款人:曾健生


    [文章作者]曾健生

    [作者邮箱]h6k65@126.com

    [作者QQ]190678908

    [新浪微博] @newjueqi

    [博客]http://blog.csdn.net/newjueqi

              http://blog.sina.com.cn/h6k65

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    Selenium(Python)等待元素出现
    java文件的I/O
    Map的四种遍历方式
    模板类实现链表
    字符串相关库函数使用
    动态规划之背包问题
    最长递增子序列
    深度优先搜索(DFS),逃离迷宫
    素数环问题(递归回溯)
    枚举(百鸡问题)
  • 原文地址:https://www.cnblogs.com/dingxiaoyue/p/4926825.html
Copyright © 2011-2022 走看看