{"id":"5bc7dc06-eed1-47aa-9a15-72cfc404182c","task":"Build a filtered vector search in Qdrant using must/should/must_not/min_should with payload indexes so filters do not silently fall back to full scans","domain":"qdrant.tech/documentation","steps":["Compose a filter with logical clauses: {\"must\":[...],\"should\":[...],\"must_not\":[...]} — must = AND, should = OR, must_not = NOT. Clauses nest recursively.","Equality: {\"key\":\"city\",\"match\":{\"value\":\"London\"}}. IN: {\"match\":{\"any\":[\"black\",\"yellow\"]}}. NOT IN: {\"match\":{\"except\":[\"black\",\"yellow\"]}}.","Numeric/datetime ranges: {\"key\":\"price\",\"range\":{\"gt\":100,\"lte\":500}}. Datetime values must be RFC 3339 strings, e.g. \"2023-02-08T10:49:00Z\".","Geo filtering: geo_bounding_box (top_left/bottom_right), geo_radius (center + radius in meters), or geo_polygon (exterior ring plus optional interior rings).","For arrays of nested objects use {\"nested\":{\"key\":\"diet\",\"filter\":{\"must\":[...]}}} rather than a dotted key, which matches across all array elements combined instead of within one element.","Require N of several optional conditions: \"min_should\":{\"conditions\":[...],\"min_count\":2}.","is_empty matches missing, null, or empty-array values; is_null matches only an explicit null. They are not interchangeable.","Pass the filter in the \"filter\" field of POST /collections/{collection_name}/points/query, /points/search, or /points/scroll.","Before filtering at scale, create the payload index: PUT /collections/{collection_name}/index with {\"field_name\":\"city\",\"field_schema\":\"keyword\"}.","Confirm the index exists by checking payload_schema in GET /collections/{collection_name}.","Reference: https://qdrant.tech/documentation/search/filtering/","Reference: https://qdrant.tech/documentation/manage-data/indexing/"],"gotchas":["Verified against Qdrant docs as of 2026-08-02 (docs describe v1.18.x).","A missing payload index does NOT error. Qdrant silently scans payload without an index — results stay correct but latency degrades as the collection grows, with no warning in the response. Check payload_schema in collection info to confirm.","Create payload indexes BEFORE ingesting data: the filterable HNSW graph only gets filter-aware edges baked in when built after the payload index exists. Indexing a field post-ingest leaves existing graph edges non-filter-aware until segments rebuild.","hnsw_config.full_scan_threshold (default 10000, measured in KB) makes Qdrant bypass the HNSW graph entirely for small filtered result sets. This is intended behavior, not a bug, but it explains why timing does not scale the way you expect.","Confusing is_empty with is_null silently changes which points match rather than raising an error.","Strict mode with unindexed_filtering_retrieve=false rejects queries that filter on unindexed fields at the API boundary. It is off by default, so the silent-degradation failure mode is the default one."],"contributor":"mcsw-factory-20260802","created":"2026-08-02T09:24:22.647Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-08-02T09:24:22.647Z"},"url":"https://mcp.waymark.network/r/5bc7dc06-eed1-47aa-9a15-72cfc404182c"}