Spatial Query
一、介绍
空间索引(spatial index)是指依据空间对象的位置和形状,按一定顺序排列的一种数据结构,其中包含空间对象的概要信息如对象的标识、最小外接矩形(minimum bounding rectangle,MBR)及指向空间对象实体的指针。空间索引使空间操作能够快速访问操作对象,从而提高效率。目前普遍认为,空间索引技术的采纳与否以及空间索引的性能优劣直接影响地理信息系统(GIS)的整体性能。

空间索引技术可大致分为:基于树结构,基于网格划分,混合型。这里主要分析基于网格以及KD树的空间索引。

1.网格索引法:

格网型空间索引的基本思想是将研究区域用横竖线条划分大小相等或不等的格网,记录每一个格网所包含的空间实体。当用户进行空间查询时,首先计算出用户查询对象所在格网,然后再在该网格中快速查询所选空间实体,这样一来就大大地加速了空间索引的查询速度。

把一幅图的矩形地理范围均等地划分为 m行n列,即规则地划分二维数据空间,得到m×n个小矩形网格区域。每个网格区域为一个索引项,并分配一个 动态存储区,全部或部分落入该网格的空间对象的标识以及外接矩形存入该网格。

网格索引是一种多对多的索引,会导致冗余,网格划分得越细,搜索的精度就越高,当然冗余也越大,耗费的磁盘空间和搜索时间也越长。网格法由于必须预先定义好网格大小,因此它不是一种动态的数据结构。适合点数据。网格索引搜索算法的时间复杂度为o(N2)。

KD-Tree法:
SIFT算法中做特征点匹配的时候就会利用到k-d树。而特征点匹配实际上就是一个通过距离函数在高维矢量之间进行相似性检索的问题。针对如何快速而准确地找到查询点的近邻,现在提出了很多高维空间索引结构和近似查询的算法,k-d树就是其中一种。

索引结构中相似性查询有两种基本的方式:一种是范围查询(range searches),另一种是K近邻查询(K-neighbor searches)。范围查询就是给定查询点和查询距离的阈值,从数据集中找出所有与查询点距离小于阈值的数据;K近邻查询是给定查询点及正整数K,从数据集中找到距离查询点最近的K个数据,当K=1时,就是最近邻查询(nearest neighbor searches)。

特征匹配算子大致可以分为两类。一类是线性扫描法,即将数据集中的点与查询点逐一进行距离比较,也就是穷举,缺点很明显,就是没有利用数据集本身蕴含的任何结构信息,搜索效率较低,第二类是建立数据索引,然后再进行快速匹配。因为实际数据一般都会呈现出簇状的聚类形态,通过设计有效的索引结构可以大大加快检索的速度。索引树属于第二类,其基本思想就是对搜索空间进行层次划分。根据划分的空间是否有混叠可以分为Clipping和Overlapping两种。前者划分空间没有重叠,其代表就是k-d树;后者划分空间相互有交叠,其代表为R树。

二、问题描述
2.1具体任务
本次作业任务是空间检索,给定一个GPS数据记录文件,每条记录包含经度、纬度等多个属性,其中常用的就是经度、维度、地点的ID以及地点的类别属性,要求采用合适的算法,实现三种检索方法,分别是最邻近算法(KNN),区域查询以及半径查询。最邻近算法是给定一个坐标ID,查找距离该坐标最近的某个地点。区域查询是通过给定的矩形范围四个角的经纬度,查询该区域中某类别的坐标地点。半径查询是给定一个中心位置,以该位置为圆心,进行圆形区域范围检索某类别的坐标地点。

2.2程序输入
本程序分为最近距离搜索、区域搜索和半径搜索。最近距离搜索的输入为:查询地点的坐标ID,最近的查询类别编号。区域搜素的输入为:左上角经度,左上角纬度,右上角经度,右上角纬度,查找类别。半径搜索的输入为:查找地点坐标ID,查询半径以及查询地点的类别编号。

2.3 程序输出
本程序输出的是经度坐标、维度坐标、名字和最近距离。

三、问题解答
3.1 数据预处理
本次程序输入为GPS数据记录文件,每行记录又分为若干个属性,根据题意,我们只需关注经度、纬度坐标、地点ID以及坐标类别属性即可,原始数据文件部分记录如图3.1所示:

图3.1 原始数据文件部分记录示意图

刚开始选择的方案是与数据文件建立连接,从中抽取出需要的属性对应的数据,形成新的数据文件或者是在存储在内存数组中,存储在内存中缺点是占用内存,形成新的数据文件是用行号作为索引,可能会多次多文件进行读取,增大运行时间。后来经过研究发现,可以有两种方式,在不占用太大内存的情况下,将数据输入数据文件,并在内存中建立数据的索引。分别时将对象序列化存入数据文件,将对象的索引以集合的方式在内存中建立索引,另一种是将数据存储JSONObject,然后装入JSONArray,写入JSON文件,就可以以下标方式建立索引。通过运行时间比较发现,对象序列化方式建立文件和读取的速度快。

