Filter JSON by meaning
Use this when exact string matching is too brittle: support tickets that say the same thing in different words, log messages that imply the same failure, or records where the field name is known but the wording is messy.
ajq keeps the surrounding jq pipeline deterministic. Only the explicit semantic predicate
(=~, !~, or sem_match) asks a backend for a judgement.
Try the query with no network
The mock backend is deterministic and in-process, so it needs no model, network, or API key. It is useful for checking the jq shape before paying for model calls:
printf '[{"id":1,"msg":"payment failed during checkout"},{"id":2,"msg":"new avatar uploaded"}]' \
| ajq --backend mock -c '.[] | select(.msg =~ "payment failed") | {id, msg}'
Expected output with the mock backend:
{"id":1,"msg":"payment failed during checkout"}
The predicate .msg =~ "payment failed" is shorthand for
sem_match(.msg; "payment failed"). Everything else is ordinary jq.
Run the same filter on a real backend
After the command shape is correct, choose a backend that can make real semantic judgements:
# Managed local backend after `ajq provision`
printf '[{"id":1,"msg":"card declined at checkout"},{"id":2,"msg":"profile photo changed"}]' \
| ajq --backend local --max-calls 10 -c '.[] | select(.msg =~ "payment failure") | {id, msg}'
# Anthropic cloud backend, using ANTHROPIC_API_KEY from the environment
printf '[{"id":1,"msg":"card declined at checkout"},{"id":2,"msg":"profile photo changed"}]' \
| ajq --cloud --max-calls 10 -c '.[] | select(.msg =~ "payment failure") | {id, msg}'
Paid backends default to a 100-call cap. Setting a smaller --max-calls while you tune a
query makes accidental large runs fail before crossing your budget.
Estimate, cap, and cache the work
Before running against a real model, ask ajq to explain the semantic plan:
printf '[{"msg":"payment failed"},{"msg":"payment failed"},{"msg":"avatar uploaded"}]' \
| ajq --explain '.[] | select(.msg =~ "payment failure") | .msg'
The value to budget against is post_dedup_judgements: repeated values are judged once
per backend/model/spec/value cache key. Successful judgements are stored in the persistent
cache, so rerunning the same query can hit the cache instead of the backend. Use
--no-cache only when you intentionally want to avoid reading or writing cached
judgements.
Keep filters within shipped semantic shapes
For production filtering, prefer =~, !~, or sem_match. Standalone semantic
extraction and redaction are registered but currently unsupported, so do not build a
filter that assumes ajq can extract arbitrary fields or redact text as a standalone
transform.
Related
- Semantic functions reference — exact function forms, return types, and current limits.
- Backends reference — backend names, model requirements, credentials, and default caps.
- Estimate model calls — read
--explainestimates before executing. - Manage the judgement cache — inspect, bypass, or clear cached judgements.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.