Relevance and Scoring Starter Pack

Understand what ranked first and why

personClever Llamas
CleverLlamasMinimum Llamaverse Version: 2.4.0
databaseMinimum MarkLogic Version: 11

Each example keeps the score values, the query, and the output together — so when someone asks why this result ranked first, you have the receipts.

When somebody asks "why did this result rank first?", this pack gives you receipts.

The examples call out the score-related values that explain ranking and keep the results tabs trimmed to the fields that matter for that explanation.

The examples in this article assume the llamaverse (v2.4.0+) is deployed. The llamaverse sample data is freely available from github.com/cleverllamas/llamaverse - see the llamaverse article for full setup instructions.

API Context for This Pack

Context ItemWhat this pack uses
Data setllamaverse v2.4.0+ sample data
Quality profileCurated document quality values on selected wild llama profiles, providing non-zero cts:quality() output in read-only relevance diagnostics
Primary document scopewild llama JSON documents (/cleverllamas/llamaverse/raw/wild-llamas/llamas/{uuid}.json)
Query entry pointcts:search-style result nodes used to inspect score attributes
Fields usedNone in these examples
Index contextRelevance and score metadata are resolved in the cts search/index layer

If score behaviour looks surprising, verify that the query options are the ones you intend and that you are comparing nodes returned from the same query context.

Relevance Signals at a Glance

Functions in This Pack

cts:score

The relevance number everyone argues about and nobody should ignore.

Source docs: https://docs.marklogic.com/11.0/cts:score

Option / ArgumentWhat it controlsUsed here
$nodeThe result node from which score metadata is readA node returned by cts:search(...)
$logtfLogarithmic tf scaling mode for score calculationNot set in this sample
{
  "name": "Aaron",
  "breed": "Huacaya",
  "placeOfBirth": "Cusco, Peru",
  "secretPowerId": "d8839ba6-2b77-4bcc-9927-b86cdfecb9fb"
}
xquery version "1.0-ml";

let $query := cts:and-query((
  cts:collection-query("wild-llamas"),
  cts:word-query("sung")
))
for $node in cts:search(fn:doc(), $query)[1 to 5]
return
  map:entry("uri", xdmp:node-uri($node))
  => map:with("score", cts:score($node))
'use strict';

const query = cts.andQuery([
  cts.collectionQuery('wild-llamas'),
  cts.wordQuery('sung')
]);

const results = cts.search(query).toArray().slice(0, 5).map((doc) => ({
  uri: xdmp.nodeUri(doc),
  score: cts.score(doc)
}));

({
  sample: 'cts/relevance-and-scoring-starter-pack/assets/cts-score.sjs',
  kind: Array.isArray(results) ? (results.every((item) => typeof item === 'object' && 'subject' in item && 'predicate' in item && 'object' in item) ? 'triples' : 'rows') : ((results !== null && typeof results === 'object') ? 'object' : 'scalar'),
  count: Array.isArray(results) ? results.length : 0,
  data: results
});
[
  {
    "score": 16896,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json"
  },
  {
    "score": 16896,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/4429e229-490a-4398-992e-84d0f4737d6d.json"
  },
  {
    "score": 16896,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/d9af3805-d87d-473b-b01f-67bc8628e3df.json"
  },
  {
    "score": 16896,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/78a3ea33-382d-486a-aece-77bae497af14.json"
  },
  {
    "score": 16896,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/3cb1a513-b57b-49c4-b80a-e67aa99dd272.json"
  },
  {
    "score": 16896,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/7ceb979a-b831-48fd-8b1a-a1c724370ba1.json"
  },
  {
    "score": 16896,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/b67c3b62-b38b-4cb8-ae04-88a2fdd1ebda.json"
  },
  {
    "score": 16896,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json"
  },
  {
    "score": 16896,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/eaa6c416-ef46-4f91-b861-1e99b28ae18b.json"
  },
  {
    "score": 16896,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/58fc1645-17d2-4732-aded-1e88f637f967.json"
  }
]
ScoreURI
16896/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json
16896/cleverllamas/llamaverse/raw/wild-llamas/llamas/4429e229-490a-4398-992e-84d0f4737d6d.json
16896/cleverllamas/llamaverse/raw/wild-llamas/llamas/d9af3805-d87d-473b-b01f-67bc8628e3df.json
16896/cleverllamas/llamaverse/raw/wild-llamas/llamas/78a3ea33-382d-486a-aece-77bae497af14.json
16896/cleverllamas/llamaverse/raw/wild-llamas/llamas/3cb1a513-b57b-49c4-b80a-e67aa99dd272.json
16896/cleverllamas/llamaverse/raw/wild-llamas/llamas/7ceb979a-b831-48fd-8b1a-a1c724370ba1.json
16896/cleverllamas/llamaverse/raw/wild-llamas/llamas/b67c3b62-b38b-4cb8-ae04-88a2fdd1ebda.json
16896/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json
16896/cleverllamas/llamaverse/raw/wild-llamas/llamas/eaa6c416-ef46-4f91-b861-1e99b28ae18b.json
16896/cleverllamas/llamaverse/raw/wild-llamas/llamas/58fc1645-17d2-4732-aded-1e88f637f967.json

