搜索附近的人的搜索算法实现

随着移动终端的普及,很多应用都基于LBS功能,附近的某某(餐馆、银行、妹纸等等)。

基础数据中,一般保存了目标位置的经纬度;利用用户提供的经纬度,进行对比,从而获得是否在附近。

目标:

查找附近的XXX,由近到远返回结果,且结果中有与目标点的距离。

针对查找附近的XXX,方案如下:

Geohash算法;geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串。

以下是具体实现的例子:

比如,成都永丰立交的编码是wm3yr31d2524

优点:

1、利用一个字段,即可存储经纬度;搜索时,只需一条索引,效率较高

2、编码的前缀可以表示更大的区域,查找附近的,非常方便。 SQL中,LIKE ‘wm3yr3%’,即可查询附近的所有地点。

3、通过编码精度可模糊坐标、隐私保护等。

缺点: 距离和排序需二次运算(筛选结果中运行,其实挺快)

具体算法步骤如下:

1、geohash的编码算法

成都永丰立交经纬度(30.63578,104.031601)

1.1、纬度范围(-90, 90)平分成两个区间(-90, 0)、(0, 90),如果目标纬度位于前一个区间,则编码为0,否则编码为1。

由于30.625265属于(0, 90),所以取编码为1。

然后再将(0, 90)分成 (0, 45), (45, 90)两个区间,而39.92324位于(0, 45),所以编码为0,

然后再将(0, 45)分成 (0, 22.5), (22.5, 45)两个区间,而39.92324位于(22.5, 45),所以编码为1,

依次类推可得永丰立交纬度编码为101010111001001000100101101010。

1.2、经度也用同样的算法,对(-180, 180)依次细分,(-180,0)、(0,180) 得出编码110010011111101001100000000000

1.3、合并经纬度编码,从高到低,先取一位经度,再取一位纬度;得出结果 111001001100011111101011100011000010110000010001010001000100

1.4、用0-9、b-z(去掉a, i, l, o)这32个字母进行base32编码,得到(30.63578,104.031601)的编码为wm3yr31d2524。

11100 10011 00011 11110 10111 00011 00001 01100 00010 00101 00010 00100 => wm3yr31d2524

十进制  0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15

base32   0   1   2   3   4   5   6   7   8   9   b   c   d   e   f   g

十进制  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31

base32   h   j   k   m   n   p   q   r   s   t   u   v   w   x   y   z

2、具体匹配策略

1、在纬度和经度入库时,数据库新加一字段geohash,记录此点的geohash值

2、查找附近,利用 在SQL中 LIKE ‘wm3yr3%’;且此结果可缓存;在小区域内,不会因为改变经纬度,而重新数据库查询

3、查找出的有限结果,如需要求距离或者排序,可利用距离公式和二维数据排序;此时也是少量数据,会很快的。

import java.util.HashMap;
import java.util.Map;

public class GeoHashKit {

	private static char[] base32 = { ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘, ‘g‘, ‘h‘, ‘j‘, ‘k‘, ‘m‘, ‘n‘, ‘p‘, ‘q‘, ‘r‘, ‘s‘, ‘t‘, ‘u‘, ‘v‘, ‘w‘, ‘x‘, ‘y‘, ‘z‘ };
	private final static Map<Character, Integer> decodemap = new HashMap<Character, Integer>();
	static {
		int sz = base32.length;
		for (int i = 0; i < sz; i++) {
			decodemap.put(base32[i], i);
		}
	}
	private static int precision = 10;
	private static int[] bits = { 16, 8, 4, 2, 1 };

	/**
	 * 设置精度
	 * @param int precision 设置精确位数,此参数决定了该算法的经度
	 *
	 * */
	public static void setPrecision(int precision) {
		GeoHashKit.precision = precision;
	}

	public static double getPrecision(double x, double precision) {
		double base = Math.pow(10, -precision);
		double diff = x % base;
		return x - diff;
	}

	public static String encode(double latitude, double longitude) {
		double[] lat_interval = { -90.0, 90.0 };
		double[] lon_interval = { -180.0, 180.0 };
		StringBuilder geohash = new StringBuilder();
		boolean is_even = true;
		int bit = 0, ch = 0;
		while (geohash.length() < precision) {
			double mid = 0.0;
			if (is_even) {
				mid = (lon_interval[0] + lon_interval[1]) / 2;
				if (longitude > mid) {
					ch |= bits[bit];
					lon_interval[0] = mid;
				} else {
					lon_interval[1] = mid;
				}
			} else {
				mid = (lat_interval[0] + lat_interval[1]) / 2;
				if (latitude > mid) {
					ch |= bits[bit];
					lat_interval[0] = mid;
				} else {
					lat_interval[1] = mid;
				}
			}
			is_even = is_even ? false : true;

			if (bit < 4) {
				bit++;
			} else {
				geohash.append(base32[ch]);
				bit = 0;
				ch = 0;
			}
		}
		return geohash.toString();
	}

