Confused with search:suggest
I'm not able to provided this simple autocompletion feature with the help of the search:suggest function.
Based on the Oscars corpus from Marklogic Demo data, I try to provide a suggest query which was for instance able to return "Robert Loggia" as an answer even if the user is currently writing "Robert Lo" or "Loggia Rob" or even "L Rob".
Currently, I'm only able to return "Robert Loggia" amongst some of his peers with this simple query :
let $options :开发者_如何学JAVA=
<options xmlns="http://marklogic.com/appservices/search">
<default-suggestion-source>
<range type="xs:string">
<element ns="http://marklogic.com/wikipedia" name="name" />
</range>
</default-suggestion-source>
</options>
return search:suggest("Rob",$options)
But as soon as I'm writing a two words phrase, I'm not sure to understand how to write that, because none of the answer is correct with what I'm waiting. For instance :
search:suggest("Robert Lo",$options)
or
search:suggest(("Robert", "Lo"),$options)
Is it due to missing option, indexes misconfiguration or a misused feature ?
Thanks For Help
It's grammar-aware
.
You need to add quotes around the phrase if you want to get suggestions on the phrase, otherwise it treats the tokens separately. Try the following:
search:suggest('"Robert Lo"',$options)
That's a common mistake, I've made it several times myself.
As Colleen says, you need to place quotes around the query string. This is the same as searching in general using the search API, or google for that matter: with quotes your argument is considered a phrase, and without each token is a separate argument.
Without the quotes, the default behavior is to consider the two terms as separate tokens, and to either AND or OR them together in the query, depending on your configuration.
It looks odd to me too, using 4.2-6 on OS X. Here's what the results looked like in my test, using the full oscars data set.
import module namespace search = "http://marklogic.com/appservices/search"
at "/MarkLogic/appservices/search/search.xqy";
let $options :=
<options xmlns="http://marklogic.com/appservices/search">
<default-suggestion-source>
<range type="xs:string">
<element ns="http://marklogic.com/wikipedia" name="name" />
</range>
</default-suggestion-source>
</options>
return search:suggest("Robert Lo", $options)
=>
Robert "Loretta Young"
Robert "Lorraine Bracco"
Robert "Lotte Lenya"
Robert "Louis Calhern"
Robert "Louis Gossett, Jr."
Robert "Louis Malle"
Robert "Louise Fletcher"
It looks like the values are generated for or-query(('Robert', 'Lo')) and then merged in an odd way. If we drop down to using the cts lexicon function, things look normal.
cts:element-value-match(
QName('http://marklogic.com/wikipedia', 'name'),
'Robert Lo*')
=>
Robert Loggia
The word-swap aspect makes things more complicated, and goes beyond the scope of what autosuggest usually does (and what search:suggest
and cts:element-value-match
can do without help).
Here's a version that uses extra string manipulation to create two patterns, handling pairs of words. It assumes that the first word is always complete, while the second might be a stub, but that the words may need to be swapped for a match. If you define your desired logic, you should be able to modify this to suit your requirements. Note that function mapping is in play, so cts:element-value-match
is called once per pattern during evaluation. That may have a performance impact.
let $toks := cts:tokenize($INPUT)[. instance of cts:word]
let $pat := (
if (count($toks) eq 1) then concat($toks, '*')
else (
concat($toks[2], '* ', $toks[1]),
concat($toks[1], ' ', $toks[2], '*')))
return cts:element-value-match(
QName('http://marklogic.com/wikipedia', 'name'),
$pat)
=>
Robert Loggia
精彩评论