0

I'm finding a related element through it's id, stored in a reference element's href, like so:

let $item := ($doc//(map|question|theory|reading|glossgroup))[@id = $ref/@href]

Reading ExistDB's documentation, I'm pretty sure a simple <create qname="@ID" type="xs:string" /> index should've been enough, and should perhaps even be autogenerated.. but looking at the profiler, my query is not using any indexes.

I've even tried

let $item := $doc//map[@id = $ref/@href]

And created an index with the id field like so

<index>
    <range>
        <create qname="map" type="xs:string">
            <field name="map-id" match="@id" type="xs:string" />
        </create>
    </range>
</index>

But nothing seems to be working.

I'm pretty new to ExistDB.. probably doing something obvious wrong, so if anybody can point me in the right direction :)?

Example XML:

<root>
  <map id="ide931fee3-6a45-4435-a8d2-f018ae2ca2ea">
    <mapref href="f80cc8c8-6b6d-4005-b2e9-85eac2ee2fbf.1.36" />
  </map>
  <map id="f80cc8c8-6b6d-4005-b2e9-85eac2ee2fbf.1.36">
    <topicref href="47aed1dd-62f7-4fb6-ae76-dbfcde0a4bab.1.9" />
  </map>
  <question id="47aed1dd-62f7-4fb6-ae76-dbfcde0a4bab.1.9">
    ...
  </question>
</root>
vahdet
  • 6,357
  • 9
  • 51
  • 106
Rein Baarsma
  • 1,466
  • 13
  • 22

3 Answers3

1

If you can, I would advise to switch to the xml:id attribute. This is indexed automatically by exist-db. You can then drop the index definition and use the id() function to retrieve the elements.

Example

$doc/id($ref/@href)

Use fn:id to lookup xml:id attributes

eXist-db automatically indexes all xml:id attributes and other attributes with type ID as declared in a DTD (if validation is enabled). This automatic index is used by the standard id functions and provides a fast way to look up an element. For example, id("sect1")/head works through a fast index lookup.

However, the equivalent expression //section[@xml:id = 'sect1']/head will not use the id index.

Some users have reported that larger xml:id values have a negative performance impact.

source

line-o
  • 1,885
  • 3
  • 16
  • 33
0

If you still want to stick with @id:

Create a range index with:

<index>
    <range>
        <create match="@id" type="xs:string" />
    </range>
</index>

This should give you basic index usage.

Rewriting your query might further improve performance (fully optimized):

$doc//(map|question|theory|reading|glossgroup)/@id[. = $ref/@href]/..
line-o
  • 1,885
  • 3
  • 16
  • 33
0

For anyone interested in the solution I eventually chose. The answers listed unfortunately didn't really make my query faster or gave me a good idea how to rewrite it.

So instead I did this:

let $item := $doc//map[@id = $ref/@href]
let $item := if ($item) then $item else $doc//question[@id = $ref/@href]
let $item := if ($item) then $item else $doc//theory[@id = $ref/@href]
let $item := if ($item) then $item else $doc//reading[@id = $ref/@href]
let $item := if ($item) then $item else $doc//glossgroup[@id = $ref/@href]

and created the appropriate indexes separately

<create qname="map" type="xs:string">
    <field name="map-id" match="@id" type="xs:string" />
</create>
<create qname="question" type="xs:string">
    <field name="question-id" match="@id" type="xs:string" />
</create>
<create qname="theory" type="xs:string">
    <field name="theory-id" match="@id" type="xs:string" />
</create>
<create qname="reading" type="xs:string">
    <field name="reading-id" match="@id" type="xs:string" />
</create>
<create qname="glossgroup" type="xs:string">
    <field name="glossgroup-id" match="@id" type="xs:string" />
</create>
Rein Baarsma
  • 1,466
  • 13
  • 22