3.2 Grid-based Spatial Indexing
3.2.1 搜索的特点
(1)将空间划分为不相交和均匀的网格

(2)在每个网格和网格点之间建立反向索引

3.2.2 范围查询
(1)查找与范围查询相关的网格。

(2)从网格中获取点并确定范围内的点。

3.2.3 最邻近查询
(1)计算的是欧式距离。

(2)道路网络的距离是完全不同的。

最近的点在网格内部          最近的点在网格外部             快速近似

3.2.4 基于网格查询的优缺点
优点:(1)易于实现和理解。

(2)能非常有效的处理范围和最近的查询。

缺点:(1)索引大小可能很大。

(2)难以处理不平衡的数据。

3.3 KD-Tree Spatial Indexing
3.3.1 搜索的特点
图中的行编号表示对应节点出现的树的级别。

Kd-Tree,即K-dimensional tree,是一棵二叉树,树中存储的是一些K维数据。在一个K维数据集合上构建一棵Kd-Tree代表了对该K维数据集合构成的K维空间的一个划分,即树中的每个结点就对应了一个K维的超矩形区域(Hyperrectangle)。

3.2.2 范围查询
(1) 判断结点在不在范围之内,如果包含于范围之内就进入子树查询。

(2)通过建立的树节点比较可以节省查询时间,提高查询效率。

由于kd-tree每一层都是对平面的划分,我们考虑其孙子辈节点.查询只会对那些与其相交的节点递归查询,因此只需要判断相交区域数目就行了。

3.2.3最邻近查询
从根节点开始递归的查找,根据p在节点的左边还是右边,决定递归方向

若到达叶节点,则将其作为当前最优节点

回溯:
(1) 若当前节点比当前最优点更优,则将其作为当前最优节点
(2) 判断左子树是否存在最优点,若有则递归下去

当根节点搜索完毕,则查找结束。

具体实现的时候需要说明的是,可以用一个优先队列存储最优的k个节点,这样每次比对回溯节点是否比当前最优点更优的时候,就只需用当前最优点中里p最远的节点来比对,而这个工作对于优先队列来说是O(1)的。

四、代码实现
4.1 程序总流程
网格法空间搜索:

(1)获取原始点坐标并将其写入到文件中,主要包括读文件和写文件两种操作。

(2)将所选区域等分为格状,读取目标物经纬度,查找网格内部与它最近的点的位置。

(3)若搜寻无果,则扩大搜索范围,采用递归调用的方法逐渐搜寻与他最近的点。

KD-Tree空间搜索:

1.最邻近算法

k_close(p,o,k,)//查询点p,树当前节点o,近邻数目k从根节点开始递归的查找,根据p在节点的左边还是右边,决定递归方向若到达叶节点,则将其作为当前最优节点回溯:
(1) 若当前节点比当前最优点更优,则将其作为当前最优节点
(2) 判断左子树是否存在最优点,若有则递归下去

当根节点搜索完毕,则查找结束。

2.范围查找

if v 是叶子
报告并return
if lc(左子树) 包含于 搜索区域
报告lc
else 左子树与搜索区域相交
递归搜索左子树
if rc(右子树) 包含于 搜索区域
else 右子树与搜索区域相交
递归搜索右子树
报告rc

4.2 具体代码实现
    https://download.csdn.net/download/asd2479745295/10675084

五、程序运行结果
5.1 网格法空间搜索:
  5.1.1最邻近算法

5.1.2范围查找算法

5.1.3圆范围查找

5.2 KD-Tree空间搜索
5.2.1最邻近算法查找

5.2.2范围查找

5.2.3半径查找

5.3 索引文件建立时间对比
   抽取的数据放入txt需要频繁读取,所以考虑了两种建立索引的方式,一种是将数据放入对象,然后序列化写入文件,另一种是将数据存入JSON对象,然后写入JSON文件。

部分代码