	public static double[] decode(String geohash) {
		double[] ge = decode_exactly(geohash);
		double lat, lon, lat_err, lon_err;
		lat = ge[0];
		lon = ge[1];
		lat_err = ge[2];
		lon_err = ge[3];
		double lat_precision = Math.max(1, Math.round(-Math.log10(lat_err))) - 1;
		double lon_precision = Math.max(1, Math.round(-Math.log10(lon_err))) - 1;
		lat = getPrecision(lat, lat_precision);
		lon = getPrecision(lon, lon_precision);
		return new double[] { lat, lon };
	}

	public static double[] decode_exactly(String geohash) {
		double[] lat_interval = { -90.0, 90.0 };
		double[] lon_interval = { -180.0, 180.0 };
		double lat_err = 90.0;
		double lon_err = 180.0;
		boolean is_even = true;
		int sz = geohash.length();
		int bsz = bits.length;
		double latitude, longitude;
		for (int i = 0; i < sz; i++) {
			int cd = decodemap.get(geohash.charAt(i));
			for (int z = 0; z < bsz; z++) {
				int mask = bits[z];
				if (is_even) {
					lon_err /= 2;
					if ((cd & mask) != 0) {
						lon_interval[0] = (lon_interval[0] + lon_interval[1]) / 2;
					} else {
						lon_interval[1] = (lon_interval[0] + lon_interval[1]) / 2;
					}
				} else {
					lat_err /= 2;

					if ((cd & mask) != 0) {
						lat_interval[0] = (lat_interval[0] + lat_interval[1]) / 2;
					} else {
						lat_interval[1] = (lat_interval[0] + lat_interval[1]) / 2;
					}
				}
				is_even = is_even ? false : true;
			}
		}
		latitude = (lat_interval[0] + lat_interval[1]) / 2;
		longitude = (lon_interval[0] + lon_interval[1]) / 2;
		return new double[] { latitude, longitude, lat_err, lon_err };
	}

	public static void main(String[] args) {
		GeoHashKit ghf = new GeoHashKit();
		String gc1 = ghf.encode(31.277631, 120.53916300000003);
		String gc2 = ghf.encode(51.4797, -0.0124);

		System.out.println(gc1);
		System.out.println(gc2);

		double[] gd1 = ghf.decode(gc1);
		double[] gd2 = ghf.decode(gc2);
		System.out.println(gd1[0] + ", " + gd1[1]);
		System.out.println(gd2[0] + ", " + gd2[1]);
	}
}

搜索附近的人的搜索算法实现,布布扣,bubuko.com

时间: 2024-10-15 01:03:01

搜索附近的人的搜索算法实现的相关文章

搜狗微信搜索推出 一些人又要忙坏了

搜狗微信搜索开通了,不得不说方便了许多,用户可在搜狗搜索结果页可浏览到与查询词相关的微信公众号及全部文章.就像之前说的雅虎新闻摘要yahoo news digest,在方便大多数人的同时也方便了采集者,如果他们不加修改地直接发布的话也会造成信息的泛滥. 对于搜狗微信搜索,微信官方称:"微信公众平台搜索功能核心为,用户获取.查询微信公众平台的内容信息更简单.方便,为微信增加了一个非常好的内容查询入口." 微信称,这次与搜狗合作意义在于三点:一是公众号可以从搜索引擎获得更多流量与阅读量:其

ElasticSearch+Spark 构建高相关性搜索服务&amp;千人千面推荐系统 教程资源

本文配套资料获取链接:点击这里 基于大众点评搜索以及推荐业务,从企业实际项目落地实践的角度出发,在使用SpringBoot加mybatis完成用户登录.注册.商家入驻以及结合前端模板搭建运营后台门店服务管理功能后,借助ElasticSearch的最新版本ES7逐步迭代,完成高相关性进阶搜索服务,并基于spark mllib2.4.4构建个性化千人千面推荐系统. 课程所用到的技术: 在具体场景中的应用效果: 环境参数: 本文配套资料获取链接:点击这里 原文地址:https://www.cnblog

四叉树搜索附近的人

