背景技术
栅格数据是指按网格单元的行与列排列、具有不同灰度或颜色的阵列数据。其结构是大小相等分布均匀、紧密相连的像素(网格单元)阵列来表示空间地物或现象分布的数据组织,是最简单、最直观的空间数据结构。它将地球表面划分为大小、均匀、紧密相邻的网格阵列。每一个象素的位置由它的行列号定义。
GIS行业中,遥感、航测等直观反映地物地貌的影像数据(比如IMG,GRID,JPG,TIFF等文件格式),就属于栅格数据的一种。可以是数字航空照片、卫星影像、数字图片,甚至可以是扫描的地图。这些文件的格式虽然不同,但它们都可以相互转换。在实际应用中有以下几个方面:
栅格数据用作地理底图:在GIS中,航空摄影、卫星影像和扫描地图的正射影像这些栅格数据,常作为其他图层的背景,用来显示真实的对象。
栅格数据用作地形图:栅格数据非常适于表示随地形(地表)连续变化的数据。它们提供了一种将连续性数据存储为地表的有效方法。而且,还可以提供一种间隔均匀的地表表示法。自地球表面测量的高程值是地形图最常见的应用,但是其他值,如降雨量、温度、浓度、人口密度也可用于定义可进行空间分析的地形。
栅格数据用作专题地图:常见的应用是按土地覆盖类别对卫星影像进行分类显示。
软件技术发展到如今,已经有很多第三方的栅格数据管理模块,例如GDAL。这些栅格数据管理模块独立性强,功能全面。为避免重复开发和节约成本,市场上的GIS软件在管理栅格数据上都直接使用这些第三方模块,包括著名的ESRI的ARCGIS 9.3,Google Earth和跨平台的GRASS GIS系统。尽管这些栅格数据管理模块的应用如此广泛,而且能够很好的封装栅格数据并能够相互转换格式,但大多数情况下它被用来处理计算机硬盘上的文件格式数据。例如GDAL,尽管从1.8.0版本后,增加了处理远程计算机上栅格数据和栅格数据压缩包的功能,但本质上始终要求数据格式是文件形式。
ARCGIS对数据存储管理提供三种方式:硬盘文件,本地Access数据库和大型关系数据库。大型关系数据库涵盖市面上流行的Oracle、MS SQL Server、IBM DB2、IBMInformix、PostgreSQL,栅格数据会被转换成二进制形式存在数据表中。ARCGIS在栅格数据管理上由于使用了GDAL,虽然支持处理内存中二进制形式的栅格数据,但实现方式和处理硬盘文件的方式不同,中间需要有一个内存文件的过度。同样的数据,由于存储方式不同,而导致用多套代码去管理,会减少重用代码和增大开发量。
发明内容
本发明主要是解决现有技术所存在的存储量受限,存储成本较大,并且代码重复利用率低的技术问题;提供了一种GIS栅格数据云存储方法。该方法将栅格数据存储在云数据库中,依赖云数据库动态伸缩存储节点的能力,实现无容量上限存储栅格数据,并且通过注入的方式扩展了栅格数据管理模块的文件系统,使其具有读写云数据库的能力,保证了在二次开发方可以用同样的方式打开硬盘栅格数据文件和云数据库上的栅格数据,减少了开发量,增加了代码重用。
本发明的上述技术问题主要是通过下述技术方案得以解决的:
一种GIS栅格数据云存储方法,基于GDAL实现空间数据的转换,包括:继承GDAL的文件操作虚函数VSIFilesystemHandler类,将InstallHandler方法中的前缀osPrefix的形式参数类型改为常字符类型,接收调用函数所传递的前缀osPrefix的实际参数,如果所接收到的实际参数为空则不执行任何操作,否则将实际参数转换为字符串类型后再调用父函数的InstallHandler操作函数,其中,所述InstallHandler方法用于将类的实例注入到GDAL的实例容器中。
优化的,上述的一种GIS栅格数据的管理方法,根据不同的云数据库提供的二次开发框架或者API实现用于以流方式读写文件的IStream接口,利用所述IStream接口实现文件的读写。
优化的,上述的一种GIS栅格数据的管理方法,在存储GIS栅格数据时,按照预设的金字塔层级将原始的GIS栅格数据转换成金字塔数据文件,将金字塔数据文件切割成预定数量的数据块,建立一个数据块映射文件用于存储金字塔数据文件中不同层级的数据与各数据块之间关系的映射关系,将各数据块发送至云数据库,由云数据库存按照相应的分配规则存储于不同的存储节点;
在读取GIS栅格数据时,根据映射文件找到所需层级的金字塔数据所对应的数据块文件,在云数据库中查找并取出相应的数据块文件。
优化的,上述的一种GIS栅格数据的管理方法,在分割待保存的文件时,若待保存的文件大小为1GB以上,则将待保存的文件切割成16MB大小的若干个数据块;
若待保存的文件大小为10MB以上并且小于1GB时,则将待保存的文件切割成1MB大小的若干个数据块;
若待保存的文件大小小于10MB时,则将待保存的文件切割成255K大小的若干个数据块。
因此,本发明具有如下优点:
1.本发明将栅格数据存储在云数据库中,依赖云数据库动态伸缩存储节点的能力,实现无容量上限存储栅格数据。只要是能够正常运行的计算机就可以作为存储节点,不再有配置要求,降低了存储成本。
2.本发明通过注入的方式扩展了栅格数据管理模块的文件系统,使其具有读写云数据库的能力。保证了在二次开发方可以用同样的方式打开硬盘栅格数据文件和云数据库上的栅格数据,减少了开发量,增加了代码重用。
实施例:
本发明本质上是一个能够将栅格数据导入云数据库,并扩展所有第三方栅格数据管理模块,使其具备读写云数据库中栅格数据能力的软件模块。将栅格数据导入云数据库存储有三个目的:实现容量无上限存储、简约硬件成本的开销、提升读写效率。
1、系统结构
如图1所示,是一个云数据库集群图。图中箭头方向代表了数据的流动。集群中包含三种节点,每个节点逻辑概念上是一个服务,物理上是一个进程。
存储节点是数据真正存放的位置。一台计算机上可以部署一个存储节点,也可以部署多个存储节点(由端口号区分)。如何部署由需求决定。
配置节点负责负载均衡。根据每个存储节点的压力,决定将数据存储到哪个存储节点上。
路由节点是整个集群对外暴露连接的唯一节点。客户端连接集群时只需要知道路由节点的IP和端口,而不需要了解集群内部的部署情况。路由节点隐藏了集群细节。当集群部署发生改变时,无需通知或修改客户端。
通过动态增加存储节点,可实现容量无上限存储。通过减少存储节点,可控制硬件成本。
2、数据切割
GIS栅格数据用来描述一个范围内的影像,所以通常很大。为了达到快速读写,需要将原始数据切割成多个小的数据块存储。
栅格数据将地理空间划分成若干行、若干列,称为一个像元阵列,其最小单元称为像元或像素,每个像元的位置由行列号确定,通过单元格中的值记录这一位置属于何种地理实体或记录某一主题要素在这个位置上的数值。栅格数据的结构如图2所示。栅格数据像元基本单元的大小,对栅格数据的分辨率和计算精度起关键作用。比如一个栅格像元大小是1*1,那么一个栅格单元代表1平方米,其分辨率也是1米。栅格像元越小,影像分辨率越高,对地物的表示越精致。
浏览栅格影像数据时做的放大,缩小操作,为提高显示效率,并不是从原始文件提取像元数据重新显示,而是直接提取栅格金字塔数据。金字塔指在同一的空间参照下,根据用户需要以不同分辨率进行存储与显示,形成分辨率由粗到细、数据量由小到大的金字塔结构。影像金字塔结构用于图像编码和渐进式图像传输,是一种典型的分层数据结构形式,适合于栅格数据和影响数据的多分辨率组织,也是一种栅格数据或影像数据的有损压缩方式。
金字塔通过仅检索使用指定分辨率(取决于显示要求)的数据,可以加快栅格数据的显示速度。利用金字塔,可在绘制整个数据集时快速显示较低分辨率的数据副本。而随着放大操作的进行,各个更精细的分辨率等级将逐渐得到绘制;但性能将保持不变,因为在连续绘制更小的各个区域。数据库会根据用户的显示比例自动选择最适合的金字塔等级。如果不使用金字塔,则必须从磁盘中读取整个数据集,然后将其重采样为更小的大小。
每个栅格数据只需构建一次金字塔,之后每次查看栅格数据集时都会访问这些金字塔。栅格数据集越大,创建金字塔集所花费的时间就越长。但是,这也就意味着可以为将来节省更多的时间。金字塔结构如图3所示。
本引擎将栅格影像文件的金字塔数据,构造成和原始文件同名,但后缀不同的数据文件,也是分割成多个数据快后,存放在云数据库上。利用云数据库多个存储节点能够同时工作的优势,在做缩放操作时,快速调取金字塔的不同层,达到大数据缩放无延迟感的效果。命名上,金字塔文件和影像文件同名但不同后缀。例如原始影像文件名为507.GIF,对应的金字塔文件名为507.GIF.ovr。通过文件名称关联影像文件和金字塔文件,并实现缩放的过程,由GDAL自己实现。外部程序只需要组织文件位置。
金字塔的层级是根据文件大小来的。文件越大,像素越多,层级越多。栅格影像数据和它的金字塔,都是以文件形式存在的,同名但不同后缀。它们被存储到云数据库中,都是先切割成小的数据块存储。云数据库只负责存数据,它不关心是什么数据。所以切割的目的是为了快速读写。这些小的数据块是如何分布到各个存储节点的,是由云数据库集群的配置节点自己决定,外部不干涉,理论上数据会均匀的分布在各个存储节点上。读数据也一样,数据读取方不会关心数据真正在哪里,只需要知道数据在哪个表里。负载均衡是集群的内部细节,外部使用者不会关心。
切割时是按照文件大小切割,也和金字塔层级无关。实现大数据的无延迟缩放浏览也是基于文件快速读写,也就是体现在切割和分散存储两个方面。例如金字塔某一层数据被切到一个块里,但这个块有可能被分散存储到三个节点上。首先,三个节点同时并行工作,将数据拿到;其次,每个块是有编号的,前面文档提到过。GDAL只需要读取这一层的数据,并不需要整个金字塔文件的全部数据,所以GDAL知道这个数据段在金字塔文件中的开始和结束位置。本引擎通过这个位置,计算出块的编号。
计算机文件无论是什么形式,本质上都是二进制数据。本引擎按二进制格式读出原始栅格数据,每到一定长度时将这段数据作为一个内存块记录到数据块队列,并按先后顺序赋予一个编号。由于32位操作系统的进程容量是2GB,当数据块队列总容量超过50MB时,将队列的全部数据块写库,然后清空队列,继续读余下数据。数据块队列总容量是可以随着工作环境而调整的,默认是50MB。设置的值越大,就要消耗更多内存,但效率会高;设置越小,内存使用少,但效率会降低。
存储栅格数据的过程如图2所示,箭头方向代表数据流动方向。图2的集群部分,也包括路由节点和配置节点,由于和本流程关系不大,所以没有画出,但它们是存在的。
栅格数据的切割流程如图3所示。切割有两个目的,包括:
(1)快速读取文件:从云数据库上读取栅格数据时,多个存储节点同一时间并行工作,将各自的数据快返回给本引擎。本引擎根据数据快编号,按大小顺序拼装成一个完整的文件。相比较硬盘文件的读取,理论上,数据块的个数,就是效率的倍速。
(2)快速随机读写:随机读写是指对一个文件中的某一段数据区域进行读或写操作。本引擎可以根据要读写区域的位置,计算出其所属的数据块编号,所以参与读写操作的只是一个或多个轻量级的小数据块,而不是整个文件。通过位置除以数据块长度,可以获得编号。本引擎根据编号从存储节点上获取数据块,实现高效随机读写。
切割过程中,每一个数据块的长度是根据原始文件的大小来确定的。理论上,数据块越多,随机读写效率越高,但读取整个文件效率会降低;数据块越少,读取整个文件效率高,但随机读写效率降低。为兼顾以上两种情况,本引擎根据原始文件大小,按图4中的流程设计数据块的大小。
3、数据管理
目前市场上GIS软件用到的栅格数据管理模块,都以实现两大功能为主:提供方法在象素级别上操作影像文件和实现不同格式文件间的相互转换。它们以Windows动态连接库的形式提供给GIS软件做二次开发。动态连接库本质上是一组功能函数的集合,二次开发方通过调用这些功能函数,完成软件功能;甚至也可以调用功能函数反过来去管理,扩展动态连接库。
栅格数据管理模块用操作系统提供的API处理硬盘文件,整个读写过程由一个单独的文件模块管理。本引擎将云数据库读写过程,包装为一个文件系统的子模块。通过调用动态连接库的功能函数,注入到文件系统中,以实现文件系统能够直接处理云数据库的栅格数据,如图5所示。这种注入的方式并没有改变栅格数据管理模块处理数据的流程,只是增加了一种数据类型的分支,所以在做二次开发时,可以用同样的方式处理文件数据和云数据库存储的数据。
本发明的读写基于GDAL实现。GDAL是一个知名度非常高的开源的影像文件处理第三方库,它支持市面上常用的多种影像格式文件,并包装成统一的抽象概念数据集(DataSet),暴露给二次开发用户使用。从载入文件到获得构造好的数据集对象,这个过程可以理解为GDAL两大模块在协同工作,其一是驱动,驱动将按照不同文件格式读出文件数据,将这些数据写入数据集的成员,提供给二次开发用户使用,而这个文件读写的过程,就要依靠另一模块,虚拟文件系统。
影像文件的位置和形态是多样的,它可能就存放在本机某个磁盘上,也可能被放在某个远程机器上;它可能是jpg文件,也可能被做成了压缩文件。而压缩文件也可能是rar或者是7zip。为统一处理这些状况,GDAL声明虚拟文件系统管理类:VSIFileManager。下面是类的声明:
VSIFilesystemHandler是个抽象类,定义了一些文件操作的虚函数。具体将在下一节说明,现在只需要知道所有文件操作类的父类,都是VSIFilesystemHandler。
poDefaultHandler是GDAL用windows API实现的本地文件读写类的实例,作为默认文件操作对象。oHandlers这个容器管理除本地文件外,其他虚拟文件操作类的实例。目前GDAL支持的虚拟文件包括远程文件,压缩文件和内存文件。
InstallHandler将载入一个虚拟文件操作类的实例。
到此,可以明确Mongodb文件系统注入GDAL虚拟文件系统的大致思路了:继承一个VSIFilesystemHandler类,在操作文件之前,调用InstallHandler,将类的实例注入到oHandlers容器中,这样就能够在不改变GDAL运行机制的前提下,实现对远程分布式数据库文件的读写操作。
VSIFilesystemHandler做为所有文件操作的抽象基类,它实际上主要管理文件流属性和文件夹相关操作,具体文件的读写在VSIVirtualHandle这个抽象类中实现。VSIFilesystemHandler和VSIVirtualHandle在GDAL源代码cpl_vsi_virtual.h中声明。
声明CMongoFilesystemHandle和CMongoHandle两个类,分别继承实现VSIFilesystemHandler和VSIVirtualHandle,如图8所示。
GGMongoDatabase是一个COM组件,专门实现对分布式数据库文件读写。
CMongoFilesystemHandle负责实例化CMongoHandle,CMongoHandle调用GGMongoDatabase组件,实现具体的读写操作。
整个文件操作过程如图9所示。GGMongoDatabase组件定义文件流IStream接口,实现对文件的流式读写。
GDAL作为普通windows动态库对外暴露方法,虽然InstallHandler可以被调用,但前缀声明为标准库的string类型,debug下调用会有问题。每个VS版本对标准库的实现都不一样,再加上标准库实现过程中用到静态成员,动态库暴露方法的参数一直避免使用标准库类型。所以这里要新增一个InstallHandler方法,将string类型改为const char*。修改VSIFilesystemHandler类,红色代码为新增,如下:
物理形式上,CMongoFilesystemHandle和CMongoHandle是类,都有各自的头文件和cpp文件。GGMongoDatabase是COM组件,是一个DLL文件,通过接口对外暴露方法。CMongoFilesystemHandle管理(包含)CMongoHandle,CMongoHandle管理(包含)GGMongoDatabase。修改第三方库的源代码应该避免,但此处修改是必要修改,否则无法实现注入。而且只增加了代码,没有修改或删除。但无论如何,在做GDAL版本升级时,这个地方要特别注意。
CMongoHandle,CMongoFilesystemHandle这两个类是继承实现了GDAL的虚拟文件系统的抽象类,为的是能够将云数据库读写功能注入到GD虚拟文件系统中,那么真正实现远程分布式数据库读写功能的另外一个COM组件:GGMongoDatabase。
由于数据是二进制存储,所以GGMongoDatabase组件暴露接口IStream,提供流式读写数据。那么GDAL的虚拟文件系统的抽象类的一个虚方法,在IStream接口上就有一个接口方法对应。
例如当GDAL的虚拟文件系统的open(打开文件)方法被调用后的流程如图10所示,当GDAL的虚拟文件系统的read(读文件)方法被调用后的流程如图11所示。
由于在打开文件时CMongoFilesystemHandle返回了CMongoHandle实例,所以后续文件操作直接作用在CMongoHandle身上,CMongoHandle再调用其管理的GGMongoDatabase的IStream接口方法,完成文件读写过程。其他对应的方法包括
写入:
CMongoHandle::Write对应IStream::Write
设置当前位置:
CMongoHandle::Seek对应IStream::Seek
获得当前位置:
CMongoHandle::Teel对应IStream::get_Position
关闭文件并提交数据:
CMongoHandle::Close对应IStream::Commit
GGMongoDatabase组件的IStream接口相关实现方法,要根据不同的云数据库提供的二次开发框架或者API。不同的数据库产品提供的二次开发API都不同,但这个思路是不变的。
接口和组件的关系就是抽象和具体的关系。接口只有一个,组件可以有多个。例如现在要实现云数据库A和B两个产品的读写功能,那么就要实现GGMongoDatabaseA和GGMongoDatabaseB两个组件,但是它们有共同的接口IStream。这也保证了即使实现发生改变,但组件调用方保证代码不变。
本文中所描述的具体实施例仅仅是对本发明精神作举例说明。本发明所属技术领域的技术人员可以对所描述的具体实施例做各种各样的修改或补充或采用类似的方式替代,但并不会偏离本发明的精神或者超越所附权利要求书所定义的范围。