What to notice: this sample currently returns equal score values for the shown rows, which is still useful for demonstrating how to inspect score metadata directly.

cts:confidence

Useful when raw score numbers are technically correct but conversationally useless.

Source docs: https://docs.marklogic.com/11.0/cts:confidence

Option / ArgumentWhat it controlsUsed here
$nodeThe result node from which confidence is readA node returned by cts:search(...)
{
  "name": "Aaron",
  "breed": "Huacaya",
  "placeOfBirth": "Cusco, Peru",
  "secretPowerId": "d8839ba6-2b77-4bcc-9927-b86cdfecb9fb"
}
xquery version "1.0-ml";

let $query := cts:and-query((
  cts:collection-query("wild-llamas"),
  cts:word-query("sung")
))
for $node in cts:search(fn:doc(), $query)[1 to 5]
return
  map:entry("uri", xdmp:node-uri($node))
  => map:with("score", cts:score($node))
  => map:with("confidence", cts:confidence($node))
'use strict';

const query = cts.andQuery([
  cts.collectionQuery('wild-llamas'),
  cts.wordQuery('sung')
]);

const results = cts.search(query).toArray().slice(0, 5).map((doc) => ({
  uri: xdmp.nodeUri(doc),
  score: cts.score(doc),
  confidence: cts.confidence(doc)
}));

({
  sample: 'cts/relevance-and-scoring-starter-pack/assets/cts-confidence.sjs',
  kind: Array.isArray(results) ? 'rows' : 'object',
  count: Array.isArray(results) ? results.length : 0,
  data: results
});
[
  {
    "score": 58368,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/0a6911e5-0d17-44e1-a114-cb747490f469.json",
    "confidence": 0.4191779
  },
  {
    "score": 28416,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/507cf4de-4469-497f-9888-7756c592b119.json",
    "confidence": 0.2889328
  },
  {
    "score": 27648,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/19be9dcc-fd35-4c54-b503-63a6a8a1043d.json",
    "confidence": 0.2889328
  },
  {
    "score": 27392,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json",
    "confidence": 0.2889328
  },
  {
    "score": 27136,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/cd37f616-e707-47f3-99c0-d20def77c1a6.json",
    "confidence": 0.2889328
  }
]
ScoreConfidenceURI
583680.4191779/cleverllamas/llamaverse/raw/wild-llamas/llamas/0a6911e5-0d17-44e1-a114-cb747490f469.json
284160.2889328/cleverllamas/llamaverse/raw/wild-llamas/llamas/507cf4de-4469-497f-9888-7756c592b119.json
276480.2889328/cleverllamas/llamaverse/raw/wild-llamas/llamas/19be9dcc-fd35-4c54-b503-63a6a8a1043d.json
273920.2889328/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json
271360.2889328/cleverllamas/llamaverse/raw/wild-llamas/llamas/cd37f616-e707-47f3-99c0-d20def77c1a6.json

What to notice: confidence gives you a normalised scoring signal that is easier to compare across nearby results than a large integer score on its own.

cts:fitness

Useful when you want another relevance signal in the room before somebody starts "fixing" the ranking by gut feel.

Source docs: https://docs.marklogic.com/11.0/cts:fitness

