Problem

Show more recent documents higher in a result set than older documents. For instance, when searching blog posts, more recent content is more likely to be current and relevant than older content.

Solution

With server-side code:

// MarkLogic 8+ for JavaScript
var jsearch = require('/MarkLogic/jsearch.sjs');
jsearch.documents()
  .where([
    cts.elementRangeQuery(
      fn.QName("", "pubdate"), "<=", fn.currentDateTime(),
      "score-function=reciprocal")
  ])
  .result()
cts:search(
  fn:doc(),
  cts:element-range-query(
    xs:QName("pubdate"), "<=", fn:current-dateTime(),
    "score-function=reciprocal")
)

With the REST API:

{
  "search": {
    "qtext": "recent LE " + fn.currentDateTime()
    "options": {
      "constraint": [
        {
          "name": "recent",
          "range": {
            "facet": false,
            "type": "xs:dateTime",
            "element": {
              "name": "pubdate"
            },
            "range-option": [ "score-function=reciprocal" ]
          }
        }
      ]
  }
}
<search xmlns="https://marklogic.com/appservices/search">
  <qtext>{"recent LE " || fn:current-dateTime()}</qtext>
  <options>
    <constraint name="recent">
      <range type="xs:dateTime" facet="false">
        <element ns="" name="pubdate"/>
        <range-option>score-function=reciprocal</range-option>
      </range>
    </constraint>
  </options>
</search>

Required Indexes:

  • dateTime index on target element or property

Discussion

Part of searching is determining the order in which to present the results. Commonly, this ordering is based on the score– how well does each document match the query? Normally, range constraints don’t affect the score, but we can override that. This is useful in preferring recent content, or in finding documents with a geospatial component near a particular point.

In the example above, our content documents have an element called “pubdate”. If we set up a dateTime index on this element, then we can do range queries. We might use those to limit our results to just content within the last year, but in this case, the goal is just to affect the scoring. As such, the JSearch and XQuery examples perform a <= comparison with the current date and time — we’d expect this to match all documents (note that documents without a score will fail to match and will drop out of the result set).

The current date and time provides an anchor for the comparison; the distance between a document’s pubdate value and the anchor value is fed into the reciprocal score function. This means that the more recent documents will get a boost in score. You may want to adjust the weight parameter to the element range query to tune how much impact recency has.

To use this approach with the REST API, create a range constraint and specify the “score-function=reciprocal” range option. You’ll need to provide an anchor point with the constraint, for instance “recent:2017-05-22T15:36:00”. The anchor time will added by your middle tier, combining it with the user inputs.

The score-function option can be reversed by specifying the “linear” function. This rewards values that are further away from the anchor value. In the case of pubdate, “score-function=linear” would favor older documents.

Learn More

Range Query Scoring Examples

Read over use cases for range query score contributions, along with some examples of how to use the feature and additional APIs, such as structured query and QBE.

Search Developer's Guide Documentation

Read the documentation that goes over how to use search in MarkLogic, along with its terms and definitions, licensing requirements, features, real-life examples, and more.

“Ask Anything” Universal Index

Find out how MarkLogic uses an “Ask Anything” Universal Index to index data as soon as it is loaded so that you can start asking questions of your data.

This website uses cookies.

By continuing to use this website you are giving consent to cookies being used in accordance with the MarkLogic Privacy Statement.