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

Reply via email to