Applying suggestion-source constraints for typeahead in Marklogic - xquery

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.

Related

MarkLogic: How to manage additional query in constraint

MarkLogic 9.0.8
On UI, apart from search text, few filters are applied including publish date year.
As we can't control how end user will write query in multiline textbox.
So at end query look like something
AU:Manish AND PY:>=2001 AND CT:Control AND UT:uncontrol AND PY:<=2010
(AU:Manish AND PY:>=2001) OR (CT:Control AND UT:uncontrol AND PY:<=2010)
AU:Manish AND CT:Control AND UT:uncontrol AND PY:>=2001 AND PY:<=2010
Till now we managed with having year range at the end in query and was working with following code
Qyery: AU:Manish AND CT:Control AND UT:uncontrol OR PY:>=2001 AND PY:<=2010
<additional-query>
{
cts:and-query((
cts:path-range-query("contg/sortdate/yr", ">=",xs:int($startYear)),
cts:path-range-query("contg/sortdate/yr", "<=",xs:int($endYear))))
}
</additional-query>
But now as user can put year range anywhere in the query text, its not working as expected
So can we write condition in constraint directly and how to put additional query inside ?
<constraint name="Year">
<range type="xs:int" facet="false">
<path-index>article/date/year</path-index>
</range>
</constraint>
Expected Behavior
If user pass year range then it should return documents within given range
if not then it will not apply year range

Conditional combined indexes:When there are several decimal types of indexes, the desired results can not be queried

Use version:4.5.0
db/system/config/db/test/collection.xconf The code is as follows:
<range>
<create qname="item">
<condition attribute="name" value="number"/>
<field name="number" match="#value" type="xs:decimal"/>
</create>
<create qname="item">
<condition attribute="name" value="acreage"/>
<field name="acreage" match="#value" type="xs:decimal"/>
</create>
<create qname="item">
<condition attribute="name" value="radii"/>
<field name="radii" match="#value" type="xs:decimal"/>
</create>
<create qname="item">
<condition attribute="name" value="diameter"/>
<field name="diameter" match="#value" type="xs:decimal"/>
</create>
</range>
Browse Indexes
db/test The code of an XML file is as follows:
<root>
<item name="number" value="4"/>
<item name="acreage" value="5"/>
<item name="radii" value="6"/>
<item name="diameter" value="7"/> </root>
Query statement:
//item[#name='radii'][#value>5.0]
Query Profiling
No result
In theory, the XML file can be found, but the result can not be found for what? Can you help me? Thank you!
Based on the documentation for eXist's Conditional Combined Indexes feature you are trying to use here, it appears to me that this feature only support string comparisons (with an optional "numeric" mode). See https://exist-db.org/exist/apps/doc/newrangeindex#D3.21.18. In other words, your #type="xs:decimal" is not resulting in your attributes' values being cast to xs:decimal; effectively, instead, they are being indexed as xs:string.
Thus, for your query to work with the given data, change the predicate to [#value gt "5"].
Or, to force numeric comparisons, add numeric="yes" to the <field> element in your index definitions, and then change your predicate to [#value gt "5.0"].

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.

Exact constraint search in marklogic8

Two different documents in my database (with default index setup) contains title like below
first document:-
<title>Reconceptualizing Subject</title>
second document:-
<title>Reconceptualizing Subject (LP)</title>
I have created word constraint on title for search in the title
<constraint name="title">
<word>
<element ns="" name="title"/>
<term-option>case-insensitive</term-option>
</word>
</constraint>
so if I query search:search("title:Reconceptualizing Subject") then I am getting both document as a result from database but if I query search:search("title:Reconceptualizing Subject (LP)") it gives me only single document result.
How can I achieve exact search (single document) when I query "title:Reconceptualizing Subject" ?
Change your search constraint to:
<constraint name="title">
<value>
<element ns="" name="title"/>
<term-option>case-insensitive</term-option>
</value>
</constraint>
And then double-quote your search string:
search:search(' title:"Reconceptualizing Subject" ')
HTH!

How to load data from XML with attribute to database in Sql Server 2005

I was trying to read data of concerned columns from XML given below and load into database.
My XML is like below:
<questions>
<question>
<Field name="id">12</Field>
<Field name="lid">10</Field>
<Field name="text">Hello</Field>
</question>
</questions>
I have table with columns id,lid and text , i want to load data from above xml into database. Try to use OpenXML but in vain.not able to read attribute.
I was using below query.
DECLARE #doc AS INT
EXEC Sp_xml_preparedocument
#doc OUTPUT,
#queueData
INSERT INTO dbo.Questions
([Id],[Lid],[Text])
SELECT * FROM OPENXML(#doc, '/questions/question/Field', 1)
WITH ( id VARCHAR(20),
lid VARCHAR(20) ,
text VARCHAR(MAX))
i want to load data from above xml into database. Try to use OpenXML but in vain.not able to read attribute.
ANY Help appreciated!!
Thank you!!
Try this.
declare #xml xml = '
<questions>
<question>
<Field name="id">12</Field>
<Field name="lid">10</Field>
<Field name="text">Hello</Field>
</question>
</questions>
'
select N.value('(Field[#name="id"])[1]', 'varchar(20)'),
N.value('(Field[#name="lid"])[1]', 'varchar(20)'),
N.value('(Field[#name="text"])[1]', 'varchar(max)')
from #xml.nodes('/questions/question') as T(N)
Read more about it here: http://msdn.microsoft.com/en-us/library/ms190798.aspx

Resources