Thanks, Mike! This gives us a couple options to try out. -Brent
-----Original Message----- From: [email protected] [mailto:[email protected]] On Behalf Of Michael Blakeley Sent: Wednesday, January 30, 2013 1:54 PM To: MarkLogic Developer Discussion Subject: Re: [MarkLogic Dev General] how to use custom functions without impeding ML's ability to use its universal index? The short answer is "no", but there are ways and means. Almost any function call will be ignored by the query plan, and any potential matches will be tested as part of filtering. My article on code review at http://blakeley.com/blogofile/archives/518/ touches on this, under "Review any function calls within XPath predicates" - although it could be a little more explicit. As you found out, you can see the effects of a function call in the query-trace or plan, as well as profiling or query meters. But there are exceptions for cases like this, where the code could potentially use indexes. One is to simply inline the function, but this can create a lot of repeated code. Another is to write functions that build an XPath expression as a string, and then call xdmp:unpath or xdmp:value to evaluate them. My preference is to structure the function so that it can always evaluate a rooted XPath. So instead of writing a function that returns values and using those values in XPath, write a function that evaluates XPath in a parameterized way. Something like this: declare function local:with-lmd-eq( $qname-root as xs:QName, $qname-pred as xs:QName, $value as xs:string) as element()* { /*[node-name(.) eq $qname-root]/mv-lmd:metadata/mv-lmd:layered/*[ node-name(.) eq $qname-pred][. = $value]/root() }; local:with-lmd-eq( xs:QName('mv-lmd:book'), xs:QName('mv-lmd:color'), 'red') I'm not sure if I have all the namespaces right, but the intent is to return all the book elements with color 'red', just as the original XPath did. But this function allows you to parameterize the root QName, the predicate QName, and the predicate value. Because fn:node-name() is one of those rare functions that is optimized in query plans, the plan should show everything searchable until the final root() step. Another tool for this kind of thing is cts:contains(), which can also use indexes. If that approach doesn't work out, then using xdmp:unpath or xdmp:value is probably the next best alternative. -- Mike On 30 Jan 2013, at 07:00 , Brent Hartwig <[email protected]> wrote: > Good morning, > > Is it possible to use custom functions within an XPath expression without > impeding ML's ability to use its universal index? > > We defined custom functions in order to abstract a content model that may > change between releases. But, this approach doesn't scale. Xdmp:plan() > reveals XPath expressions using the functions require MarkLogic to filter out > false positives. Not true if we replace the calls to the custom functions > with the markup we're trying to abstract: xdmp:plan()'s estimate then equals > the number of actual results. > > Here's an example of an XPath expression that gets everything it needs from > the universal index: > > /book[./mv:metadata/mv-lmd:layered/mv-lmd:color = 'red'] > > Here's the same using the custom function: > > /book[rmd:get-lmd-value(., 'color') = 'red'] > > Below is the associated code. "Lmd" stands for layered metadata. Layered > metadata may repeat, which is why get-lmd-value() takes the first value from > get-lmd-values(). And, in this case, $mo is a <book> element. > > declare function get-lmd-values( > $mo as element(), > $name as xs:string) as xs:string* { > $mo/mv:metadata/mv-lmd:layered/node()[fn:node-name(.) eq > xs:QName(fn:concat("mv-lmd:",$name))] > }; > > declare function get-lmd-value( > $mo as element(), > $name as xs:string) as xs:string { > let $values as xs:string* := get-lmd-values($mo, $name) > return if ($values) then xs:string($values[1]) else "" > }; > > Thank you. > > -Brent > _______________________________________________ > General mailing list > [email protected] > http://developer.marklogic.com/mailman/listinfo/general _______________________________________________ General mailing list [email protected] http://developer.marklogic.com/mailman/listinfo/general _______________________________________________ General mailing list [email protected] http://developer.marklogic.com/mailman/listinfo/general