Option / ArgumentWhat it controlsUsed here
$nodeThe result node from which fitness is readA node returned by cts:search(...)
{
  "name": "Aaron",
  "breed": "Huacaya",
  "placeOfBirth": "Cusco, Peru",
  "secretPowerId": "d8839ba6-2b77-4bcc-9927-b86cdfecb9fb"
}
xquery version "1.0-ml";

let $query := cts:and-query((
  cts:collection-query("wild-llamas"),
  cts:word-query("sung")
))
for $node in cts:search(fn:doc(), $query)[1 to 5]
return
  map:entry("uri", xdmp:node-uri($node))
  => map:with("score", cts:score($node))
  => map:with("fitness", cts:fitness($node))
'use strict';

const query = cts.andQuery([
  cts.collectionQuery('wild-llamas'),
  cts.wordQuery('sung')
]);

const results = cts.search(query).toArray().slice(0, 5).map((doc) => ({
  uri: xdmp.nodeUri(doc),
  score: cts.score(doc),
  fitness: cts.fitness(doc)
}));

({
  sample: 'cts/relevance-and-scoring-starter-pack/assets/cts-fitness.sjs',
  kind: Array.isArray(results) ? 'rows' : 'object',
  count: Array.isArray(results) ? results.length : 0,
  data: results
});
[
	{
		"score": 58368,
		"fitness": 0.3951162,
		"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/0a6911e5-0d17-44e1-a114-cb747490f469.json"
	},
	{
		"score": 28416,
		"fitness": 0.2723475,
		"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/507cf4de-4469-497f-9888-7756c592b119.json"
	},
	{
		"score": 27648,
		"fitness": 0.2723475,
		"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/19be9dcc-fd35-4c54-b503-63a6a8a1043d.json"
	},
	{
		"score": 27392,
		"fitness": 0.2723475,
		"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json"
	},
	{
		"score": 27136,
		"fitness": 0.2723475,
		"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/cd37f616-e707-47f3-99c0-d20def77c1a6.json"
	}
]
ScoreFitnessURI
583680.3951162/cleverllamas/llamaverse/raw/wild-llamas/llamas/0a6911e5-0d17-44e1-a114-cb747490f469.json
284160.2723475/cleverllamas/llamaverse/raw/wild-llamas/llamas/507cf4de-4469-497f-9888-7756c592b119.json
276480.2723475/cleverllamas/llamaverse/raw/wild-llamas/llamas/19be9dcc-fd35-4c54-b503-63a6a8a1043d.json
273920.2723475/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json
271360.2723475/cleverllamas/llamaverse/raw/wild-llamas/llamas/cd37f616-e707-47f3-99c0-d20def77c1a6.json

What to notice: fitness gives a second normalised relevance lens. It often tracks confidence closely, but treating them as identical is how ranking conversations get fuzzy.

cts:remainder

Useful for quick UI pagination estimates when exact counts are overkill.

Source docs: https://docs.marklogic.com/11.0/cts:remainder

Option / ArgumentWhat it controlsUsed here
$nodeThe result node whose remaining-count estimate is requestedA node returned by cts:search(...)
{
  "name": "Aaron",
  "breed": "Huacaya",
  "placeOfBirth": "Cusco, Peru",
  "secretPowerId": "d8839ba6-2b77-4bcc-9927-b86cdfecb9fb"
}
xquery version "1.0-ml";

let $query := cts:and-query((
  cts:collection-query("wild-llamas"),
  cts:word-query("sung")
))
for $node in cts:search(fn:doc(), $query)[1 to 5]
return
  map:entry("uri", xdmp:node-uri($node))
  => map:with("remainder", cts:remainder($node))
'use strict';

const query = cts.andQuery([
  cts.collectionQuery('wild-llamas'),
  cts.wordQuery('sung')
]);

const results = cts.search(query).toArray().slice(0, 5).map((doc) => ({
  uri: xdmp.nodeUri(doc),
  remainder: cts.remainder(doc)
}));

