Created
June 4, 2019 13:43
-
-
Save prestonmcgowan/3dd7d7d59216f705e6d7f2b16522df5a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
xquery version "1.0-ml"; | |
(: Configurable variables :) | |
declare variable $initial-radius := 1; (: miles :) | |
declare variable $radius-step := 5; (: miles :) | |
declare variable $radius-max := 100; (: miles :) | |
declare variable $total-matches := 1; | |
declare variable $lat-long-element-container := "FacilitySite"; | |
declare variable $lat-element := "LatitudeMeasure"; | |
declare variable $lon-element := "LongitudeMeasure"; | |
(: Variables used for state :) | |
declare variable $radius-not-found := -9999; | |
(: --- The code --- :) | |
(: WARNING: If a search does not match the total-matches requirement and the subsequent match matches a LARGE number of | |
: documents, the expanded tree cache could be filled and cause the order by in the bottom of the code to error out. It might make | |
: sense to write in an overload condition to catch this issue. You might be able to mitigate the issue by changing your radius-step to | |
: a smaller value. | |
:) | |
(: Geospatial search using a circle with a radius :) | |
declare function local:geo-search($radius, $point) { | |
cts:search(fn:doc(), | |
cts:element-pair-geospatial-query(xs:QName($lat-long-element-container), | |
xs:QName($lat-element), xs:QName($lon-element), cts:circle($radius, $point)) | |
) | |
}; | |
(: Return the number of matches for a given point and radius :) | |
declare function local:result-count($radius as xs:float, $point as cts:point) | |
as xs:integer { | |
xdmp:estimate( | |
cts:search(fn:doc(), | |
cts:element-pair-geospatial-query(xs:QName($lat-long-element-container), | |
xs:QName($lat-element), xs:QName($lon-element), cts:circle($radius, $point)) | |
) | |
) | |
}; | |
(: Recursive function to increase the radius until a satisfying radius has been found or radius-not-found :) | |
declare function local:expanding-radius-search($radius, $point) { | |
let $count := local:result-count($radius, $point) | |
return | |
if ($count >= $total-matches) then $radius | |
else | |
let $new-radius := $radius + $radius-step | |
return | |
if ($new-radius <= $radius-max) then | |
local:expanding-radius-search($new-radius, $point) | |
else | |
$radius-not-found | |
}; | |
(: Change these values to change where you are starting your search :) | |
let $point-lat := 37.557151 | |
let $point-lon := -122.4313 | |
(: The main module code :) | |
(: Note: if the lat, lon elements have namespaces, the xdmp:value below needs to be changed to xdmp:with-namespaces :) | |
let $point := cts:point($point-lat, $point-lon) | |
let $radius := local:expanding-radius-search($initial-radius, $point) | |
return | |
if ($radius eq $radius-not-found) then | |
"No documents found" | |
else | |
let $matches := | |
for $doc in local:geo-search($radius, $point) | |
order by cts:distance($point, | |
cts:point(xdmp:value(fn:concat("$doc//", $lat-element)), xdmp:value(fn:concat("$doc//", $lon-element))) | |
) | |
return $doc | |
return (text {"Radius used:", $radius}, $matches[1 to $total-matches] ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment