full-text-searchxqueryintersectionmarklogiccts-search

Intersect search:search result set with cts:search result set that used cts:polygon geospatial search


I had to add geo-spatial search capability to an already existing app which uses search:search API and has full text search and faceted search. I've read about Extending the Search API, but I just don't have the time right now. So, I thought I will adapt my code in order to just do an intersection of the two result sets (one returned by the search:search API and the other returned by the cts:search that allows cts:polygon search). Unfortunately the intersection degrades heavily the execution time. Is there a better way to optimize or speed up the following expression bellow?

$results_fts//search:result[./search:metadata/Vhe eq $geo_results//root/Vhe]

Here is my code:

declare variable $geo_results := 
let $qr := cts:search(doc(), cts:and-query(($q-geospatial,
            cts:word-query("*", ("case-insensitive","whitespace-insensitive","wildcarded","diacritic-insensitive"))   ))   )  (:Search all * within the polygon:)
return $qr;

declare variable $results_fts := 
let $qrs := search:search($q-text, $options, xs:unsignedLong(xdmp:get-request-field("start","1")), 12000)  (:max page length to get all records:)
return $qrs;

declare variable $results := 
let $qrt := if (xdmp:get-request-field("map-code")) then 
(:intersect geospatial search with the full text search:)
                <search:response>
                  { $results_fts//search:result[./search:metadata/Vhe eq $geo_results//root/Vhe] } 
                  { $results_fts//search:facet }
                  { $results_fts//search:qtext }
                  { $results_fts//search:metrics }
                </search:response>
          else $results_fts
return $qrt;

Solution

  • As a footnote to Dave's good advice, another alternative would be to use search:parse() instead of search:search() to convert the second search request to a cts:query before running the cts:search().

    http://docs.marklogic.com/search:parse?q=search:parse&v=8.0&api=true

    Then, add the cts:query() generated search:parse() to the list of subqueries within the existing cts:and-query() and run a single search.

    It's not clear to me what the cts:word-query("*") clause within the geospatial query is doing, but that's unrelated to the main point.