martes, 29 de julio de 2014

Constraints not just for facets... Making a complex search


As it is known the way to return facets on a search, using the search api from marklogic, is by defining some constraints and using
indexes for those constraint, and it has been proved to be very useful, but contraints are not just useful for facets, they are very useful for "constraining"
a search, so that the search becomes more complex.

Lets say for instance you want to search a keyword and you want just the search to be done on a single element, you would think
one way is to use cts:element-query, now you want to enable the "Google typed" grammar on this search, well then you use the grammar
on the search options. So far so good.

Know let`s say you want to make your search a little more complex, and you want to search on two elements using the same grammar, then
you would need to use a cts:or-query, surrounding the two cts:element-query's that point to the two different nodes and the search api will search
on both cases using the grammar individually, for example.

keyword: "house"
returns -> documents with "house" in <NODE_1> OR "house" in <NODE_2>

keyword: "house AND car"
returns -> documents with words "house" AND "car" in <NODE_1> OR words "house" AND "car" in <NODE_2>

It might seem ok to you, but what if you want that the grammar applies to all nodes and its possible "combinatory" cases, i.e.:

keyword: "house AND car"
returns -> documents with (words "house" AND "car" in <NODE_1>)
OR (words "house" AND "car" in <NODE_2>)
OR (word "house" in <NODE_1> AND "car" in <NODE_2>)
OR (word "house" in <NODE_2> AND "car" in <NODE_1>)

If you want your app to behave as complex as explained before, you would have to create your cts queries as complex, but wait, althought it is not difficult you have
to think in case the end user uses a really complex and extended keyword (e.g: house OR (cat AND "dog eats bones") AND -(bunny OR fish))
also you may want to think the case you want to use more than 2 nodes... as you see it gets complicated, not imposible, but complicated..

Here's when the constraints come useful, either if you create a constraint for each node, attribute or property data, or you use a fiel for them, the constraints
will help you to re-structure your search easier and also to merge it with the grammar and search api benefits.

So now let's see how does a search constraint looks like:

<constraint name="inAbstract">
  <word>
    <element ns="http://example.com" name="abstract"/>
  </word>
</constraint>

If you add the previous snippet to the options node for your search, it will create a constraint to be used with the prefix "inAbstract",
so for example:

keyword: "inAbstract:house"
returns -> documents with "house" in node <abstract>
keyword: "inAbstract:(house and car)"
returns -> documents with words "house" and "car" in node <abstract>

This is very useful for a search that points to just one node, but if you need to add another node to the search, then you will have to create another constraint,
with another prefix, and then you will have to parse your query text so it will fit all possible cases, This is much easier than
the case of ...