两年前我写过一篇关于ArcGIS地图切图/缓存原理的文章,《ArcGIS Server的切图原理深入》,里面以tiling scheme为主,讲了缓存图片的存储结构以及相关坐标的计算。那时还是ArcGIS 9.3版本,现在ArcGIS 10已经推出快一年多了,地图缓存/切图方面有了很大改进,比如增加了compact缓存格式,增加了import/export map server cache工具,增加了mixed图片模式等。这次就在上篇文章的基础上,以ArcGIS 10为例,看看其中地图切图/缓存制作的工作机制。
注:本文旨在深入了解ArcGIS目前切图(即制作地图服务的缓存)的机制,以帮助工作中有需要的朋友们提高工作效率,因为切图,尤其是大比例尺,耗时耗资源,实在是一件伤不起的工作。这里已经假设你知道了如何为缓存地图服务配置地图,如何检查发布地图服务的地图文档的性能,开始动手前务必进行小范围、全比例尺切图试验等等注意事项,如否,请查阅相关资料。
supertile和bundle
要深入了解ArcGIS在切图时的工作机制,有两个概念必须明白,就是supertile和bundle。
假设一个tile(切片)的大小是256*256,在切图时如果按照这个大小直接exportmap,开启了动态标注的地图服务上线图层和面图层就会有很多重复的标注。因为exportmap时,每个tile都会包含一个要素的标注,如果一个要素横跨了多个tile(这在大比例尺下基本是肯定的),那么这些tile上就会出现相同的标注,exportmap时并不知道相邻的tile上已经有了该要素的标注。
为了解决这个问题,ArcGIS在切图时引入了supertile的概念,开启抗锯齿时supertile大小为2048*2048,反之为4096*4096。真正切图时会首先exportmap出一个supertile,然后将它们分割成指定大小的tile。对于每个要素,每个supertile中只包含一次标注,这样保证一个superfile大小的范围内不会出现重复标注。事实上在绘制supertile时,会尽可能多地包含周围的标注,所以在每个supertile的边界周围仍会有重复标注。解决重复标注的根本办法就是使用annotation,而不是label。
ArcGIS 10中推出了新的compact缓存格式,将原来离散的每个tile图片(exploded格式),保存成连续的二进制文件(.bundle),每个.bundle文件最多可存储128*128个tile。相比以前成千上万的tile文件,这样做有明显的好处:易于缓存迁移,减少占用磁盘空间,减少硬盘i/o等,esri在任何时候都推荐使用compact格式来创建缓存,除非你需要自己读取每个tile(技术上来说这点可以不成立)。ArcGIS 10在切图时,也采用了bundle的概念:对于每一级比例尺,首先从tiling scheme origin开始,将切图范围分成若干个bundle,每个bundle覆盖的范围是128*128个tile大小。比如在1:4096比例尺时,如果tile大小是256*256,DPI为96,那么每个bundle范围的大小是:((4096*2.54/96)/100/1000*256*128)^2=1261.086平方千米。之后,有且仅有(这么做是为了避免多个进程同时读写一个磁盘文件)一个服务实例/一个arcsoc.exe进程(如果是high isolated)来负责此bundle范围的切图,先输出supertile,然后再切成tile。即使选择了exploded缓存格式,ArcGIS 10中也会采用这种机制来切图。
9.3.1及以前版本中,每个服务实例工作的单位是supertile。即一个arcsoc.exe负责生成一个supertile,然后切成tile,再继续生成下一个supertile……相比supertile这种处理单位来说,采用bundle作为处理单位的ArcGIS 10中的服务实例可以将更多精力投入到连续切图中去,而不是频繁切换自己负责的范围。在大比例尺切图中,这种新机制能很大程度上减少切图时间;但在小比例尺切图中,这种新机制有可能反而增加切图时间。因为小比例尺时可能全图范围只有不到一个bundle范围大小,这样只会有一个服务实例来切图,其他实例都处于空闲状态,而9.3.1及以前版本中,所有服务实例都会“蜂拥而上”。
网格切图和按featureclass范围切图
有过大比例尺范围切图经验的朋友肯定会知道,一般切图策略是:小比例尺全图直接切,较小比例尺可能按照某个featureclass范围来切,而大比例尺一般是按照包含网格(grid)的featureclass范围来切。以我国全范围切图为例,小比例尺时全图切没有问题,大比例尺时如果仍然全图范围(包络矩形)切的话,会将周边其他的国家也包含进来,这并不需要的额外工作量在大比例尺时会是一场噩梦。
而之所以不仅要按指定featureclass范围切图,而且featureclass里要包含网格的原因在于,便于细化和跟踪切图进度。切图工具会给你指定的featureclass创建一个新的Cached字段,将已经切好的feature标记为YES,以便在选择Recreate Empty Cache时避免重复切图,从而可以将切图工作分为多次来进行,或者以便在切图失败后排查原因,继续切图工作。
在指定featureclass范围切图时,是顺序处理该featureclass中的所有feature的。所有的服务实例会首先集体处理一个feature范围,切出该feature范围内所有要求的比例尺级别的结果。此时ArcGIS Server会重启该服务。然后所有服务实例再去切下一个feature范围……所以与每个feature边界相交的supertile可能会被创建两次或多次(多个feature的相交处),这也是为什么在使用featureclass切图前,需要分别对它进行Generalize,Aggregate和Dissolve的原因。
结合之前bundle的机制我们知道,如果一个feature范围恰好只包含一个bundle,那么就杯具了,因为对该feature切图时,只会有一个服务实例进行工作(一个bundle同时由且仅由一个服务实例处理),其他服务实例全部处于空闲状态。因此,比较理想的情况是,每个feature至少包含比服务实例数更多的bundle时,才能充分利用硬件资源来对其切图。
这就会引出一个问题,就是如何来确定某个比例尺下一个bundle的大小,从而生成这样的featureclass呢?ArcGIS 10中,给我们提供了一个新的GP工具Map Server Cache Tiling Scheme To Polygons,利用它,我们可以针对某个地图服务,生成每个需要切图比例尺下所有的supertile,进而得到以每个supertile为一个feature的featureclass。以全国地图为例,在1:288,895比例尺(ArcGIS Online Tiling Scheme的第12级)下生成的supertile是这样的:
我们需要的是某个比例尺下bundle的范围,如何根据supertile来确定bundle的大小呢?在N级比例尺时,一个supertile是16*16个tile,第N+1级比例尺时,该supertile会覆盖32*32个tile,第N+2级比例尺时,覆盖64*64个tile,第N+3级比例尺时,这个第N级的supertile会覆盖128*128个tile,眼熟吧,这正是一个bundle的大小。由于supertile和bundle都是从tiling scheme origin往右下角算起的,因此第N级一个supertile的范围正是第N+3级一个bundle的范围。由此如果我们要生成第15级的bundle网格,只需要用Map Server Cache Tiling Scheme To Polygons工具生成第12级supertile的网格即可,如上图。
以此为例,我们来说明如何有效进行大比例尺切图的问题。假设我们需要对1:36,111(ArcGIS Online Tiling Scheme的第15级)这个比例尺进行切图,我们首先生成该范围的bundle网格,恰好是第12级的supertile网格,如上图。为了简便起见,我们只取其中8个feature来做说明,地图服务的最大实例数是4个(机器是单cpu,4核)。如果每个feature恰好是一个bundle,那么一个feature只能被一个arcsoc.exe处理,而其他3个服务实例均处在空闲状态(占用内存最少的那个arcsoc.exe是用来清空工作目录的,与具体服务无关):
而我们对这个featureclass做一个处理,将4个feature(恰好是一个bundle)合并成一个feature(bundle cluster),这样每个feature就恰好包含了4个bundle,如此我们所开启的4个服务实例就可全速工作了,发挥了机器的最大性能:
ps:Map Server Cache Tiling Scheme To Polygons工具生成的supertile是从tiling scheme origin开始计算的,而不是地图服务的fullextent左上角,因此利用它生成的supertile合并出来的bundle是最合理的,恰好与理想的bundle分界处一致。因此在大比例尺下利用featureclass切图时,应当利用Map Server Cache Tiling Scheme To Polygons来生成网格,而不是fishnet工具。在ArcGIS 10.1中,将会推出新的GP工具,会根据cpu核数来生成合理的包含bundle cluster大小feature的featureclass。
其他方面还有一些问题,比如切图时最大服务实例数设置多少为好(一般是cpu核数+1),即使所有实例全部工作cpu占用率依然低于90%(有可能是内存不足)等问题,与切图机制无关,就不在此讨论了。
总之,切图是一个技术活,要求还比较高,需要考虑的问题很多。如果你只把它当一项体力活来看的话,只能说明认识还不够全面,那就不能怪ArcGIS Server不好。毕竟,人家ArcGIS Online全球的19级缓存都7*24小时上线两年了,还有什么理由说产品不好呢?