Searching for one result

MarkLogic is both a database and a search engine. Sometimes, you know you only want one result from your search. What’s a good way to do that?

Using MarkLogic’s Server-side JavaScript, here’s one way to do it:

const query = ...;
// foreshadowing -- there's a better way!
cts.search(query).toArray().slice(0, 1)

We get the results of our search, change the results from a Sequence to an Array, and take the first one. Simple — but not the way we should do this. How do we know? We ask MarkLogic, of course. Instead of the above, let’s evaluate the following in Query Console (note: if your query will hit a large number of documents, maybe don’t run this in Query Console).

const query = ...;
cts.search(query).toArray().slice(0, 1);
xdmp.queryMeters()

Looking at the queryMeters output, we see some interesting things, including cache hits and misses. Toward the end of the response, there’s a JSON property called “documents”, which is an array of objects identifying the URIs that the query loaded. As written, that array will include all results from the search, not just the one that we want to get.

We want to tell MarkLogic to just return the first one. For some MarkLogic functions, you can specify an option “limit=1”. The cts.search() function doesn’t have that option.

cts.search returns a Sequence, a data structure that is similar to an array in some ways, but not quite the same. In XQuery, there are a few ways we could wrap a call to cts:search() to tell MarkLogic that we only wanted a certain number of results:

cts:search(fn:doc(), $query)[1 to 10]
fn:subsequence(cts:search(fn:doc(), $query), 1, 10)

MarkLogic sees what parts of the Sequence we want and optimizes to only return those. Calling xdmp:query-meters() confirms that.

Okay, that’s cool and all, but we’re working with JavaScript. Can we do the same thing?

Yes, yes we can.

fn.subsequence(cts.search(query), 1, 10)

xdmp.queryMeters() tells us that we’re only bringing back the ten documents (remember that a Sequence starts at index 1, while an Array starts at index 0).

Knowing that Sequence optimizations influence our searches, we’ve got a real simple way to get just that first result:

const query = ...;
fn.head(cts.search(query))

Again, we turn to xdmp.queryMeters() and find just one item in the documents array. Just what we need!

Leave a Reply

Your email address will not be published. Required fields are marked *