Query Configs and quote_mode Guide
This guide explains how to configure per-query behavior with Query Configs (qcfg) and how to test quote_mode correctly.
What To Know First
- Exact match is done on normalized query text.
- On create, send
queryonly. The system computesnormalized_queryautomatically. quote_modeand query-levelsearch_configare configured via Admin APIs (or index settings), not passed directly in the/searchrequest body.- Do not edit Query Config records directly in DynamoDB. Use APIs so shard/artifact rebuild and KV sync are triggered.
How Exact Match Works
When a search request comes in, the Ecom API normalizes the incoming q and looks for a Query Config with the same normalized value.
Examples that normalize to the same value:
OrléansorleansORLEANS
If those normalize to the same key, they will all match the same qcfg.
quote_mode Values
For query air jordan 1:
quote_mode |
Output query form |
|---|---|
no_quotes |
air jordan 1 |
phrase |
"air jordan 1" |
token |
"air" "jordan" "1" |
tokens_except_first |
air "jordan" "1" |
tokens_except_last |
"air" "jordan" 1 |
Notes:
- Per-query
quote_modein qcfg overrides index-levelquote_mode. no_quotesexplicitly disables quoting (useful to override index-level quoting).quote_modeis not applied for image queries, multi-term object queries, orsearchMethod = TENSOR.- For lexical false positives like
air jordan 1matchingair jordan 11, start withtoken.
Environment Setup
export ECOM_HOST=https://staging-ecom.dev-marqo.org
export HOST=https://staging-admin.dev-marqo.org
export SYSTEM_ACCOUNT_ID=<system_account_id>
export INDEX_NAME=<index_name>
Query Config Admin API Workflow
1) Check index details first
cloudflared access curl "$HOST/api/v1/admin/accounts/$SYSTEM_ACCOUNT_ID/indexes/$INDEX_NAME" | jq
Recommended check: confirm query config overrides are enabled for the index (feature_flags.qcfg_overrides).
2) Create query configs
cloudflared access curl "$HOST/api/v1/accounts/$SYSTEM_ACCOUNT_ID/indexes/$INDEX_NAME/query-configs" \
-sS -X POST \
-H "Content-Type: application/json" \
--data '[
{
"query": "air jordan 1",
"quote_mode": "token",
"search_config": {
"searchMethod": "HYBRID",
"hybridParameters": { "alpha": 0.15 }
},
"updated_by": "[email protected]",
"reason_for_update": "Reduce lexical false positives for AJ1"
}
]' | jq
Response shape is batch-based:
succeeded: items writtenfailed: item-level errors- HTTP
207if partial success,200if all succeeded
3) Get one config
Use the normalized query in the path:
ENC=$(printf '%s' "air jordan 1" | jq -sRr @uri)
cloudflared access curl "$HOST/api/v1/accounts/$SYSTEM_ACCOUNT_ID/indexes/$INDEX_NAME/query-configs/$ENC" | jq
4) List configs
cloudflared access curl "$HOST/api/v1/accounts/$SYSTEM_ACCOUNT_ID/indexes/$INDEX_NAME/query-configs?limit=50" | jq
cloudflared access curl "$HOST/api/v1/accounts/$SYSTEM_ACCOUNT_ID/indexes/$INDEX_NAME/query-configs?limit=50&q_prefix=air%20jordan" | jq
5) Update configs
Use normalized_query for updates:
cloudflared access curl "$HOST/api/v1/accounts/$SYSTEM_ACCOUNT_ID/indexes/$INDEX_NAME/query-configs" \
-sS -X PUT \
-H "Content-Type: application/json" \
--data '[
{
"normalized_query": "air jordan 1",
"quote_mode": "phrase",
"updated_by": "[email protected]",
"reason_for_update": "Try phrase mode"
}
]' | jq
Nullable update behavior:
- Omit
quote_modeto keep the current value. - Send
"quote_mode": nullto clear it (inherit index-level setting).
6) Delete configs
Delete by normalized query keys:
cloudflared access curl "$HOST/api/v1/accounts/$SYSTEM_ACCOUNT_ID/indexes/$INDEX_NAME/query-configs" \
-sS -X DELETE \
-H "Content-Type: application/json" \
--data-binary '["air jordan 1"]' | jq
How To Test quote_mode Correctly
Correct test flow
- Set
quote_modein qcfg (or index settings), not in/searchbody. - Send Ecom search request with
x-marqo-search-request: true. - Inspect the response header
x-marqo-search-requestto verify what was sent to classic Marqo.
Example:
curl -sS -i \
-H "x-marqo-index-id: ${SYSTEM_ACCOUNT_ID}-${INDEX_NAME}" \
-H "x-marqo-search-request: true" \
-H "Content-Type: application/json" \
-X POST \
--data '{"q":"air jordan 1","limit":20}' \
"$ECOM_HOST/api/v1/indexes/$INDEX_NAME/search"
Look for x-marqo-search-request in the response headers:
- If only quoting is active, expect quoted
q. - If quoting +
query_lexical_expansionare active, expect: hybridParameters.queryTensor: unquoted queryhybridParameters.queryLexical: quoted query plus unquoted expansionsqremoved
Representative header examples:
x-marqo-search-request: {"q":"\"air\" \"jordan\" \"1\"","limit":20,"searchMethod":"HYBRID","hybridParameters":{"alpha":0.15}}
x-marqo-search-request: {"limit":20,"searchMethod":"HYBRID","hybridParameters":{"alpha":0.15,"queryTensor":"air jordan 1","queryLexical":"\"air\" \"jordan\" \"1\" retro sneaker"}}
Notes:
- Header value is JSON serialized as a single-line string.
- Exact extra fields vary by index
search_config; focus onqvsqueryTensor/queryLexical.
Common mistake
Do not send quote_mode in this /search payload:
{
"q": "mens basketball shoes",
"quote_mode": "token"
}
That does not configure qcfg behavior. Configure quote_mode through Query Config APIs or index settings.
Manual Classic API Comparison (Optional)
If you want to manually simulate quoting behavior against classic Marqo:
- Quote
queryLexicalmanually. - Keep
queryTensorunquoted. - Do not send
qwhen sendingqueryTensororqueryLexical.
Use this only as a behavior check. To test real qcfg-driven quote_mode, go through Ecom API.
Troubleshooting Checklist
- No difference between modes:
- Confirm
quote_modeis stored in qcfg (GET query-config endpoint). - Confirm you are checking
x-marqo-search-requestresponse header. - Confirm search method is not tensor-only.
- Config not matching:
- Confirm the incoming query normalizes to your qcfg key.
- Remember exact matching is normalized-string equality.
- Unexpected behavior after direct table edits:
- Revert to Admin API writes only; direct DDB writes bypass rebuild/sync workflows.