public class UtilZ{/*** 读取指定文件指定行号的内容* @param sourceFile 文件* @param lineNumber 行号* @return 字符串内容*/public String readAppointedLineNumber(File sourceFile, int lineNumber)  throws IOException {  FileReader in = new FileReader(sourceFile);  LineNumberReader reader = new LineNumberReader(in);  String s = "";  int lines = 0;  while (s != null) {  lines++;  s = reader.readLine();  if((lines - lineNumber) == 0) {  // System.out.println(s);return s;  }  }  reader.close();  in.close();  return s;}/*** 字符串模糊匹配* @param adressName 匹配的字符串  比如ATM* @param text 查询的内容 比如中国银行ATM机* @return 字符串内容*/private static boolean match(String adressName,String text){Pattern pattern = Pattern.compile("("+adressName+")");Matcher matcher = pattern.matcher(text);if(matcher.find()){// System.out.println("匹配到了:"+matcher.group(1));return true;}// System.out.println("没有匹配到");return false;}/*** 根据两点经纬度获得两点距离* @param lat 经度* @param lon 纬度* @return 两点距离*/public static double Geodist(double lat1, double lon1, double lat2, double lon2){double radLat1 = Rad(lat1);double radLat2 = Rad(lat2);double delta_lon = Rad(lon2 - lon1);double top_1 = Math.cos(radLat2) * Math.sin(delta_lon);double top_2 = Math.cos(radLat1) * Math.sin(radLat2) - Math.sin(radLat1) * Math.cos(radLat2) * Math.cos(delta_lon);double top = Math.sqrt(top_1 * top_1 + top_2 * top_2);double bottom = Math.sin(radLat1) * Math.sin(radLat2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.cos(delta_lon);double delta_sigma = Math.atan2(top, bottom);double distance = delta_sigma * 6378137.0;return distance;}public static double Rad(double d){return d * Math.PI / 180.0;}/*** 根据某点经纬度和半径,获取圆周内最大最小经纬度* @param lat 经度* @param lon 纬度* @param 半径* @return 数组minLat, minLng, maxLat, maxLng*/public static double[] GetAround(double lat, double lon, int raidus){Double latitude = lat;Double longitude = lon;Double degree = (24901 * 1609) / 360.0;double raidusMile = raidus;Double dpmLat = 1 / degree;Double radiusLat = dpmLat * raidusMile;Double minLat = latitude - radiusLat;Double maxLat = latitude + radiusLat;Double mpdLng = degree * Math.cos(latitude * (3.14159265 / 180));Double dpmLng = 1 / mpdLng;Double radiusLng = dpmLng * raidusMile;Double maxLng = longitude - radiusLng;Double minLng = longitude + radiusLng;return new double[] { minLat, minLng, maxLat, maxLng };}/*** 求一个一维数组的方差* @param data 数据** @return 方差*/public static double variance(ArrayList<double[]> data,int dimention){double vsum = 0;double sum = 0;for(double[] d:data){sum+=d[dimention];vsum+=d[dimention]*d[dimention];}int n = data.size();return vsum/n-Math.pow(sum/n, 2);}/*** 递归实现快速排序算法* @param data 数据* @param low 低位置* @param high 高位置* @return 方差*/public static void QuickSort(double[] data,int low,int high){// TODO 自动生成的方法存根if(low<high){int middle=GetMiddle(data,low,high);QuickSort(data,low,middle-1);QuickSort(data,middle+1,high);}}//将数组拆分public static int GetMiddle(double[] data, int low, int high){// TODO 自动生成的方法存根//将数组位置最小的元素赋值给中轴double temp=data[low];while(low<high){while(low < high && data[high] >= temp){high--;}data[low] = data[high];//比中轴小的记录移到低位置while(low < high && data[low] <= temp){low++;}data[high] = data[low] ; //比中轴大的记录移到高位置}data[low] = temp ; //将中轴元素放入中轴return low;}/*** 求矩形外一点到矩形最小的距离* @param input 输入的点的数据* @param max 横纵坐标的最大值* @param min 横纵坐标的最小值* @return 最小距离*/public static double minP_RDistance(double []input,double []max,double min[]){double point_x=input[0];double point_y=input[1];double max_x=max[0];double max_y=max[1];double min_x=min[0];double min_y=min[1];double mindistance=0;//如果在矩形的左右两边if(point_y>min_y&&point_y<max_y){if(point_x>max_x){mindistance=Geodist(point_x,point_y, max_x, point_y);}else if(point_x<min_x){mindistance=Geodist(point_x,point_y, min_x, point_y);}}else if(point_x>min_x&&point_x<max_x){if(point_y>max_y){mindistance=Geodist(point_x,point_y, point_x, max_y);}else if(point_y<min_y){mindistance=Geodist(point_x,point_y, point_x, min_y);}}//在四个角上else{  //左上if(point_x<min_x&&point_y>max_y){mindistance=Geodist(point_x,point_y,min_x,max_y);}//左下else if(point_x<min_x&&point_y<min_y){mindistance=Geodist(point_x,point_y,min_x,min_y);}//右上else if(point_x>max_x&&point_y>max_y){mindistance=Geodist(point_x,point_y,max_x,max_y);}//右下else if(point_x>max_x&&point_y<min_y){mindistance=Geodist(point_x,point_y,max_x,min_y);}}return mindistance;}}

java实现网格法、KDTree空间检索相关推荐

