How to construct triples manually in Marklogic - xquery

I have been trying to insert triples in Marklogic using this query
xquery version "1.0-ml";
import module namespace sem = "http://marklogic.com/semantics"
at "/MarkLogic/semantics.xqy";
declare variable $TRIPLE as xs:string external ;
declare variable $GRAPHNAME as xs:string external ;
let $TRIPLE:="sem:triple(sem:iri('http://smartlogic.com/document#testForTriples.xml'),sem:iri('http://www.smartlogic.com/schemas/docinfo.rdf#type'),'document')"
let $GRAPHNAME :="sem:iri('testGraph')"
let $r :=
sem:graph-insert($GRAPHNAME, $TRIPLE)
return <result>{$r}</result>
Unfortunately, that returns a coercion error:
XDMP-AS: (err:XPTY0004) $graphname as sem:iri -- Invalid coercion: "sem:iri('testGraph')" as sem:iri
What am I doing wrong?

You should not put quotes around sem:triple and sem:iri, they are type cast functions:
xquery version "1.0-ml";
import module namespace sem = "http://marklogic.com/semantics"
at "/MarkLogic/semantics.xqy";
let $TRIPLE := sem:triple(sem:iri('http://smartlogic.com/document#testForTriples.xml'),sem:iri('http://www.smartlogic.com/schemas/docinfo.rdf#type'),'document')
let $GRAPHNAME := sem:iri('testGraph')
let $r := sem:graph-insert($GRAPHNAME, $TRIPLE)
return <result>{$r}</result>
If you are trying to create the triples dynamically, pass through a sem:triple or sem:iri objects from external, or pass through the string values, and cast them inside the code.
HTH!

Related

Error in Optic query in MarkLogic - Invalid coercion: map:map

