Skip to content

Filter Operators

Show:

Filter operators let you narrow bucket search results by metadata predicates. In the v2 bucket search request body, pass them inside the filter object. Plain scalar values are exact-match shortcuts; wrap a value in an operator object to express richer predicates.

Note: Metadata values are stored and compared as strings. Booleans become "true"/"false" and numbers are coerced to strings before matching.

VersionStatusNotes
v2CurrentPOST /v2/buckets/\{bucket_id\}/search. Use for all new integrations.
v1DeprecatedPOST /v1/buckets/\{bucket_id\}/search is kept for existing clients and returns Deprecation, Warning, and Link headers pointing to the v2 successor.

POST /v1/buckets/\{bucket_id\}/search is deprecated and accepts the same filter operators documented on this page. New integrations should use POST /v2/buckets/\{bucket_id\}/search instead.

OperatorTypeExampleNotes
eqany{"eq": "urgent"}Exact match. Top-level eq is lowered to the engine fast path.
neany{"ne": "draft"}Not-equal. Applied as a post-filter.
likestring{"like": "%legal%"}SQL LIKE: % matches any sequence, _ matches one char, \% / \_ are literals. Case-insensitive.
prefixstring{"prefix": "2024-"}Starts-with. Case-insensitive.
inarray{"in": ["a", "b"]}Membership test. Maximum 100 entries.
gt / gtenumber / ISO date{"gte": 0.8}Greater-than (or equal).
lt / ltenumber / ISO date{"lt": 100}Less-than (or equal).
existsboolean{"exists": true}Field presence: true means present and non-empty; false means missing or empty.

Each operator object must contain exactly one key. A single filter key can use only one operator at a time.

Use $or to express disjunctions across different metadata keys. $or accepts a list of sub-filter dictionaries and can be nested up to 3 levels.

{
"filter": {
"doc_type": "policy",
"$or": [
{"severity": "high"},
{"priority": {"in": ["P0", "P1"]}}
]
}
}

Top-level keys are still AND. The example matches documents where doc_type = "policy" AND (severity = "high" OR priority ∈ {"P0", "P1"}). Each arm is a full sub-filter and can use any operator. A single $or list supports up to 16 arms.

  • Top-level keys in filter are conjunctive (AND).
  • Same-key OR uses the in operator; cross-key OR uses $or.
  • Exact-match keys are pushed to the vector engine for pruning. Operator keys are evaluated server-side on returned candidates, so the engine fast path stays untouched.
LimitValue
Max filter JSON size (internal filter query param)8 KB
Max filter nesting depth16
like / prefix pattern length256 characters
like wildcard count (% + _)16
in list length100 entries
$or nesting depth3 levels
$or arms per list16

Patterns are translated to anchored case-insensitive regex with all regex metacharacters escaped, so there is no SQL injection surface.

Search a bucket with a text query and metadata filters.

NameTypeDescription
bucket_idstringUUID or slug of the bucket to search.
FieldTypeRequiredDefaultDescription
querystringYesNatural-language query. Maximum 8,192 characters.
top_kintegerNo10Maximum number of results to return.
filterobjectNonullMetadata predicates. Plain values are exact match; operator objects use the operators above.
modestringNo"hybrid""vector" or "hybrid".
rerankbooleanNofalseWhether to rerank candidates.
min_scorenumberNonullMinimum score threshold (0.01.0).
Terminal window
curl -X POST ${API_BASE_URL:-https://api.schift.io}/v2/buckets/product-docs/search \
-H "Authorization: Bearer $SCHIFT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "fire safety inspection cycle",
"top_k": 10,
"filter": {
"tag": "urgent",
"source_url": {"like": "%fire-safety%"},
"filename": {"prefix": "2024-"},
"doc_type": {"in": ["policy", "spec"]},
"score": {"gte": 0.8},
"stage": {"ne": "draft"},
"author": {"exists": true},
"$or": [
{"severity": "high"},
{"priority": {"in": ["P0", "P1"]}}
]
}
}'
FieldTypeDescription
bucket_idstringBucket that was searched.
querystringQuery that was executed.
search_idstring | nullServer-generated search identifier.
resultsarrayMatching chunks, ordered by relevance.
results[].idstringChunk identifier.
results[].scorenumberFinal relevance score.
results[].textstringChunk text.
results[].metadataobjectChunk metadata.
results[].citationstring | nullFormatted citation, if requested.
degradedbooleanWhether the response was produced in a degraded mode.
warningsarraySearch warnings, if any.
{
"bucket_id": "product-docs",
"query": "fire safety inspection cycle",
"search_id": "srch_01j8x9q2mvk8r",
"results": [
{
"id": "chunk_01j8x9q2mvn9q",
"score": 0.91,
"text": "Annual fire safety inspections must follow the 2024 inspection cycle.",
"metadata": {
"doc_type": "policy",
"filename": "2024-fire-safety.pdf",
"tag": "urgent",
"author": "safety-team"
},
"citation": "[1] 2024-fire-safety.pdf, p. 4"
}
],
"degraded": false,
"warnings": []
}
// 400 Bad Request — invalid operator combination
{
"detail": "FilterOperator must have exactly one of eq/ne/like/prefix/in/gt/gte/lt/lte/exists"
}
// 400 Bad Request — unsupported filter key
{
"detail": "Invalid filter: unsupported metadata key 'internal_tag'"
}
// 413 Payload Too Large — filter exceeds size limit
{
"detail": "filter parameter exceeds 8KB"
}
// 413 Payload Too Large — filter too deeply nested
{
"detail": "filter JSON exceeds nesting depth"
}
// 402 Payment Required — search quota exhausted
{
"allowed": false,
"reason": "quota_exceeded"
}
// 403 Forbidden — search quota unavailable
{
"detail": "Search quota unavailable. Upgrade your plan."
}
// 404 Not Found
{
"detail": "Bucket 'product-docs' not found"
}