  1. kdtree java_KdTree理解与实现(Java)

    KdTree理解与实现(Java) 抛出问题 KdTree简介 原理简介 代码实现 Point.java Rect.java KdTree.java 复杂度比较 结语 抛出问题 如果让你设计一个外卖系 ...

  2. libsvm java svmtrain_libsvm工具包(含网格法查找最优解函数 SVMcgForClass.m 内用svmtrain函数)...

    [实例简介] 在其中的windows文件夹中 [实例截图] [核心代码] libsvm-3.22 └── libsvm-3.22 ├── COPYRIGHT ├── FAQ.html ├── hear ...

  3. java实现k 近邻算法_K近邻算法哪家强?KDTree、Annoy、HNSW原理和使用方法介绍

    1.什么是K近邻算法 K近邻算法(KNN)是一种常用的分类和回归方法,它的基本思想是从训练集中寻找和输入样本最相似的k个样本,如果这k个样本中的大多数属于某一个类别,则输入的样本也属于这个类别. 关于 ...

  4. Kd-Tree算法原理和开源实现代码

    Kd-Tree算法原理和开源实现代码 本文介绍一种用于高维空间中的快速最近邻和近似最近邻查找技术--Kd-Tree(Kd树).Kd-Tree,即K-dimensional tree,是一种高维索引树形 ...

  5. 根据经纬度求最近点的三种解法java实现

    文章目录 1. geoHash 2. kdTree算法求最近点 3.暴力法 4.利用elasticsearch或者lucene 1. geoHash 首先对经纬度点进行编码: 利用geoHash把经纬 ...

  6. 支持C/C++、Java、python、Matlab等语言的第三方机器学习库汇总

    C 通用机器学习 Recommender - 一个产品推荐的C语言库,利用了协同过滤. 计算机视觉 CCV - C-based/Cached/Core Computer Vision Library ...

  7. 【机器学习】K近邻算法(K-NearestNeighbors , KNN)详解 + Java代码实现

    文章目录 一.KNN 基本介绍 二.KNN 核心思想 三.KNN 算法流程 四.KNN 优缺点 五.Java 代码实现 KNN 六.KNN 改进策略 一.KNN 基本介绍 邻近算法,或者说K最邻近(K ...

  8. kdtree java_Java中的KDTree实现

    这是KD树的完整实现,我已经使用了一些库来存储点和矩形.这些库免费提供.我可以用这些类来做你自己的类来存储点和矩形.请分享您的反馈. import java.util.ArrayList; impor ...

  9. java.beans.transient_@Transient注解的使用(不被序列化和作为临时变量存储)

    java 的transient关键字的作用是需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中. trans ...

最新文章

  1. 2010年9月14日佛山大沥机楼网络故障日志
  2. 【Spring】Bean的生命周期
  3. 产品开发专业认证_食品招生季食品科学与工程专业介绍
  4. pmp每日三题(2022年3月2日)
  5. HDU - 5394 Trie in Tina Town(回文自动机+字典树)
  6. c++ reference counting引用计数原理
  7. php stdin是什么意思,php:// input和php:// stdin之间有什么区别?
  8. 【Android游戏开发十一】手把手让你爱上Android sdk自带“9妹”
  9. 2012年5月份第2周51Aspx源码发布详情
  10. python logging模块使用教程
  11. Disruptor本地线程队列_实现线程间通信---线程间通信工作笔记001
  12. Eclipse如何新建TOMCAT并配置Server Locations和Publishing属性
  13. hadoop中的序列化和反序列化
  14. 用Unity简单实现第三人称人物的移动和转向
  15. 计算机编程c语言汇总,计算机软件编程中的C语言分析
  16. eclipse如何修改项目的jdr或jre版本
  17. sql server中的架构,模式,用户,角色,登录名,所有者,登录名,dbo之间的关系
  18. PC端上必应词典与金山词霸的测评分析
  19. QT之Button插入图片
  20. 从网秦安全报告看各国各城百态

热门文章

  1. html实现自动手动广告轮播,HTML+CSS+jQuery实现轮播广告图
  2. android 将数字转换为汉字
  3. 使用fastDFS上传压缩包,下载后格式有误,大乌龙
  4. 2018年世界杯赔率预测
  5. 希尔伯特-施密特独立性准则(Hilbert-Schmidt Independence Criterion-HSIC)的理解
  6. Jenkin slave 老掉线?--skb rides the rocket: 19 slots
  7. VC6.0转成VC2008可能出现的问题
  8. java实习生面试会问什么问题,大量教程
  9. 如何在 Linux 服务器上更改分区方案?
  10. Django项目-商品详情页