I am getting an invalid map error when trying to get the percentage of a record based on a certain condition to the total count of another record.
Can you please help to identify the issue here in my code.
The below code is trying to get the percentage of the count of all 6 months old AncillaryQuote price to the total no of Shipments References when the Ancillary quote price is greater than 0 . I am taking Booking Date to calculate the 6 months old date range.
Here is my optic query which I am trying -
xquery version "1.0-ml";
import module namespace op="http://marklogic.com/optic" at "/MarkLogic/optic.xqy";
import module namespace ofn="http://marklogic.com/optic/expression/fn" at "/MarkLogic/optic/optic-fn.xqy";
import module namespace osql="http://marklogic.com/optic/expression/sql" at "/MarkLogic/optic/optic-sql.xqy";
declare option xdmp:mapping "false";
let $view := op:from-view("GTM2_Shipment", "Shipment_View")
let $Var1 := op:view-col("Shipment_View", "Ancillary_QuotePrice")
let $Var2 := op:view-col("Shipment_View", "Shipment_Ref")
let $Var3 := op:view-col("Shipment_View", "BookingCreateDt")
return $view
=> op:group-by("transMode",(op:count("Var2", $Var2),op:count("Var1", $Var1)))
=> op:where(op:and((
op:gt($Var1, 0),op:gt(ofn:format-dateTime($Var3, '[Y0001]-[M01]-[D01]'),osql:dateadd('month',-6, ofn:format-dateTime(fn:current-dateTime(),'[Y0001]-[M01]-[D01]')))
))
)
=>op:select(op:as("multiply", op:divide(op:col("Var1"), op:col("Var2"))))
=>op:select($Var3,op:as("percentage", op:multiply(100, op:col("multiply"))))
=> op:result()
Here is the error I am getting -
[1.0-ml] XDMP-AS: (err:XPTY0004) $qualifier as xs:string? -- Invalid coercion: map:map(<map:map xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" .../>) as xs:string
Stack Trace
In /MarkLogic/optic.xqy on line 685
In xdmp:eval("xquery version "1.0-ml";
import module namespace o...", (), <options xmlns="xdmp:eval"><database>16857865358322067141</database>...</options>)
In xdmp:eval("xquery version "1.0-ml";
import module namespace o...", (), <options xmlns="xdmp:eval"><database>16857865358322067141</database>...</options>)
The error is telling you that the $qualifier parameter is a map and cannot be converted to xs:string.
If you look at the signature of the op:select function:
op:select(
$plan as map:map,
$columns as columnIdentifier*,
[$qualifier as xs:string?]
) as map:map
You will see that $qualifier is the third parameter.
When using the =>, the plan is being set as the first parameter for you. The columns for the op:select() are the second parameter. However, you need to provide those columns as a sequence (wrap with ()). Otherwise, it appears that you are specifying $Var3 as the columns to select, and then the percentage column as the $qualifier.
Change:
=> op:select($Var3, op:as("percentage", op:multiply(100, op:col("multiply"))))
to:
=> op:select( ($Var3,op:as("percentage", op:multiply(100, op:col("multiply")))) )

cts:element-value-match does not works from scheduled tasks

I have written this code in the scheduled task XQuery -
xquery version "1.0-ml";
declare namespace grp = "http://marklogic.com/xdmp/group";
declare namespace c = 'http://iddn.icis.com/ns/core';
import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy";
declare variable $task-file-path := "/var/tmp/Projects/update-malformed-ids-task.xqy";
declare variable $string-starting-with-new-line-pattern := "
*";
declare variable $string-starting-with-space-pattern := " *";
declare variable $LIVE-ASSET-COLLECTION := "live-collection";
declare variable $batch-size := 100;
declare function local:is-migration-needed()
{
(
fn:exists(cts:element-value-match(xs:QName("c:id"), $string-starting-with-space-pattern, (), cts:collection-query($LIVE-ASSET-COLLECTION))) or
fn:exists(cts:element-value-match(xs:QName("c:id"), $string-starting-with-new-line-pattern, (), cts:collection-query($LIVE-ASSET-COLLECTION)))
)
};
declare function local:migrate()
{
if(local:is-migration-needed())
then (: do task here :)
else ()
}
local:migrate()
But this code is not working in scheduled task. The error which is logged in error logs says XDMP-ARG: cts:element-value-match(xs:QName("c:id"), " *", (), cts:collection-query("live-collection")) -- arg2 is invalid
I tried the same query on QConsole. It is working fine. I also tried using xdmp:spawn on the same file which also worked fine.
I also tried firing the simple cts:element-value-match without any pattern or wildcards. Looks like cts:element-value-match is not supported in scheduled tasks.
Is there something else need to be done to run this code from a scheduled task?
It seems like cts:element-value-match doesn't work in the scheduled tasks of MarkLogic. I did the desired task using cts:element-word-query instead.
Now the updated code in the task file, which worked for me, looks like -
xquery version "1.0-ml";
declare namespace grp = "http://marklogic.com/xdmp/group";
declare namespace c = 'http://iddn.icis.com/ns/core';
import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy";
declare variable $task-file-path := "/var/tmp/Projects/update-malformed-ids-task.xqy";
declare variable $string-pattern-for-new-line-and-space as xs:string* := (" *","
*");
declare variable $LIVE-ASSET-COLLECTION := "live-collection";
declare function local:is-migration-needed()
{
fn:count(cts:search(
fn:collection($LIVE-ASSET-COLLECTION),
cts:element-word-query(
xs:QName("c:id"),
$string-pattern-for-new-line-and-space,
("whitespace-sensitive", "wildcarded")
)
))>0
};
declare function local:migrate()
{
if(local:is-migration-needed())
then (: do task here :)
else ()
}
local:migrate()

How to dynamically create a search query based on a set of quoted strings in MarkLogic

I have the following query, where i want to form a string of values from a list and i want to use that comma separated string as an or-query but it does not give any result, however when i return just the concatenated string it gives the exact value needed for the query.
The query is as follows:
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
declare variable $docURI as xs:string external ;
declare variable $orQuery as xs:string external ;
let $tags :=
<tags>
<tag>"credit"</tag>
<tag>"bank"</tag>
<tag>"private banking"</tag>
</tags>
let $docURI := "/2012-10-22_CSGN.VX_(Citi)_Credit_Suisse_(CSGN.VX)__Model_Update.61198869.xml"
let $orQuery := (string-join($tags/tag, ','))
for $x in cts:search(doc($docURI)/doc/Content/Section/Paragraph, cts:or-query(($orQuery)))
let $r := cts:highlight($x, cts:or-query($orQuery), <b>{$cts:text}</b>)
return <result>{$r}</result>
The exact query that i want to run is :
cts:search(doc($docURI)/doc/Content/Section/Paragraph, cts:or-query(("credit","bank","private banking")))
and when i do
return (string-join($tags/tag, ','))
it gives me exactly what i require
"credit","bank","private banking"
But why does it not return any result in or-query?
The string-join step should not need to be string-join. That passes in a literal string. In xQuery, sequences are your friend.
I think you want to do something like this:
let $tags-to-search := ($tags/tag/text()!replace(., '^"|"$', '') ) (: a sequence of tags :)
cts:search(doc($docURI)/doc/Content/Section/Paragraph, cts:word-query($tags-to-search))
cts:word-query is the default query used for parameter 2 of search if you pass in a string. cts:word query also returns matches for any items in a sequence if presented with that.
https://docs.marklogic.com/cts:word-query
EDIT: Added the replace step for the quotes as suggested by Abel. This is specific to the data as presented by the original question. The overall approach remains the same.
Maybe do you need something like this
let $orQuery := for $tag in $tags/tag return cts:word-query($tag)
I used fn:tokenize instead it worked perfectly for my usecase
its because i was trying to pass these arguments from java using XCC api and it would not return anything with string values
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
declare variable $docURI as xs:string external ;
declare variable $orQuery as xs:string external ;
let $input := "credit,bank"
let $tokens := fn:tokenize($input, ",")
let $docURI := "2012-11-19 0005.HK (Citi) HSBC Holdings Plc (0005.HK)_ Model Update.61503613.pdf"
for $x in cts:search(fn:doc($docURI), cts:or-query(($tokens)))
let $r := cts:highlight($x, cts:or-query(($tokens)), <b>{$cts:text}</b>)
return <result>{$r}</result>

Pass a map to External function

I have the following module
xquery version "1.0-ml";
declare variable $datasets as map:map external;
...
I want to call this so I do an xdmp:invoke like this
...
let $update := xdmp:invoke("/app/lib/my-module.xqy", (xs:QName("datasets"), $map), <options xmlns="xdmp:eval">
<modules>{xdmp:modules-database()}</modules>
</options>)
...
$map is of type map:map.
Running this gives me the following error
[1.0-ml] XDMP-ARG: xdmp:invoke("/app/lib/20140527-0916-copy-y-axis-labels-from-chart-to-dataset-...", fn:QName("", "datasets"), <options xmlns="xdmp:eval"><modules>0</modules></options>) -- Invalid argument
Why is that?
It's hard to know for sure from the limited code samples you've posted, but I think that your $map variable is bound to the empty sequence (the rough analogue of null in XPath/XQuery).
I've created the following main module, that simply returns the external variable $datasets:
xquery version "1.0-ml";
declare variable $datasets as map:map external;
$datasets
Invoking it as follows works correctly:
let $map := map:entry("key", "value")
return
xdmp:invoke("/test.xqy",
(xs:QName("datasets"), $map),
<options xmlns="xdmp:eval">
<modules>{xdmp:modules-database()}</modules>
</options>)
This results in the "invalid argument" error:
let $map := ()
return
xdmp:invoke("/test.xqy",
(xs:QName("datasets"), $map),
<options xmlns="xdmp:eval">
<modules>{xdmp:modules-database()}</modules>
</options>)
XQuery flattens sequences (they don't nest like s-expressions), so when $map is the empty sequence, the <options/> element becomes the value of the $datasets param, which is an invalid value for the external variable.
Update: Doh! #mblakele's comments below explain the error conditions ...
TL;DR: () is not an instance of map:map.

XQuery node is sequence

Is is-node-in-sequence-deep-equal in XQuery? I'm wondering because I've seen the function at xqueryfunctions.com, but I'm not being able to use it.
That function is part of the FunctX XQuery library. There are two methods to use this function:
You download the whole library (select the download which corresponds to your version of XQuery), save it in the same directory as your XQuery program/file and then import the module in your XQuery file, e.g.:
import module namespace functx = "http://www.functx.com" at "functx-1.0-doc-2007-01.xq";
(: Insert your code here and call the is-node-in-sequence-deep-equal function as seen below :)
functx:is-node-in-sequence-deep-equal($node, $seq)
Instead of downloading the whole library with all functions you can also simply copy paste the specific function which you need as shown on the page you linked to:
declare namespace functx = "http://www.functx.com";
declare function functx:is-node-in-sequence-deep-equal
( $node as node()? ,
$seq as node()* ) as xs:boolean {
some $nodeInSeq in $seq satisfies deep-equal($nodeInSeq,$node)
} ;
(: Insert your code here and call the 'is-node-in-sequence-deep-equal' function as seen below :)
functx:is-node-in-sequence-deep-equal($node, $seq)
In both examples you simply replace $node and $seq with your variables.

Resources