I wanted to "convert" one of my old XQuery examples that uses buckets (bucketed search) to JSearch:
import module namespace search =
"http://marklogic.com/appservices/search"
at "/MarkLogic/appservices/search/search.xqy";
declare variable $options := <options xmlns="http://marklogic.com/appservices/search">
<constraint name="height">
<range type="xs:double" facet="true">
<bucket ge="1.9" name="supertall">1.90m + </bucket>
<bucket lt="1.9" ge="1.7" name="tall">1.70m - 1.90m</bucket>
<bucket lt="1.7" ge="1.2" name="normalish">1.20m - 1.70m</bucket>
<bucket lt="1.2" name="short">0m - 1.20m</bucket>
<facet-option>limit=20</facet-option>
<json-property>height</json-property>
</range>
</constraint>
</options>;
let $results := search:search("height:short", $options)
for $facet in $results/search:facet
return $results;
The above allows the definition of buckets as well as allows the usage of 'height' as part of the search grammar, meaning that a search such as search:search('height:short')
works just as fine.
Unfortunately I couldn't get the JSearch version working, this is what I have tried:
var jsearch = require('/MarkLogic/jsearch');
jsearch.documents(
jsearch.facet('Height', 'height').groupInto([
jsearch.bucketName('short'), 1.60,
jsearch.bucketName('normal'), 1.90,
jsearch.bucketName('tall'), 4.00
]))
.where(cts.parse('height:short'))
.result();
The above code returns:
{ "results": null, "estimate": 0 }
I have also tried to add a reference to the JSON property 'height' but that didn't work either:
var jsearch = require('/MarkLogic/jsearch');
var reference = { height: cts.jsonPropertyReference('height') };
jsearch.documents(
jsearch.facet('Height', 'height').groupInto([
jsearch.bucketName('short'), 1.60,
jsearch.bucketName('normal'), 1.90,
jsearch.bucketName('tall'), 4.00
]))
.where(cts.parse('height:short', reference))
.result();
However when I remove the .where()
constraint I get my buckets generated just fine. Any suggestions?
I believe I have found a solution to this. The values of height are numbers and in my JSearch query I am trying to match the string 'short' against those numbers. In order to overcome this I had to use a callback function which was documented on this page http://docs.marklogic.com/cts.parse
Essentially the solution was to create my own query using a set of cts query constructors (cts.andQuery and cts.jsonPropertyRangeQuery). The solution now looks like this:
var jsearch = require('/MarkLogic/jsearch');
var short = 1.60;
var normal = 1.80;
var tall = 1.90;
var refCallback = function(operator, values, options) {
if (values === 'short') {
return cts.jsonPropertyRangeQuery('height', '<=', short)
} else if (values === 'normal') {
return cts.andQuery([
cts.jsonPropertyRangeQuery('height', '>=', normal),
cts.jsonPropertyRangeQuery('height', '<', tall)
])
} else {
return cts.jsonPropertyRangeQuery('height', '>=', tall)
}
};
var reference = { height: refCallback };
jsearch.documents(
jsearch.facet('height').groupInto([
jsearch.bucketName('short'), short,
jsearch.bucketName('normal'), normal,
jsearch.bucketName('tall'), tall
]))
.where(cts.parse('height:tall', reference))
.result();
Note that I also had to externalise the variable declarations as now I can reuse those within the bucket definitions as well as the callback function.