Word Queries vs Value Queries
Choosing the Right Query Type
Word queries and value queries are not interchangeable. They may both accept strings, but they answer different classes of question and rely on different matching semantics.
If you have ever seen search results that were technically explainable but practically baffling, this distinction is usually the reason.
Start Here: The Hidden Default
cts:search("...") is already a word query
One subtle but important behaviour: passing a plain string to cts:search() is shorthand for a word query. In other words, cts:search("llama") is treated as if you had written cts:search(cts:word-query("llama")).
This matters because many teams think they are issuing a generic search call, but they are already in word-query semantics (token-based matching, relevance scoring, stemming rules, wildcard behaviour, and so on).
You can inspect this directly:
xquery version "1.0-ml";
let $implicit := cts:search(fn:collection("wild-llamas"), "llama")
let $explicit := cts:search(fn:collection("wild-llamas"), cts:word-query("llama"))
return (
"Implicit query as described by MarkLogic:",
xdmp:describe(cts:word-query("llama")),
"Counts (implicit vs explicit):",
(count($implicit), count($explicit))
)
Implicit query as described by MarkLogic:
cts:word-query("llama", ("lang=en"), 1)
Counts (implicit vs explicit):
3001
3001
When you use the Search API library, the same practical principle applies: generated CTS often includes word-query clauses unless you explicitly model value/range constraints.
The examples in this article assume the llamaverse (v2.3.1+) is deployed. The llamaverse sample data is freely available from github.com/cleverllamas/llamaverse — see the llamaverse article for full setup instructions.
Runtime validation note: all executable XQuery samples in this article were re-run against a live local MarkLogic server (localhost:8010, cleverllamas-content) on 2026-07-22, and results are included alongside each code sample.
Core Query Models
Why this distinction matters
Many production search bugs come from using a query type that does not match the question being asked. Teams often describe their intent as "find value X", then accidentally implement token-based search, or they implement strict value matching where users expected language-aware text relevance.
The fastest way to avoid this is to make the query intent explicit up front:
| Intent | Query family | Typical outcome |
|---|---|---|
| Find documents about a concept in prose | Word queries (cts:word-query) | Linguistic matching and relevance-ranked text search |
| Match a specific field value exactly | Value queries (cts:*-value-query) | Deterministic field-level filtering |
| Apply greater-than/less-than constraints | Range queries (cts:*-range-query) | Ordered comparison over indexed scalar values |
Mental model: token evidence vs field equality
Word queries
Word queries are token-based. They evaluate terms using the word index and are generally the right choice for free-text discovery in descriptions, notes, comments, and narrative content.
xquery version "1.0-ml";
(: Full-text word query against wild-llamas. :)
cts:search(
fn:collection("wild-llamas"),
cts:word-query("Suri")
)[1 to 5] ! xdmp:node-uri(.)
[
{
"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json",
"name": "David",
"breed": "Suri",
"heightCm": "155",
"description": "David is a gray-eyed llama with blonde hair, standing 155 cm tall. Originally from Port Stephaniestad, Haiti, David enjoys knitting, wood carving, painting. Known for their energetic and shy personality, David is a beloved member of the llama community."
},
{
"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/67384a21-62fe-4f80-a964-72783cfb076f.json",
"name": "Lisa",
"breed": "Hybrid",
"heightCm": "149",
"description": "Lisa is a gray-eyed llama with silver hair, standing 149 cm tall. Originally from Kimberlychester, British Indian Ocean Territory (Chagos Archipelago), Lisa enjoys hiking, knitting, wood carving. Known for their mischievous and calm personality, Lisa is a beloved member of the llama community."
}
]
/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/4429e229-490a-4398-992e-84d0f4737d6d.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/d9af3805-d87d-473b-b01f-67bc8628e3df.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/eaa6c416-ef46-4f91-b861-1e99b28ae18b.json
Value queries
Value queries are field-equality checks. They are ideal when the business rule is exact matching on structured properties such as IDs, category names, status fields, or enumerated labels.
xquery version "1.0-ml";
(: Structured value query on one JSON property. :)
cts:search(
fn:collection("wild-llamas"),
cts:json-property-value-query("breed", "Suri", "exact")
)[1 to 5] ! xdmp:node-uri(.)
[
{
"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json",
"name": "David",
"breed": "Suri",
"heightCm": "155",
"description": "David is a gray-eyed llama with blonde hair, standing 155 cm tall. Originally from Port Stephaniestad, Haiti, David enjoys knitting, wood carving, painting. Known for their energetic and shy personality, David is a beloved member of the llama community."
},
{
"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/67384a21-62fe-4f80-a964-72783cfb076f.json",
"name": "Lisa",
"breed": "Hybrid",
"heightCm": "149",
"description": "Lisa is a gray-eyed llama with silver hair, standing 149 cm tall. Originally from Kimberlychester, British Indian Ocean Territory (Chagos Archipelago), Lisa enjoys hiking, knitting, wood carving. Known for their mischievous and calm personality, Lisa is a beloved member of the llama community."
}
]
/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/4429e229-490a-4398-992e-84d0f4737d6d.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/d9af3805-d87d-473b-b01f-67bc8628e3df.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/24a25bb9-b35f-48b3-b01c-d8f4a64d7a2d.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/eaa6c416-ef46-4f91-b861-1e99b28ae18b.json
If your requirement is "this field must be exactly this value", default to value queries.
Live comparison on llamaverse data
xquery version "1.0-ml";
(
concat("word:", fn:count(cts:search(fn:collection("wild-llamas"), cts:word-query("Suri")))),
concat("value:", fn:count(cts:search(fn:collection("wild-llamas"), cts:json-property-value-query("breed", "Suri", "exact"))))
)
[
{
"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json",
"name": "David",
"breed": "Suri",
"heightCm": "155",
"description": "David is a gray-eyed llama with blonde hair, standing 155 cm tall. Originally from Port Stephaniestad, Haiti, David enjoys knitting, wood carving, painting. Known for their energetic and shy personality, David is a beloved member of the llama community."
},
{
"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/67384a21-62fe-4f80-a964-72783cfb076f.json",
"name": "Lisa",
"breed": "Hybrid",
"heightCm": "149",
"description": "Lisa is a gray-eyed llama with silver hair, standing 149 cm tall. Originally from Kimberlychester, British Indian Ocean Territory (Chagos Archipelago), Lisa enjoys hiking, knitting, wood carving. Known for their mischievous and calm personality, Lisa is a beloved member of the llama community."
}
]
word:1047
value:1047
In this dataset the counts are the same for this term and property, but that is not guaranteed in general. Once term distribution or text context changes, word and value results can diverge quickly.
Ordered comparisons belong to range queries
When the question is numeric or temporal ordering, use range queries, not word queries.
xquery version "1.0-ml";
(: Ordered comparison uses a path range index, not a word query. :)
cts:search(
fn:collection("wild-llamas"),
cts:path-range-query("/heightCm", ">=", 120)
)[1 to 5] ! xdmp:node-uri(.)
[
{
"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json",
"name": "David",
"breed": "Suri",
"heightCm": "155",
"description": "David is a gray-eyed llama with blonde hair, standing 155 cm tall. Originally from Port Stephaniestad, Haiti, David enjoys knitting, wood carving, painting. Known for their energetic and shy personality, David is a beloved member of the llama community."
},
{
"uri": "/cleverllamas/llamaverse/raw/wild-llamas/llamas/67384a21-62fe-4f80-a964-72783cfb076f.json",
"name": "Lisa",
"breed": "Hybrid",
"heightCm": "149",
"description": "Lisa is a gray-eyed llama with silver hair, standing 149 cm tall. Originally from Kimberlychester, British Indian Ocean Territory (Chagos Archipelago), Lisa enjoys hiking, knitting, wood carving. Known for their mischievous and calm personality, Lisa is a beloved member of the llama community."
}
]
/cleverllamas/llamaverse/raw/wild-llamas/llamas/67384a21-62fe-4f80-a964-72783cfb076f.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/b3591799-54a8-44ea-87a1-d1c05659f781.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/4429e229-490a-4398-992e-84d0f4737d6d.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/8520c251-7abe-4eb4-a0e8-6706bf5c2397.json
Building Query Plans in Production
Selection guide (keep this handy)
- Use word queries for prose, descriptions, and user search text.
- Use value queries for exact field-level matching.
- Use range queries for ordered numeric/date comparisons.
- Combine structured filters with word queries for best relevance.
Production combination pattern
A common production pattern is:
- Use value queries to narrow to the right entity set.
- Apply word queries for relevance within that set.
- Add range queries for thresholds and windowing.
This preserves precision while still giving useful text relevance.
In practice, this pattern gives you both correctness and speed:
- Structured constraints reduce candidate set size early.
- Relevance scoring runs over a smaller, more meaningful subset.
- Range constraints enforce hard business rules (dates, numbers, durations).
Filtered vs unfiltered behaviour
Both query families are index-driven, but filtered mode validates candidates more strictly while unfiltered mode can return faster approximate results in some cases. For strict field equality and compliance-sensitive filtering, filtered search is usually the safer default.
Operational rule:
| Scenario | Recommended mode |
|---|---|
| Compliance/security-sensitive filtering | Filtered |
| Exploratory search where minor approximation is acceptable | Consider unfiltered, then validate |
| Debugging result correctness | Always compare in filtered mode |
Cost and Index Strategy for Word Queries
Index expectations
Correct query family selection is necessary, but not sufficient. You also need appropriate indexes.
| Query family | Depends on |
|---|---|
| Word queries | Word index and related text settings |
| Value queries | Property/element value query support and scalar index configuration |
| Range queries | Matching range/path range indexes with correct scalar type |
A mismatch between query type and index configuration often appears as one of these symptoms:
- Correct-looking query with poor performance.
- Correct-looking query with unexpectedly empty or broad results.
- Overuse of fallback logic in application code.
Database settings that change word query cost
Word queries are highly sensitive to database text-index settings. This is where many teams accidentally trade query convenience for long-term operational cost.
High-Impact Settings
| Setting | What it changes | Cost impact |
|---|---|---|
| Stemmed searches | Expands term matching to linguistic stems | Broader recall, slightly more scoring work |
| Word positions | Enables accurate positional/proximity behaviour | Larger index footprint, higher ingest cost |
| Trailing wildcard searches | Makes suffix-wildcard patterns (term*) index-friendly | Extra index space and reindex overhead |
| Three/two/one character searches | Supports shorter wildcard/token patterns efficiently | Significant index growth and ingest overhead |
| Word lexicons | Enables lexicon-driven term enumeration (cts:words, cts:element-words) | Additional lexicon structures and memory pressure |
| Phrase-throughs | Allows phrase matching across configured element/property boundaries | More phrase index complexity; needs correct upfront modelling |
| Phrase-arounds | Skips configured markup boundaries during phrase evaluation | Changes phrase semantics and must be configured intentionally |
Stemming explained with run, ran, running
Stemming means MarkLogic can treat morphological variants of a term as related forms during word matching. In practical English search behaviour, a query for run can match tokens such as run, running, and often irregular forms such as ran when stemming is enabled.
Why this matters:
- Better recall for free-text search because users do not need to guess exact inflection.
- Potentially broader candidate sets, which can increase scoring and filtering work.
- Less appropriate for strict terminology fields where exact wording is important.
You can demonstrate the difference directly:
xquery version "1.0-ml";
let $stemmed := cts:search(
fn:collection("wild-llamas"),
cts:word-query("run", ("stemmed"))
)
let $unstemmed := cts:search(
fn:collection("wild-llamas"),
cts:word-query("run", ("unstemmed"))
)
return (
"Stemmed count:", count($stemmed),
"Unstemmed count:", count($unstemmed)
)
Stemmed count:
0
Unstemmed count:
0
In most prose-heavy datasets, the stemmed count is higher because inflected variants are included. That is usually desirable in discovery search, but it can be noisy in compliance or exact-term scenarios.
Phrase-through and phrase-around (important and often missed)
These two settings materially change phrase behaviour around markup boundaries.
phrase-through: phrase matching can cross configured element/property boundaries.phrase-around: phrase matching can skip around configured element/property boundaries.
Conceptually, this determines whether text separated by markup is treated as one phrase stream or as hard phrase boundaries.
Why this is operationally important:
- It changes correctness, not just performance.
- It must be known at load/reindex time so indexes store the right phrase information.
- Removing/changing these settings later may require explicit reindex strategy to avoid stale expectations.
Rule of thumb:
| Content model | Suggested phrase setting posture |
|---|---|
| Richly marked prose where inline tags should not break phrases | Consider targeted phrase-through |
| Markup used as structural boundaries that should break phrase semantics | Avoid broad phrase-through/around |
| Mixed XML/JSON with ambiguous sectioning | Apply narrowly and test with real phrase queries |
If phrase relevance looks inconsistent around inline tags, inspect phrase-through/around settings before changing query code.
Wildcard Indexes: Why You Might Not Want All of Them
It is tempting to keep enabling wildcard support (especially three-character searches) when users ask for looser matching. The trade-off is real:
- Larger indexes increase storage and reindex windows.
- Ingestion/update throughput can drop as index maintenance grows.
- Memory pressure rises, especially in mixed query workloads.
For many systems, it is better to enable only what query logs justify, rather than turning on every wildcard-related option pre-emptively.
Practical policy:
| Pattern observed in real queries | Recommendation |
|---|---|
| Mostly exact terms and phrases | Keep wildcard indexes minimal |
Frequent user prefix search (bio*, lam*) | Consider trailing wildcard only |
| Heavy short-token wildcard usage from product requirements | Evaluate targeted index enablement with capacity planning |
| Rare exploratory wildcard traffic | Prefer alternative expansion strategies before enabling more indexes |
Cost-Aware Rule of Thumb
Treat index additions as infrastructure changes, not query tweaks. The right question is not only "does this query become faster?" but also:
- what does this add to ingest/reindex cost?
- how much index growth will it cause?
- is there a lower-cost query pattern that satisfies the same user intent?
Advanced Alternative: Controlled Term Expansion
Sometimes the better approach is not broader wildcard indexes, but controlled expansion of candidate terms using lexicons or dictionaries.
Approach 1: Expand from Element Word Lexicons
When you have a known structured section (for example a description element/property), use the word lexicon to enumerate likely terms, then build a focused or query from that set.
Conceptual flow:
- Pull candidate terms from
cts:element-words(...)(orcts:words(...)in broader cases). - Apply constraints (prefix, frequency threshold, max count).
- Build a bounded query from selected terms.
xquery version "1.0-ml";
(: Demonstrate controlled term expansion pattern :)
(: Instead of a wildcard query, build an explicit OR query from known values. :)
let $known-species := ("Huacaya", "Suri")
let $search-results := cts:search(
fn:collection("wild-llamas"),
cts:or-query(
for $species in $known-species
return cts:field-value-query("llama-species-unified", $species)
)
)
return (
fn:count($search-results),
for $doc in $search-results[1 to 3]
return xdmp:node-uri($doc)
)
2034
/cleverllamas/llamaverse/raw/wild-llamas/llamas/c45a4f65-d14a-4206-b921-ffc9470e14bb.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/4429e229-490a-4398-992e-84d0f4737d6d.json
/cleverllamas/llamaverse/raw/wild-llamas/llamas/d9af3805-d87d-473b-b01f-67bc8628e3df.json
Why this helps: you cap expansion explicitly instead of opening query complexity with unconstrained wildcards.
Approach 2: Expand from Dictionaries/Thesauri
For domain terminology (product names, abbreviations, controlled synonyms), dictionary-backed expansion often gives higher precision than pure wildcarding.
Typical strategy:
- Maintain approved term variants in a dictionary/thesaurus source.
- Expand user input to a curated synonym set.
- Query with explicit terms and tuned weights (primary term higher, variants lower).
This usually produces cleaner relevance than broad wildcard matching because expansions are curated, not just string-pattern based.
Choosing Between Expansion and More Indexes
| Need | Better fit |
|---|---|
| General, high-volume prefix search across arbitrary text | Index-backed wildcard support |
| Domain-specific vocabulary expansion | Dictionary/thesaurus expansion |
| Controlled section search with manageable term space | Lexicon-based expansion |
| Cost-sensitive systems with strict ingest SLAs | Expansion first, index additions second |
Common Failure Modes
| Mistake | Consequence | Better approach |
|---|---|---|
| Using word queries for strict field equality | Over-broad matches and noisy ranking | Use value queries scoped to the property/element |
| Using value queries for prose discovery | Weak recall and poor relevance ordering | Use word queries for narrative text |
| Using word queries for date/number thresholds | Semantically incorrect comparisons | Use range queries with matching scalar indexes |
| Tuning boost/weight before fixing query family | Hard-to-explain ranking behaviour | Choose correct query family first, then tune |
| Mixing query families without intent | Fragile, opaque query logic | Document intent per clause and combine deliberately |
| Enabling wildcard indexes reactively for every new query complaint | Growing index/storage cost with unclear ROI | Analyse query logs and evaluate expansion patterns first |
Final Takeaway
Query quality starts with intent clarity. If the requirement is about language evidence in prose, use word queries. If the requirement is exact field equality, use value queries. If the requirement is ordering over typed values, use range queries.
Most teams get the best results by combining all three deliberately rather than forcing one query type to do everything.
In practice, that one decision tends to separate search systems that stay predictable from search systems that feel like a weekly mystery novel.
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!
- Start Here: The Hidden Default
- cts:search("...") is already a word query
- Core Query Models
- Why this distinction matters
- Mental model: token evidence vs field equality
- Word queries
- Value queries
- Live comparison on llamaverse data
- Ordered comparisons belong to range queries
- Building Query Plans in Production
- Selection guide (keep this handy)
- Production combination pattern
- Filtered vs unfiltered behaviour
- Cost and Index Strategy for Word Queries
- Index expectations
- Database settings that change word query cost
- High-Impact Settings
- Stemming explained with run, ran, running
- Phrase-through and phrase-around (important and often missed)
- Wildcard Indexes: Why You Might Not Want All of Them
- Cost-Aware Rule of Thumb
- Advanced Alternative: Controlled Term Expansion
- Choosing Between Expansion and More Indexes
- Common Failure Modes
- Final Takeaway