({
  sample: 'cts/relevance-and-scoring-starter-pack/assets/cts-remainder.sjs',
  kind: Array.isArray(results) ? (results.every((item) => typeof item === 'object' && 'subject' in item && 'predicate' in item && 'object' in item) ? 'triples' : 'rows') : ((results !== null && typeof results === 'object') ? 'object' : 'scalar'),
  count: Array.isArray(results) ? results.length : 0,
  data: results
});
[
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json",
    "remainder": 3001
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/4429e229-490a-4398-992e-84d0f4737d6d.json",
    "remainder": 3000
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/d9af3805-d87d-473b-b01f-67bc8628e3df.json",
    "remainder": 2999
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/78a3ea33-382d-486a-aece-77bae497af14.json",
    "remainder": 2998
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/3cb1a513-b57b-49c4-b80a-e67aa99dd272.json",
    "remainder": 2997
  }
]
URIRemainder
/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json3001
/cleverllamas/llamaverse/raw/wild-llamas/llamas/4429e229-490a-4398-992e-84d0f4737d6d.json3000
/cleverllamas/llamaverse/raw/wild-llamas/llamas/d9af3805-d87d-473b-b01f-67bc8628e3df.json2999
/cleverllamas/llamaverse/raw/wild-llamas/llamas/78a3ea33-382d-486a-aece-77bae497af14.json2998
/cleverllamas/llamaverse/raw/wild-llamas/llamas/3cb1a513-b57b-49c4-b80a-e67aa99dd272.json2997

What to notice: remainder approximates remaining result volume from each returned node context.

cts:quality

A reminder that ranking is not only text relevance.

Source docs: https://docs.marklogic.com/11.0/cts:quality

Option / ArgumentWhat it controlsUsed here
$nodeThe result node from which quality is readA node returned by cts:search(...)

This example is read-only and uses the llamaverse v2.4.0+ quality-profile URI set. Selected wild llama profiles carry curated non-zero document quality values so quality contribution is visible without mutation during runtime.

{
  "name": "Aaron",
  "breed": "Huacaya",
  "placeOfBirth": "Cusco, Peru",
  "secretPowerId": "d8839ba6-2b77-4bcc-9927-b86cdfecb9fb"
}
xquery version "1.0-ml";

let $profile-uris := (
  "/cleverllamas/llamaverse/raw/wild-llamas/llamas/0a6911e5-0d17-44e1-a114-cb747490f469.json",
  "/cleverllamas/llamaverse/raw/wild-llamas/llamas/8520c251-7abe-4eb4-a0e8-6706bf5c2397.json",
  "/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json",
  "/cleverllamas/llamaverse/raw/wild-llamas/llamas/58fc1645-17d2-4732-aded-1e88f637f967.json",
  "/cleverllamas/llamaverse/raw/wild-llamas/llamas/e3f48f8f-ea2b-4382-8313-02430bf34a45.json",
  "/cleverllamas/llamaverse/raw/wild-llamas/llamas/507cf4de-4469-497f-9888-7756c592b119.json",
  "/cleverllamas/llamaverse/raw/wild-llamas/llamas/19be9dcc-fd35-4c54-b503-63a6a8a1043d.json",
  "/cleverllamas/llamaverse/raw/wild-llamas/llamas/cd37f616-e707-47f3-99c0-d20def77c1a6.json",
  "/cleverllamas/llamaverse/raw/wild-llamas/llamas/d50a73a0-c096-4f79-99a0-8bd05a426416.json",
  "/cleverllamas/llamaverse/raw/wild-llamas/llamas/74a7c489-3515-45f9-88bd-2e8261a7e720.json"
)
for $node in fn:doc($profile-uris)
order by cts:quality($node) descending, xdmp:node-uri($node)
return
  map:entry("uri", xdmp:node-uri($node))
  => map:with("quality", cts:quality($node))
'use strict';

