Why does total result count change as I switch the page in Marklogic? - xquery

When I execute the below code with different values set for variable $Start as declared in the code, the value fetched each time for total count keeps changing-
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
let $SearchWord := 'AB:"nuclear power plant" OR AB:"nuclear power station"'
let $SearchOption :=
<options xmlns="http://marklogic.com/appservices/search">
<constraint name="AB">
<word>
<element ns="" name="ti"/>
<term-option>case-insensitive</term-option>
<term-option>diacritic-insensitive</term-option>
<term-option>punctuation-insensitive</term-option>
<term-option>whitespace-insensitive</term-option>
</word>
</constraint>
</options>
let $Start := 1
let $pageLength := 10
let $SearchResponse := search:search($SearchWord, $SearchOption, $Start, $pageLength)
return $SearchResponse

Related

How to sort by dynamically with ascending or descending in Marklogic?

let $sortelement := 'Salary'
let $sortby := 'ascending'
for $doc in collection('employee')
order by $doc/*[local-name() eq $sortelement] $sortby
return $doc
This code throws and error, what is the correct way to do this?
If you are just looking to build the order by dynamically within a FLWOR statement, you can't. As Michael Kay points out in the comments, you could use a conditional statement and decide whether or not to reverse() the ascending (default) sorted sequence.
let $sortelement := 'Salary'
let $sortby := 'ascending'
let $results :=
for $doc in collection('employee')
order by $doc/*[local-name() eq $sortelement]
return $doc
return
if ($sortby eq 'descending')
then reverse($results)
else $results
Depending upon how many documents are in your collection, retrieving every document and sorting them won't scale. It can take a long time, and can exceed memory limits for expanded tree cache.
If you have indexes on those elements, then you can dynamically build a cts:index-order() and specify as the third parameter for cts:search() in order to get them returned in the specified order:
let $sortelement := 'Salary'
let $sortby := 'ascending'
return
cts:search(doc(),
cts:collection-query("employee"),
cts:index-order(cts:element-reference(xs:QName($sortelement)), $sortby)
)

Wildcard search not working for path-index

Here is the query which gives the desired results:
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
search:search("( ( collectionId: ( "54930050DETB6CP71D38" ) ) ) sort:documentCreationDateDES",
<options xmlns="http://marklogic.com/appservices/search">
<term>
<empty apply="all-results"/>
<term-option>unstemmed</term-option>
<term-option>case-insensitive</term-option>
<term-option>punctuation-insensitive</term-option>
<term-option>wildcarded</term-option>
</term>
<additional-query>{cts:directory-query('/dir/subdir01/', "1")}</additional-query>
<transform-results apply="transformed-result" ns="http://searchgui/search" at="/customResultSet.xqy"/>
(:
Constraints or Search Criteria.
- collectionId
- creationDate
:)
<search:constraint name="collectionId">
<search:range type="xs:string" facet="false" collation="http://marklogic.com/collation/en">
<search:path-index ns="http://any.anyns.com/2013/doc">
//cd:documentCollections/cd:collection/cd:id
</search:path-index>
</search:range>
</search:constraint>
<search:constraint name="creationDateRange">
<search:range type="xs:dateTime" facet="false">
<search:bucket ge="0" lt="0" name="documentCreationDate">
Search by Document Creation date / uploaded date
</search:bucket>
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
<facet-option>limit=10</facet-option>
<facet-option>item-order</facet-option>
<facet-option>descending</facet-option>
</search:range>
</search:constraint>
(:
Sorting options:
- collectionId
- creationDate
:)
<search:operator name="sort">
(: Document Collection Id :)
<search:state name="collectionIdASC">
<search:sort-order direction="ascending" type="xs:string">
<search:path-index ns="http://any.anyns.com/2013/doc">
//cd:documentCollections/cd:collection/cd:id
</search:path-index>
</search:sort-order>
</search:state>
<search:state name="collectionIdDES">
<search:sort-order direction="descending" type="xs:string">
<search:path-index ns="http://any.anyns.com/2013/doc">
//cd:documentCollections/cd:collection/cd:id
</search:path-index>
</search:sort-order>
</search:state>
(: Creation Date :)
<search:state name="documentCreationDateASC">
<search:sort-order direction="ascending" type="xs:dateTime">
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
</search:sort-order>
</search:state>
<search:state name="documentCreationDateDES">
<search:sort-order direction="descending" type="xs:dateTime">
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
</search:sort-order>
</search:state>
</search:operator>
</options>, 1, 100);
But when i replace the search-criteria with wild-cards as below, it does not return any results:
"( ( collectionId: ( "* *54930050DETB6CP71D38* *" ) ) ) sort:documentCreationDateDES"
Though i set the <term-option> as wildcarded still it does not work, any suggestions or pointer as to what i might be missing would help.
I have tried changing other term-option from sensitive to insensitive and back in different combinations but it does not work, nor does stemmed or unstemmed works.
Term-options don't apply to range constraints, only facet-options do. And a facet-option wildcarded does not exist. Range constraints are ideal for selecting ranges, e.g. num GT x AND num LT y, but not suited for mid-string matches.
I think you'll have to create a word or value constraint for the same path to be able to use wildcards on it. Unfortunately, you can't just create a word or value constraint on a path as specific as you have in your collectionId constraint. You'd have to create a field with that path.
HTH!
The following description answers the how, its a supplement to this answer by #grtjn.
This is the part which was changed in the query:
<search:constraint name="collectionId">
<search:word>
<search:field name="collectionIdField"/>
<search:term-option>case-insensitive</search:term-option>
<search:term-option>unstemmed</search:term-option>
<search:term-option>wildcarded</search:term-option>
<search:term-option>punctuation-insensitive</search:term-option>
</search:word>
</search:constraint>
I could use the above in my query because i created a field - collectionIdField of type - path, with path as //cd:documentCollections/cd:collection/cd:id.
This is the query used for creating the field, this can also be done from the admin-console but i prefer the query way:
xquery version "1.0-ml";
import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy";
(:
get admin configuration
:)
let $config := admin:get-configuration()
(:
Specify the database where you want to create this field
:)
let $dbid := xdmp:database("My-Database")
(:
The field you want to create
:)
let $field-name := "collectionIdField"
(:
Since you are creating a path-field, specify the path.
Multiple field-paths can be specified
:)
let $field-paths := (
admin:database-field-path("//cd:documentCollections/cd:collection/cd:id", xs:double(1.0))
)
(:
Link database-field with field-path
:)
let $fieldspec := admin:database-path-field($field-name, $field-paths)
let $addFieldConfig := admin:database-add-field($config, $dbid, $fieldspec)
(:
Save the new database-add-field configuration to create the field
:)
return admin:save-configuration($addFieldConfig)
So here is my final query which actually worked:
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
search:search("( ( collectionId: ( "54930050DETB6CP71D38" ) ) ) sort:documentCreationDateDES",
<options xmlns="http://marklogic.com/appservices/search">
<term>
<empty apply="all-results"/>
<term-option>unstemmed</term-option>
<term-option>case-insensitive</term-option>
<term-option>punctuation-insensitive</term-option>
<term-option>wildcarded</term-option>
</term>
<additional-query>{cts:directory-query('/dir/subdir01/', "1")}</additional-query>
<transform-results apply="transformed-result" ns="http://searchgui/search" at="/customResultSet.xqy"/>
(:
Constraints or Search Criteria.
- collectionId
- creationDate
:)
<search:constraint name="collectionId">
<search:word>
<search:field name="collectionIdField"/>
<search:term-option>case-insensitive</search:term-option>
<search:term-option>unstemmed</search:term-option>
<search:term-option>wildcarded</search:term-option>
<search:term-option>punctuation-insensitive</search:term-option>
</search:word>
</search:constraint>
<search:constraint name="creationDateRange">
<search:range type="xs:dateTime" facet="false">
<search:bucket ge="0" lt="0" name="documentCreationDate">
Search by Document Creation date / uploaded date
</search:bucket>
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
<facet-option>limit=10</facet-option>
<facet-option>item-order</facet-option>
<facet-option>descending</facet-option>
</search:range>
</search:constraint>
(:
Sorting options:
- collectionId
- creationDate
:)
<search:operator name="sort">
(: Document Collection Id :)
<search:state name="collectionIdASC">
<search:sort-order direction="ascending" type="xs:string">
<search:path-index ns="http://any.anyns.com/2013/doc">
//cd:documentCollections/cd:collection/cd:id
</search:path-index>
</search:sort-order>
</search:state>
<search:state name="collectionIdDES">
<search:sort-order direction="descending" type="xs:string">
<search:path-index ns="http://any.anyns.com/2013/doc">
//cd:documentCollections/cd:collection/cd:id
</search:path-index>
</search:sort-order>
</search:state>
(: Creation Date :)
<search:state name="documentCreationDateASC">
<search:sort-order direction="ascending" type="xs:dateTime">
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
</search:sort-order>
</search:state>
<search:state name="documentCreationDateDES">
<search:sort-order direction="descending" type="xs:dateTime">
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
</search:sort-order>
</search:state>
</search:operator>
</options>, 1, 100);
Field helps with the wildcard and it has its own term-options to be supplied in the <word> element as shown above.

Can I use indexes for speeding up select queries over dateTime ranges in BaseX?

I would like to ask about the way to speed up the select queries in a Basex database.
I have for example the following xml in a database with many events(650000 approximately)
<EventList>
<Event>
<ID>317849</ID>
<Type>Measurement</Type>
<TimeStamp>2016-03-15T18:00:09.409</TimeStamp>
<Space>BIOCAT</Space>
<SourceID>BIOCAT.TE310A</SourceID>
<Content>
<Measurement>
<value>920</value>
</Measurement>
</Content>
</Event>
<Event>
<ID>317850</ID>
<Type>Measurement</Type>
<TimeStamp>2016-03-15T18:05:09.409</TimeStamp>
<Space>BIOCAT</Space>
<SourceID>BIOCAT.TE310A</SourceID>
<Content>
<Measurement>
<value>920</value>
</Measurement>
</Content>
</Event>
</EventList>
I am retrieving the events with the following code that selects with respect to the datetime of the Timestamp node
for $b in doc('mydb/my.xml')//EventList/Event
let $date_string as xs:string := xs:string($b/TimeStamp/data())
let $date as xs:dateTime := xs:dateTime($date_string)
where $date ge xs:dateTime('"+startdate+"')
and $date le xs:dateTime('"+enddate+"')
and $b/Type='"+EventType+"'
return $b
But it it is very slow it makes one minute to return 60 events.
There are many data in the BaseX database.
How can I speed up the request or my database?
BaseX currently does not have a range index for xs:dateTime, but you can use the text index for getting all events with a given event Type by moving the comparison into the XPath:
for $b in //EventList/Event[Type = 'Measurement']
let $date as xs:dateTime := xs:dateTime($b/TimeStamp)
where $date ge xs:dateTime('2016-03-15T18:00:00.000')
and $date le xs:dateTime('2016-03-15T19:00:00.000')
return $b
In the Info View of the GUI you can see that the text index is applied:
Compiling:
rewriting descendant-or-self step(s)
applying text index for "Measurement"
pre-evaluating "2016-03-15T18:00:00.000" cast as xs:dateTime
pre-evaluating "2016-03-15T19:00:00.000" cast as xs:dateTime
Optimized Query:
for $b_0 in db:text("mydb/my.xml", "Measurement")
/parent::*:Type/parent::*:Event[parent::*:EventList]
let $date_1 as xs:dateTime := $b_0/TimeStamp cast as xs:dateTime?
where (($date_1 ge "2016-03-15T18:00:00")
and ($date_1 le "2016-03-15T19:00:00"))
return $b_0

Applying suggestion-source constraints for typeahead in Marklogic

Say, I have 5 documents that belong to either of different collections such as:
Biography, Fiction, Humour, Adventure
For instance, document 1 is in Adventure Collection:
<Book>
<title>Harry Potter and the Deathly Hallows</title>
<Author>J.K.Rowling</Author>
<year>2007</year>
</Book>
document 2, is in Biography Collection:
<Book>
<title>Steve Jobs</title>
<Author>Walter Issacson</Author>
<year>2011</year>
</Book>
Now I want to apply suggest on year element. I want to apply this on collections i.e. for example-suggest on Biography collections
I have defined element range index on year and ingested sample documents using application loader and configured collections for documents in document settings.
Follwing is my XQUERY code:
xquery version "1.0-ml";
import module namespace search = "http://marklogic.com/appservices/search"
at "/MarkLogic/appservices/search/search.xqy";
let $options :=
<options xmlns="http://marklogic.com/appservices/search">
<constraint name="Group">
<collection prefix="Biography/"/>
</constraint>
<suggestion-source ref="Group">
<range collation="http://marklogic.com/collation/"
type="xs:string" >
<element name="year"/>
</range>
</suggestion-source>
</options>
return
search:suggest("Group:20", $options)
On running this query I am getting suggestions for both 2011 and 2007 which is not what I am expecting.
Expected suggestion is 2011 (as only Biography collection should be searched).
I have refered this doc on search:suggest but I am not able to find out what exactly is the mistake.
Where am I doing wrong?
Shrey:
The values from the suggestion source are substituted for the values from the referenced constraint. In other words, the options say that input qualified by the group constraint should come from the year range index, which is what you're seeing. For more detail, please see:
http://docs.marklogic.com/guide/search-dev/search-api#id_40748
To filter a set of suggestions, you can call search:suggest() with two string queries. The first provides the input for the suggestions. The second provides the filtering constraint. In the case above, the filtering constraint would be the Biography collection. For more detail, please see:
http://docs.marklogic.com/guide/search-dev/search-api#id_91911
Hoping that helps
However, I am able to achieve the required output using additional-query in options as follows:
xquery version "1.0-ml";
import module namespace search = "http://marklogic.com/appservices/search"
at "/MarkLogic/appservices/search/search.xqy";
let $options :=
<options xmlns="http://marklogic.com/appservices/search">
<additional-query>{cts:collection-query("Biography")}
</additional-query>
<constraint name="Search_Element">
<range collation="http://marklogic.com/collation/"
type="xs:string" >
<element name="year"/>
</range>
</constraint>
<suggestion-source ref="Search_Element">
<range collation="http://marklogic.com/collation/"
type="xs:string" >
<element name="year"/>
</range>
</suggestion-source>
</options>
return
search:suggest("Search_Element:20", $options)
Still, I was wondering how could it be done without using additional-query paramater because it would be more optimized to use collection constraint for above.

Add a dynamic day value to a date in xquery

I am trying to find the date of "sunday" in the current week. This is the code, I have:
let $today := fn:current-date()
let $day-week := functx:day-of-week($today)
let $start-date := xs:date($today)-xs:dayTimeDuration($day-week)
$today -> has today's date
$day-week -> is 5 (value for friday)
I thought, when I did $today-5, I will get 7/14/2013.
But, this didn't work. Kindly correct my code. Your help is appreciated.
functx:day-of-week($today) returns an xs:integer which won't cast into an xs:dayTimeDuration. Just multiply that integer by a valid duration instead of casting:
let $today := fn:current-date()
let $day-week := functx:day-of-week($today)
let $start-date := xs:date($today)-($day-week*xs:dayTimeDuration('P1D'))
I think xs:dayTimeDuration needs a bit more setting up. Try it something like this:
let $today := fn:current-date()
let $day-week := functx:day-of-week($today)
let $start-date := xs:date($today)-(xs:dayTimeDuration('P1D')*$day-week)
Get more information here:
http://pic.dhe.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=%2Fcom.ibm.db2z10.doc.xml%2Fsrc%2Ftpc%2Fdb2z_xsdaytimeduration.htm

Resources