我正在开发一个基于XQuery的库,用于从GPS文件中获取简单的地理空间信息(称为GPXQuery,可在GitHub上获得)。GPX文件通常包含GPS坐标轨迹,并且可能非常大。我的最大测试文件包含20,000个点。GPX非常简单:
<gpx version="1.1" xmlns="http://www.topografix.com/GPX/1/1">
<trk>
<name>Berkeley Test Walk #1</name>
<trkseg>
<trkpt lon="-122.26794633083045" lat="37.878523925319314">
<ele>78.4000015258789</ele>
有一长串的<trkpt>
元素,代表所有记录的GPS坐标。我希望能够处理至少100,000个,希望更多。
我的第一个稍微复杂的函数计算记录的GPS轨迹的距离。这里数学并不重要。问题是我遇到了堆栈问题。对于我的20,000个点的示例,我的标准Saxon设置已经停止了。我确信这可以通过更慷慨的内存分配来解决,但我想知道是否可能发生了更基本的事情。
我的函数应该符合尾递归优化的要求,但这有点难以判断,可能因产品而异。以下是函数,并且它们被gpxquery:trk-distance($GPX/gpx:gpx)[1]
调用,以获取给定GPX文档$GPX
中第一个GPX轨迹的距离:
module namespace gpxquery = "https://github.com/dret/GPXQuery";
declare namespace xsd = "http://www.w3.org/2001/XMLSchema";
declare namespace math = "http://www.w3.org/2005/xpath-functions/math";
declare namespace gpx = "http://www.topografix.com/GPX/1/1";
declare variable $gpxquery:earth-radius := 6371000.0;
declare function gpxquery:trk-distance($gpx as element(gpx:gpx))
as xsd:float*
{
for $trk in 1 to count($gpx/gpx:trk)
return sum(gpxquery:trk-distance-recurse($gpx/gpx:trk[$trk]/gpx:trkseg/gpx:trkpt))
};
declare function gpxquery:trk-distance-recurse($trkpts as element(gpx:trkpt)*)
as xsd:float*
{
if ( count($trkpts) le 1 )
then 0
else (
gpxquery:distance-between-points($trkpts[1]/@lat, $trkpts[1]/@lon, $trkpts[2]/@lat, $trkpts[2]/@lon) ,
gpxquery:trk-distance-recurse($trkpts[position() gt 1])
)
};
declare function gpxquery:distance-between-points($lat1 as xsd:float, $lon1 as xsd:float, $lat2 as xsd:float, $lon2 as xsd:float)
as xsd:float
{
let $dlat := ($lat2 - $lat1) * math:pi() div 180
let $dlon := ($lon2 - $lon1) * math:pi() div 180
let $rlat1 := $lat1 * math:pi() div 180
let $rlat2 := $lat2 * math:pi() div 180
let $a := math:sin($dlat div 2) * math:sin($dlat div 2) + math:sin($dlon div 2) * math:sin($dlon div 2) * math:cos($rlat1) * math:cos($rlat2)
let $c := 2 * math:atan2(math:sqrt($a), math:sqrt(1-$a))
return xsd:float($c * $gpxquery:earth-radius)
};
针对更大的文件,我是否需要在代码结构和算法方面做出不同的调整以避免这些内存问题?或者,看起来这是解决一般问题的合理方法,使用该库的人只需确保运行时环境能够处理深度嵌套递归调用的要求?
非常感谢那些使用递归函数并遇到类似问题的人提供任何反馈。