const profileUris = [
  '/cleverllamas/llamaverse/raw/wild-llamas/llamas/0a6911e5-0d17-44e1-a114-cb747490f469.json',
  '/cleverllamas/llamaverse/raw/wild-llamas/llamas/8520c251-7abe-4eb4-a0e8-6706bf5c2397.json',
  '/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json',
  '/cleverllamas/llamaverse/raw/wild-llamas/llamas/58fc1645-17d2-4732-aded-1e88f637f967.json',
  '/cleverllamas/llamaverse/raw/wild-llamas/llamas/e3f48f8f-ea2b-4382-8313-02430bf34a45.json',
  '/cleverllamas/llamaverse/raw/wild-llamas/llamas/507cf4de-4469-497f-9888-7756c592b119.json',
  '/cleverllamas/llamaverse/raw/wild-llamas/llamas/19be9dcc-fd35-4c54-b503-63a6a8a1043d.json',
  '/cleverllamas/llamaverse/raw/wild-llamas/llamas/cd37f616-e707-47f3-99c0-d20def77c1a6.json',
  '/cleverllamas/llamaverse/raw/wild-llamas/llamas/d50a73a0-c096-4f79-99a0-8bd05a426416.json',
  '/cleverllamas/llamaverse/raw/wild-llamas/llamas/74a7c489-3515-45f9-88bd-2e8261a7e720.json'
];

const results = profileUris
  .map((uri) => fn.doc(uri))
  .filter((doc) => doc)
  .map((doc) => ({
    uri: xdmp.nodeUri(doc),
    quality: cts.quality(doc)
  }))
  .sort((a, b) => (b.quality - a.quality) || a.uri.localeCompare(b.uri));

({
  sample: 'cts/relevance-and-scoring-starter-pack/assets/cts-quality.sjs',
  kind: Array.isArray(results) ? (results.every((item) => typeof item === 'object' && 'subject' in item && 'predicate' in item && 'object' in item) ? 'triples' : 'rows') : ((results !== null && typeof results === 'object') ? 'object' : 'scalar'),
  count: Array.isArray(results) ? results.length : 0,
  data: results
});
[
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/0a6911e5-0d17-44e1-a114-cb747490f469.json",
    "quality": 7
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/507cf4de-4469-497f-9888-7756c592b119.json",
    "quality": 6
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/d50a73a0-c096-4f79-99a0-8bd05a426416.json",
    "quality": 5
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/8520c251-7abe-4eb4-a0e8-6706bf5c2397.json",
    "quality": 4
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/19be9dcc-fd35-4c54-b503-63a6a8a1043d.json",
    "quality": 3
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json",
    "quality": 2
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/74a7c489-3515-45f9-88bd-2e8261a7e720.json",
    "quality": 2
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/cd37f616-e707-47f3-99c0-d20def77c1a6.json",
    "quality": 1
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/58fc1645-17d2-4732-aded-1e88f637f967.json",
    "quality": 0
  },
  {
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/e3f48f8f-ea2b-4382-8313-02430bf34a45.json",
    "quality": -1
  }
]
URIQuality
/cleverllamas/llamaverse/raw/wild-llamas/llamas/0a6911e5-0d17-44e1-a114-cb747490f469.json7
/cleverllamas/llamaverse/raw/wild-llamas/llamas/507cf4de-4469-497f-9888-7756c592b119.json6
/cleverllamas/llamaverse/raw/wild-llamas/llamas/d50a73a0-c096-4f79-99a0-8bd05a426416.json5
/cleverllamas/llamaverse/raw/wild-llamas/llamas/8520c251-7abe-4eb4-a0e8-6706bf5c2397.json4
/cleverllamas/llamaverse/raw/wild-llamas/llamas/19be9dcc-fd35-4c54-b503-63a6a8a1043d.json3
/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json2
/cleverllamas/llamaverse/raw/wild-llamas/llamas/74a7c489-3515-45f9-88bd-2e8261a7e720.json2
/cleverllamas/llamaverse/raw/wild-llamas/llamas/cd37f616-e707-47f3-99c0-d20def77c1a6.json1
/cleverllamas/llamaverse/raw/wild-llamas/llamas/58fc1645-17d2-4732-aded-1e88f637f967.json0
/cleverllamas/llamaverse/raw/wild-llamas/llamas/e3f48f8f-ea2b-4382-8313-02430bf34a45.json-1

What to notice: quality reveals non-text ranking contribution and is useful in relevance tuning sessions.

cts:relevance-info

Useful when the team stops asking for scores and starts asking for a proper explanation.

Source docs: https://docs.marklogic.com/11.0/cts:relevance-info

Option / ArgumentWhat it controlsUsed here
$nodeThe result node from which relevance trace information is readA node returned by cts:search(...) with tracing enabled

