MS RFC 22A:用于长时间运行进程和查询处理的功能缓存¶
- 日期
2007/06/24
- 作者
塔玛斯塞克勒斯
- 联系方式
gmail.com上的szekerest
- 最后编辑
2007/06/24
- 状态
讨论稿
- 版本
MAPServer 5
1。概述¶
目前,各种查询操作涉及对数据提供程序的多次访问,这可能会对性能产生重大影响,具体取决于提供程序。在第一阶段,检索给定搜索区域中的所有功能,并将相关形状的索引存储在结果缓存中。在第二阶段中,结果缓存中的特性将逐个从提供程序中检索。保留内存中的形状,我们可以消除对提供者的后续访问需求,并提高查询的整体性能。实现缓存需要在数据提供程序和客户机之间转换数据。从这一方面来说,需要提供一个框架来在更高的抽象层次上实现这种转换。
2。目的¶
此RFC的主要目的是实现功能缓存,并将形状保留在内存中,以便在查询操作期间进一步检索。不过,我也希望创建一种机制,以便一个层可以使用另一个层作为数据源。这个外层可以对来自基础层的形状应用转换,甚至可以将形状保留在内存中以供后续提取。下面是一些其他示例,其中该框架将提供解决方案:
基于特征属性构造几何图形
修改几何图形或特征属性值
几何变换(如地理操作)
特征缓存
基于外部样式信息或基于属性的样式提供默认图层样式
提供自定义数据筛选器
建立一个适当的层层次结构可以解决相当复杂的问题,而不需要创建额外的(如mapscript)代码。稍后,作为一个实况示例,我将展示以下场景的解决方案:
用户将在一个层中选择一个或多个形状(在本例中,按属性选择)。
层叠转换将应用于所选形状(我将使用geos converxfull和buffer操作)
在另一层中,将根据转换后的形状选择特征作为选择形状。
在这个建议中,为了确保更好的可读性,我将避免将大部分代码嵌入到内联中。然而,大多数实现补丁都可以在这个RFC的跟踪标签上找到(见下文)。
三。解决方案的一般原则¶
这个提议涉及到编写额外的数据提供者。这些提供者将使用另一个层作为特性的源。要设置层的层次结构,这些层的连接参数将包含源层的名称。在某些情况下,源层不参与渲染,应保持在原始层内部。因此,我们将建立将层嵌套到彼此中的支持。在这方面,连接参数将包含它所引用的层的完整路径。路径包含层次结构中的层名称,使用斜线“/”作为名称之间的分隔符。我们可以指定相对于实际图层或相对于地图本身的路径名。
指定相对于地图的引用:
LAYER
NAME "roads"
CONNECTIONTYPE OGR
CONNECTION "roads.tab"
...
END
LAYER
NAME "cache"
CONNECTIONTYPE CACHE
CONNECTION "/roads"
...
END
指定相对于外层的参照
LAYER
NAME "cache"
CONNECTIONTYPE CACHE
CONNECTION "roads"
...
LAYER
NAME "roads"
CONNECTIONTYPE OGR
CONNECTION "roads.tab"
...
END
END
这两个选项之间的主要区别在于,在第一种情况下,引用的图层包含在地图的图层集合中,因此图层将参与到图形中。在第二种情况下,参考层位于外层的内部。支持两个或多个层连接到同一个基础层,以便从同一个缓存存储库提供功能。基础层可以位于层层次的任何位置。
在任何情况下,扩展层也可以实现为可插拔的外部层。(ConnectionType插件)
为了实现所需的功能,将实施以下3个供应商:
3.1功能缓存提供程序¶
此提供程序的目的是将源层中的功能保留在内存中,以便从内部缓存提供对功能缓存提供程序的后续提取。在当前的实现中,我计划保留最后一个方面的形状。当后续的形状检索引用相同的范围(或在该范围内)时,将从缓存提供功能。目前,我不会处理来自多个不重叠扩展数据块的缓存功能,也不会实现更复杂的缓存管理(如大小限制/到期处理),但它可能是将来增强的对象。所有特定于提供程序的数据都将放置在提供程序的layerInfo结构中。缓存中的形状将存储在哈希表中。此提供程序将在单独的文件(mapcache.c)中实现。
3.1.1形状检索选项¶
此提供程序将能够使用给定范围内的所有形状或仅使用源层的resultcache中的形状填充缓存。第一个是默认选项,后者可以通过以下处理指令选择:
PROCESSING "fetch_mode=selection"
当给定的rect超出前一个rect时,将根据缓存提供程序的whichshapes调用填充缓存。我们还可以指定,无论搜索区域如何,提供者都将使用以下设置重新提取当前地图范围的所有形状:
PROCESSING "spatial_selection_mode=mapextent"
3.1.2项目选择¶
功能缓存提供程序将存储所有可用的项目,而不管从外部选择了哪些项目(通过使用which items调用)。但是,iteminfo将只包含请求项的索引。getshape和nextshape操作将只将请求的项目子集复制到调用方。此解决方案将提供与任何其他现有提供程序的兼容性,因此无需从这一方面更改公共MapServer代码。
3.1.3支持样式项“auto”选项¶
通过使用样式项“auto”选项,提供程序可以从数据源中检索每个shapeobj的classobj。为了继续支持此选项,缓存提供程序将能够在单独的哈希表中缓存这些classobj-s以及shapeobj-s。当在功能缓存提供程序上设置了样式项“auto”选项时,也将通过将getautostyle函数调用到源层来填充样式缓存。功能缓存提供程序上的后续getautostyle调用将从样式缓存中检索Classobj-s,并向调用者提供一个副本。
3.1.4支持属性过滤器¶
功能缓存提供程序将与现有查询操作兼容(在mapquery.c中的msqueryby[]函数中实现)。为了支持msquerybyattributes,nextshape将在将形状返回给调用方之前使用msevelExpression。
3.2几何变换提供者¶
几何转换提供程序(在mapgeomtrans.c中实现)将支持对源层的透明访问。每个vtable操作将被调度到源层的相应vtable操作。此外,某些其他层属性可能需要在连接的层之间进行复制。
3.2.1项目选择¶
此提供程序将与源层提供的项目子集相同。因此,initeminfo将把外部层的items和numitems复制到源层,例如:
int msGeomTransLayerInitItemInfo( layerObj *layer )
{
/* copying the item array an call the subsequent InitItemInfo*/
return msLayerSetItems(((GeomTransLayerInfo*)layer->layerinfo)->srclayer, layer->items, layer->numitems);
}
在getitems调用时,这些值将被复制回外部层,如:
int msGeomTransLayerGetItems(layerObj *layer)
{
/* copying the item array back */
int result;
GeomTransLayerInfo* layerinfo = (GeomTransLayerInfo*)layer->layerinfo;
result = msLayerGetItems(layerinfo->srclayer);
msLayerSetItems(layer, layerinfo->srclayer->items, layerinfo->srclayer->numitems);
return result;
}
3.2.2应用转换¶
提议的实现将支持MapServer支持的大多数GEO转换(buffer、converxfull、boundary、union、intersection、difference、symdifference)。转换将在将形状检索到调用方之前应用。可以使用处理选项选择所需的转换,例如:
PROCESSING "transformation=buffer"
一些转换将接受进一步的参数:
PROCESSING "buffer_width=0.2"
其中一些操作将使用两个形状来创建转换后的形状。这些转换的引用形状可以使用处理选项的wkt表示法从外部设置:
PROCESSING "ref_shape=[WKT of the shape]"
我还计划支持从层的特性集合和外部层中检索此形状。
3.3层过滤器提供程序¶
层筛选器提供程序(在mapfilter.c中实现)将提供从源层检索到的形状,并且不会对此应用任何转换。但是,根据空间和属性选择选项,在下一个形状操作中将跳过某些形状。此提供程序确保对源层(与前一层一样)的透明访问,但使用缓存存储选择形状。将从另一层检索选择形状,该层可以在以下处理选项中指定:
PROCESSING "selection_layer=[path to the layer]"
在填充选择缓存时,我将支持检索结果缓存中的所有形状或仅检索结果缓存中的形状,就像前面提到的缓存提供程序一样:
PROCESSING "fetch_mode=selection"
4。把东西放在一起(例子)¶
在本章中,我将描述前面提到的场景的解决方案。我将从一个简单的 Mapfile 定义开始,其中包含两层国家和城市点:
MAP
NAME "Hungary"
STATUS ON
EXTENT 421543.362603 47885.103526 933973.563202 367180.479761
SIZE 800 600
IMAGETYPE PNG
IMAGECOLOR 255 255 255
PROJECTION
"proj=somerc"
"lat_0=47.14439372222222"
"lon_0=19.04857177777778"
"x_0=650000"
"y_0=200000"
"ellps=GRS67"
"units=m"
"no_defs"
END
SYMBOL
Name 'point'
Type ELLIPSE
POINTS
1 1
END
FILLED TRUE
END
LAYER
PROJECTION
"AUTO"
END
NAME "Hun_Counties"
CONNECTIONTYPE OGR
CONNECTION "Hun_Megye.TAB"
STATUS default
TYPE POLYGON
LABELITEM "name"
CLASS
TEMPLATE "query.html"
LABEL
SIZE medium
COLOR 64 128 64
END
STYLE
COLOR 208 255 208
OUTLINECOLOR 64 64 64
END
END
END
LAYER
PROJECTION
"AUTO"
END
NAME "Hun_CityPoints"
CONNECTIONTYPE OGR
CONNECTION "Hun_CityPoints.TAB"
STATUS default
TYPE POINT
CLASS
STYLE
COLOR 255 0 0
SYMBOL "point"
SIZE 2
END
END
END
END
此地图将如下所示:
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample.png
4.1添加层的功能缓存¶
任何层都可以使用缓存层提供程序进行缓存。原始提供程序可能嵌套在缓存中。应为外层指定与图纸相关的参数,如:
LAYER
PROJECTION
"AUTO"
END
NAME "Hun_Counties_cache"
CONNECTIONTYPE CACHE
CONNECTION "Hun_Counties"
STATUS default
TYPE POLYGON
LABELITEM "name"
CLASS
TEMPLATE "query.html"
LABEL
SIZE medium
COLOR 64 128 64
END
STYLE
COLOR 208 255 208
OUTLINECOLOR 64 64 64
END
END
LAYER
PROJECTION
"AUTO"
END
NAME "Hun_Counties"
CONNECTIONTYPE OGR
CONNECTION "Hun_Megye.TAB"
TYPE POLYGON
END
END
Hun_Counties_缓存层是可查询的,所有现有方法都可用于填充ResultCache。在我的示例中,我将使用mapscript c drawquery示例(在drawquery.cs中实现)来执行属性查询,然后使用drawquery。以下命令将与此示例一起使用:
drawquery sample.map "('[Name]'='Tolna')" sample.png
它将(“[名称]”=“tolna”)查询字符串传递给第一层的queryByAttributes。
渲染的结果如下:
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample1.png
在这里可以找到相应的 Mapfile :
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample1.map
4.2对县实施改造¶
在下一步中,我将在第一层应用层叠的geos converxfull和buffer操作。将使用以下定义在单独的层中呈现结果:
LAYER
NAME "selectionshape"
CONNECTIONTYPE GEOMTRANS
CONNECTION "simplify"
STATUS default
TYPE POLYGON
TRANSPARENCY 50
CLASS
STYLE
COLOR 64 255 64
OUTLINECOLOR 64 64 64
END
END
PROCESSING "transformation=buffer"
PROCESSING "buffer_width=0.2"
LAYER
NAME "simplify"
TYPE POLYGON
CONNECTIONTYPE GEOMTRANS
CONNECTION "/Hun_Counties_cache"
PROCESSING "transformation=convexhull"
END
END
渲染的结果如下:
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample2.png
对应的 Mapfile :
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample2.map
这不是所期望的结果,因为所有的多边形都被转换了。为了仅转换所选形状,应使用“fetch_mode=selection”处理选项指定附加缓存:
LAYER
NAME "selectionshape"
CONNECTIONTYPE GEOMTRANS
CONNECTION "simplify"
STATUS default
TYPE POLYGON
TRANSPARENCY 50
CLASS
STYLE
COLOR 64 255 64
OUTLINECOLOR 64 64 64
END
END
PROCESSING "transformation=buffer"
PROCESSING "buffer_width=0.2"
LAYER
NAME "simplify"
TYPE POLYGON
CONNECTIONTYPE GEOMTRANS
CONNECTION "selectioncache"
PROCESSING "transformation=convexhull"
LAYER
NAME "selectioncache"
TYPE POLYGON
CONNECTIONTYPE CACHE
CONNECTION "/Hun_Counties_cache"
PROCESSING "fetch_mode=selection"
END
END
END
这是图纸的结果:
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample3.png
对应的 Mapfile :
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample3.map
4.3将转换后的形状作为选择形状¶
我的最终目标是选择点图层的特征,使用转换后的形状作为选择形状。因此,我必须在点图层上使用图层过滤器提供程序,并将选择图层设置为转换图层:
LAYER
TYPE POINT
CONNECTIONTYPE LAYERFILTER
CONNECTION "Hun_CityPoints"
NAME "selectedpoints"
STATUS default
PROCESSING "selection_layer=/selectionshape"
CLASS
STYLE
COLOR 255 0 0
SYMBOL "point"
SIZE 2
END
END
LAYER
PROJECTION
"AUTO"
END
NAME "Hun_CityPoints"
CONNECTIONTYPE OGR
CONNECTION "Hun_CityPoints.TAB"
TYPE POINT
END
END
结果如下:
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample4.png
对应的 Mapfile :
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample4.map
注1:在不改变地图配置的情况下,我可以从外部修改选择,渲染的图像将自动反映更改。例如,我可以使用查询字符串选择2个县:('[name]='tolna'或'[name]='baranya')
结果图像可以在这里找到:
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample4a.png
注2:如果不需要呈现选择层,我可以直接指定配置:
LAYER
TYPE POINT
CONNECTIONTYPE LAYERFILTER
CONNECTION "Hun_CityPoints"
NAME "selectedpoints"
STATUS default
PROCESSING "selection_layer=selectionshape"
CLASS
STYLE
COLOR 255 0 0
SYMBOL "point"
SIZE 2
END
END
LAYER
PROJECTION
"AUTO"
END
NAME "Hun_CityPoints"
CONNECTIONTYPE OGR
CONNECTION "Hun_CityPoints.TAB"
TYPE POINT
END
LAYER
NAME "selectionshape"
CONNECTIONTYPE GEOMTRANS
CONNECTION "simplify"
STATUS default
TYPE POLYGON
TRANSPARENCY 50
CLASS
STYLE
COLOR 64 255 64
OUTLINECOLOR 64 64 64
END
END
PROCESSING "transformation=buffer"
PROCESSING "buffer_width=0.2"
LAYER
NAME "simplify"
TYPE POLYGON
CONNECTIONTYPE GEOMTRANS
CONNECTION "selectioncache"
PROCESSING "transformation=convexhull"
LAYER
NAME "selectioncache"
TYPE POLYGON
CONNECTIONTYPE CACHE
CONNECTION "/Hun_Counties_cache"
PROCESSING "fetch_mode=selection"
END
END
END
END
结果如下:
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample5.png
以及相应的 Mapfile :
http://trac.osgeo.org/mapserver/attachment/ticket/2128/sample5.map
回想一下,因为我在Countries层上使用了缓存,所以所有这些渲染都只需要从原始提供者那里检索一次形状。这是这个RFC的主要目标。
5。修改MapServer核心¶
要实现所需的功能性,应在MapServer核心中执行以下主要步骤。建议更改的详细信息可在此处找到:
http://trac.osgeo.org/mapserver/attachment/ticket/2128/common.patch
5.1哈希表实现¶
当前的哈希表实现(在maphash.c中)将被概括为能够存储对象和字符串。当前哈希表只能存储字符串值。此外,我们还将在构造哈希表时提供指定哈希大小的支持。对象将被引用存储在哈希表中,对象的销毁功能也可以在外部指定。以下函数将添加到maphash.c中
int initHashTableEx( hashTableObj *table, int hashSize );
void msClearHashItems( hashTableObj *table );
struct hashObj *msInsertHashTablePtr(hashTableObj *table, const char *key, const char *value);
struct hashObj *msFirstItemFromHashTable( hashTableObj *table);
struct hashObj *msNextItemFromHashTable( hashTableObj *table, struct hashObj *lastItem );
int msGetHashTableItemCount(hashTableObj *table);
可以调用initHashTableEx以在外部指定哈希大小。实际上,原始的inithashtable将实现为使用ms_hashsize调用inithashtableex。msclearhashitems将清除哈希表的所有元素,但不清除items数组。msinserthashtableptr提供通过引用哈希表添加对象的支持。msfirstitemfromhashtable和msnextitemfromhashtable将有效地提供元素的迭代,并由功能缓存提供程序的nextshape调用。msgethashtableitemcount将检索哈希表项的实际数目。
5.2扩展layerobj结构以支持嵌套层(map.h)¶
layerObj结构中的子层将存储为一个层数组。
typedef struct layer_obj {
...
#ifndef SWIG
struct layer_obj **layers;
int numlayers; /* number of sublayers in layer */
#endif /* SWIG */
...
} layerObj;
解析器将负责加载嵌套层:
int loadLayer(layerObj *layer, mapObj *map)
{
...
case (LAYER):
if(layer->numlayers == 0)
layer->layers = (layerObj**) malloc(sizeof(layerObj*));
else
layer->layers = (layerObj**) realloc(layer->layers, sizeof(layerObj*) * (layer->numlayers));
layer->layers[layer->numlayers]=(layerObj*)malloc(sizeof(layerObj));
if (layer->layers[layer->numlayers] == NULL) {
msSetError(MS_MEMERR, "Malloc of a new layer failed.", "loadLayer()");
return MS_FAILURE;
}
if(loadLayer(layer->layers[layer->numlayers], map) == -1) return MS_FAILURE;
layer->layers[layer->numlayers]->index = layer->numlayers; /* save the index */
++layer->numlayers;
break;
...
}
5.3添加新的内置数据连接类型(map.h)¶
为新的提供程序建立了新的数据连接类型。
enum MS_CONNECTION_TYPE {MS_INLINE, MS_SHAPEFILE, MS_TILED_SHAPEFILE, MS_SDE, MS_OGR, MS_UNUSED_1, MS_POSTGIS, MS_WMS, MS_ORACLESPATIAL, MS_WFS, MS_GRATICULE, MS_MYGIS, MS_RASTER, MS_PLUGIN, MS_GEOMTRANS, MS_LAYERFILTER, MS_CACHE };
将修改lexer以解释新的连接类型。
5.4支持销毁提供者的持久数据(map.h、maplayer.c)¶
提供程序将在该层上的各种连接/关闭操作之间保留持久性数据,因此我们应该建立一种机制,通过向layervtable添加新方法来销毁此提供程序特定的数据:
void (*LayerDestroy)(layerObj *layer);
5.5新数据提供程序的vtable初始化(maplayer.c)¶
int
msInitializeVirtualTable(layerObj *layer)
{
if (layer->baselayer)
msInitializeVirtualTable(layer->baselayer);
...
switch(layer->connectiontype) {
...
case(MS_GEOMTRANS):
return(msGeomTransLayerInitializeVirtualTable(layer));
break;
case(MS_LAYERFILTER):
return(msFilterLayerInitializeVirtualTable(layer));
break;
case(MS_CACHE):
return(msCacheLayerInitializeVirtualTable(layer));
break;
...
}
..
}
6。受影响的文件¶
以下文件将受此RFC的影响:
maphash.c
maphash.h
maplayer.c
maplexer.l
mapfile.c
map.h
Makefile.vc
Makefile.in
mapcache.c (new)
mapgeomtrans.c (new)
mapfilter.c (new)
7。向后兼容性问题¶
这些更改将保持mapfile和mapscript向后兼容性。
9。投票历史¶
没有