Hi Günter,
Interesting one. It seems that there are cases in which the sliding 'let' clauses will slow down execution time; see [1]. I’ll first need to decide for better heuristics before I’ll "fix" this.
In the meanwhile, please note that the full-text index (if it exists) will not be utilized by your second query. It may seem contra-intuitive, but your query will probably be executed faster if you apply the search condition twice:
let $query := "Paris" for $city in doc('factbook')//city/name[text() contains text {$query}] return ft:mark($city)
The optimized query will look as follows (check out the Query Info panel):
for $city_1 in ft:search("factbook", "Paris" using language 'English')/ parent::*:name[parent::*:city] return ft:mark(($city_1)[text() contains text "Paris" using wildcards using language 'English'])
The reason is that the word positions, which are resulting from a full-text request, won’t be implicitly bound to the $city variable, as this can take a lot of memory. In a future version of baseX, we’ll probably try to find a smarter way to find out if the positions may be required later on in a query. Once this is realized, you’ll be able to write queries like the following one:
let $query := "Paris" for $city in doc('factbook')//city/name[text() contains text {$query}] return ft:mark($city)
And one more thing:
{ if ($ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="short"]) then $ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="short"]/string() else if ($ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="article"]) then $ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="article"]/string() else if ($ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="main"]) then $ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="main"]/string()
This code will most probably be executed faster if you only do the path traveral once, e.g. as follows:
let $title := $ele/ancestor::tei:TEI//tei:titleStmt/tei:title [@type = ('short', 'article', 'main')]/string() ... return $title
Best, Christian
[1] https://github.com/BaseXdb/basex/issues/1236
On Sat, Jan 2, 2016 at 6:52 PM, kleist kleist@mail.dunzwolff.de wrote:
Dear members, dear Christian,
when using a for-loop inside of a for-loop I run into serious performance-problems, when I'm using variables to return results. For example this code-line takes 36780ms (!!!) for evaluation:
return <li><a>{$title}</a>{$quote}</li>
When I substitute the variable $time with the defining code, it takes only 711ms for evaluation (!!):
<li><a> { if ($ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="short"]) then $ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="short"]/string() else if ($ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="article"]) then $ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="article"]/string() else if ($ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="main"]) then $ele/ancestor::tei:TEI//tei:titleStmt/tei:title[@type="main"]/string() else ()} </a>{$quote}</li>
The only difference in the code is using a variable and it differs in performance by a factor of more than 50. In my real application (using more variables) it differs by factor more than 150.
I tried to simulate the problem with a simple factbook-query. Here is the code: xquery version "3.0"; let $query := "Pa.*" for $city in doc('factbook')//city/name for $hits in ft:mark($city[.//text() contains text {$query} using wildcards]) let $country_of_city := $city/ancestor::country/name return (: fast version: Evaluating 12.54ms :) <hit><city>{$hits}</city><country>{$city/ancestor::country/name}</country></hit>
(: slow version: Evaluating 35.78 :) (: <hit><city>{$hits}</city><country>{$country_of_city}</country></hit> :)
Also here is a performance bottleneck (not as dramatically: factor 3). Is there any solution to the problem? Now I'm working in my code without variables in the result part of the xquery, but it makes realy ugly non maintainable code.
Any help would be appreciated.
- Günter