现在很多的APP都有"附近的人"功能. 粗略的思考一下,用户在登录的时候会将自己的位置信息告诉服务器,服务器会记录一份用户的位置信息列表. 假设服务器里只有10个人,那么要找附近的人就很简单,只需写一个算距离的函数,然后依次遍历长度是10的位置信息列表,距离从近到远排序,返回排序后的列表即可. 那么如果服务器里有1千万人呢,或者几亿人呢,比如微信.这时再从头到尾遍历(复杂度O(n))就不适合了. 通常情况下会使用“四叉树”来构建这些大量的位置信息. 1.四叉树 顾名思义,四叉树是叶子节

【算法】变邻域搜索算法(Variable Neighborhood Search,VNS)超详细一看

更多精彩尽在微信公众号[程序猿声] 变邻域搜索算法(Variable Neighborhood Search,VNS)一看就懂的解析 00 目录 局部搜索再次科普 变邻域搜索 造轮子写代码 01 局部搜索科普三连 虽然之前做的很多篇启发式的算法都有跟大家提过局部搜索这个概念,为了加深大家的印象,在变邻域主角登场之前还是给大家科普一下相关概念.热热身嘛- 1.1 局部搜索是什么玩意儿? 官方一点:局部搜索是解决最优化问题的一种启发式算法.对于某些计算起来非常复杂的最优化问题,比如各种NP完全问题,

刷百度相关搜索发包参数详解

因很多人需要百度相关搜索,很多人用这个技术卖钱,自己本着技术的爱好,把这个分享给大家! 刷相关搜索的实现方法: 第一:比如圆柱模板,我们可以先搜索圆柱模板厂家,然后接着再去搜索圆柱模板价格,那么每天以几倍的方式增加,当达到一定搜索量的时候,那么圆柱模板的相关词搜索就会出现圆柱模板价格了. 打开百度首页//www.baidu.com/输入圆柱模板出来的地址为: https://www.baidu.com/s?ie=UTF-8&wd=%E5%9C%86%E6%9F%B1%E6%A8%A1%E6%9D

HDU--3457--Rectangles--记忆化搜索

Rectangles Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 707    Accepted Submission(s): 284 Problem Description A rectangle in the Cartesian plane is speci ed by a pair of coordinates (x1 , y

现代优化算法 之 禁忌搜索算法

这次是首次接触这个算法,看了一些资料,总结一下. 禁忌搜索算法简介 禁忌搜索算法是组合优化算法的一种,是局部搜索算法的扩展.禁忌搜索算法是人工智能在组合优化算法中的一个成功应用.禁忌搜索算法的特点是采用了禁忌技术.所谓禁忌就是禁止重复前面的工作.禁忌搜索算法用一个禁忌表记录下已经到达过的局部最优点,在下一次搜索中,利用禁忌表中的信息不再或有选择地搜索这些点. 禁忌搜索算法实现的技术问题是算法的关键.禁忌搜索算法涉及侯选集合.禁忌对象.评价函数.特赦规则.记忆频率信息等概念. (1)邻域 在组合优

人机博弈-吃子棋游戏(四)搜索算法

博弈树搜索技术简介: 博弈树的搜索算法,负值极大搜索,alpha-beta搜索,渴望搜索,PVS极窄窗口搜索等.通常来说,搜索算法常常和以下技术联合在一起. 如下: 1.置换表,记录已经搜索过的棋局,避免再次搜索. 2.吃子启发,优先试下能够吃对方棋子的走法. 3.杀手启发,历史启发简化版. 4.历史启发,优先试下历史统计数据得出的比较好的走法. 5.静止期搜索,继续对某些叶子结点搜索,避免水平线效应. 6.迭代加深搜索,根据搜索时间,状态.决定是否继续搜索. 有兴趣的朋友可以深入研究一下上述技

PC端搜索和移动搜索的区别在哪里

我认为改成移动搜索和非移动搜索(传统搜索,以百度,google为例)的区别比较好.重要的一点:移动搜索是指人在移动场景下的搜索,移动设备只是为这个场景提供条件. 搜索的作用是建立连接,比较移动搜索和传统搜索的方法是区别它们要建立的连接. 连接的对象传统搜索将人和相对静态的信息连接起来,搜索结果受用户时间和空间的影响小:而移动搜索将人和相对动态的信息连接起来,搜索结果受用户时间和空间的影响大.连接的建立方式传统搜索在室内安稳的环境下进行,用户可以保持专注并进行细致的结果挑选:而移动搜索在室外变化的