JSearch in 5 Minutes

Aries Yuwono
Last updated October 15, 2015

Introduction

JSearch is a Server-side and high-level Javascript API that makes common search tasks (search, facets, and aggregates) easy. It's an easier path to learn than the cts.* API for novice users and a shortcut for applying what you already know for more advanced users. JSearch is available in MarkLogic 8-0.4 and above. This tutorial will provide a quick introduction to using the API.

Indexes setup

Before we begin with JSearch, let's set up our database with the indexes that we will use for the examples. We're using the Documents database for our examples, but feel free to create a new database (with a forest) of your choice if you wish. You can run this JavaScript code in Query Console (http://localhost:8000/qconsole) with the Content Source pointing to the Documents database to apply the setup.

Dataset

This city dataset contains JSON and XML documents. They are inserted into different collections (e.g. "america", "asia", ...). Some of the documents also have quality metadata value. Run this script in Query Console against Documents database to insert the data.

Let's say we want to search cities in the "america" continent; we can do so by doing search with a collection scope. Calling jsearch.documents() without any where() clause would match all documents in the database, but because we have specified the collections() scope, this query will match all documents in the "america" collection. Please note that for a larger dataset you'd only see the first 10 documents. We'll take a look at how you can apply pagination to the resultset to display potentially all the results.

Our output will return the two documents in the "america" collection.

Adding .where() will narrow the search. Please note that you can add .where() is also possible on a collection scope query.

The output should return one document that has "london" as the "city".

With orderBy(), you can sort the results based on specified index. Ordering on a property / element will always require an index.

The output will be 5 documents in this order: "new york", "new jersey", "london", "cape town", "beijing".

Adding slice() will apply pagination on the result.

As we discussed earlier by default you can see the first 10 results. The above query limits the returned documents to only 4. If you'd like to see more than 10 results you can apply the .slice() method to your search. Please make sure that you don't return a large number of documents with your search as it could lead to some unwanted problems.

JSearch provides several ways to tailor the results of your search. The map() provides built-in functions such as snippet and extract. Here is an example of using snippets.

The returned document will include match text highlighting.

extract will allow you to return a portion of document with specified path.

Instead of the entire content of the document, the query will only return the extracted portion.

You can write your own function for the mapper to produce a custom result.

This mapper will transform the result to:

Alternatively to map(), you can use reduce() to reduce the result. In broad strokes, a reducer takes in a previous result and a single value and returns either an item to pass to next invocation of the reducer, or a final result. The output from the final invocation becomes the result. Reducers are well suited for computing aggregates over a set of results.

You can use built-in reduce methods as well as custom ones. We will take a look at one of the built-in reducers later, let's now take a look at a custom one::

The above example adds the distances together of the documents that match the specified word query.

Add .withOptions() to toggle various options on/off.

In the above example we are returning things like relevancy tracing and the query execution plan.

It is also possible to parse a query string using cts.parse().

This should give you "london" and "new york". Notice how this search now understands the MarkLogic Search Grammar.

Search using values() to look up the values in a range index over documents. In this example, where() and match() are used to limit the result.

The result should return an array of values, in this case: ["cape town", "london"]

Adding aggregate() on values will apply aggregate functions against an index. For example, find the average, maximum, and minimum distance of the cities.

This will give you:

You can create range indexes and apply bucket names on them. For example, create facets on "date" and "popularity" with user-defined bucket names. Facets are quite similar to values but it provides a search report. These help users explore the data set.

The result will give you the frequencies and the values on the buckets.

Similar to values lookups, you can look up words in word lexicons over documents. For example, find all words within "city" that has the letter "n".

This should give you:

You can do geospatial searches on your data using points, circles, boxes, or polygons.

For more features, please check the JSearch function documentation or MarkLogic University's On Demand video series on JSearch.

Comments

  • I believe at the top of this guide in the code snippet that sets the indexes, there is a distanceIndex created but not added. This will cause trouble when you use aggregate() to calculate min, max, avg distance.