Tiny Flight Recorder, Not Automatic Magic

cts:relevance-info() is the tiny flight recorder for ranking. But it only records anything when you run cts:search(..., ("relevance-trace")) first. No trace flag, no recorder, no breadcrumbs, just polite silence.

{
  "name": "Aaron",
  "breed": "Huacaya",
  "placeOfBirth": "Cusco, Peru",
  "secretPowerId": "d8839ba6-2b77-4bcc-9927-b86cdfecb9fb"
}
xquery version "1.0-ml";

let $query := cts:and-query((
  cts:collection-query("wild-llamas"),
  cts:word-query("sung")
))
for $node in cts:search(fn:doc(), $query, ("relevance-trace"))[1 to 3]
let $info := cts:relevance-info($node)
let $trace := xdmp:quote($info)
return
  map:entry("uri", xdmp:node-uri($node))
  => map:with("score", cts:score($node))
  => map:with("traceRecorded", fn:exists($info))
  => map:with("traceChars", fn:string-length($trace))
  => map:with("tracePreview", fn:substring($trace, 1, 140))
'use strict';

const query = cts.andQuery([
  cts.collectionQuery('wild-llamas'),
  cts.wordQuery('sung')
]);

const results = cts.search(query, ['relevance-trace']).toArray().slice(0, 3).map((doc) => {
  const info = cts.relevanceInfo(doc);
  const trace = xdmp.quote(info);
  return {
    uri: xdmp.nodeUri(doc),
    score: cts.score(doc),
    traceRecorded: fn.exists(info),
    traceChars: fn.stringLength(trace),
    tracePreview: fn.substring(trace, 1, 140)
  };
});

({
  sample: 'cts/relevance-and-scoring-starter-pack/assets/cts-relevance-info.sjs',
  kind: Array.isArray(results) ? 'rows' : 'object',
  count: Array.isArray(results) ? results.length : 0,
  data: results
});
[
  {
    "score": 58368,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/0a6911e5-0d17-44e1-a114-cb747490f469.json",
    "traceRecorded": true,
    "traceChars": 1272,
    "tracePreview": "<qry:relevance-info xmlns:qry=\"http://marklogic.com/cts/query\">\n  <qry:score formula=\"(256*scoreSum/weightSum)+(256*qualityWeight*documentQu"
  },
  {
    "score": 28416,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/507cf4de-4469-497f-9888-7756c592b119.json",
    "traceRecorded": true,
    "traceChars": 1052,
    "tracePreview": "<qry:relevance-info xmlns:qry=\"http://marklogic.com/cts/query\">\n  <qry:score formula=\"(256*scoreSum/weightSum)+(256*qualityWeight*documentQu"
  },
  {
    "score": 27648,
    "uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/19be9dcc-fd35-4c54-b503-63a6a8a1043d.json",
    "traceRecorded": true,
    "traceChars": 1052,
    "tracePreview": "<qry:relevance-info xmlns:qry=\"http://marklogic.com/cts/query\">\n  <qry:score formula=\"(256*scoreSum/weightSum)+(256*qualityWeight*documentQu"
  }
]
ScoreTrace RecordedTrace CharsURI
58368true1272/cleverllamas/llamaverse/raw/wild-llamas/llamas/0a6911e5-0d17-44e1-a114-cb747490f469.json
28416true1052/cleverllamas/llamaverse/raw/wild-llamas/llamas/507cf4de-4469-497f-9888-7756c592b119.json
27648true1052/cleverllamas/llamaverse/raw/wild-llamas/llamas/19be9dcc-fd35-4c54-b503-63a6a8a1043d.json

What to notice: the trace payload is intentionally previewed rather than dumped in full. For ranking analysis, confirming that trace data exists and inspecting a short excerpt is usually enough to prove that explainability is available.

Unlocking the Next Mystery

Decision rule: if ranking questions are slowing delivery, instrument score early and treat query shape as part of your relevance contract.

If you're enjoying the scoring hunt, these sibling topics will deepen your understanding of how MarkLogic ranks results:

Need Some Help?


Looking for more information on this subject or any other topic related to MarkLogic? Contact Us (info@cleverllamas.com) to find out how we can assist you with consulting or training!