{
  "id": "search",
  "title": "Search and filter your data",
  "url": "https://redis.io/docs/latest/develop/get-started/search-tutorial/search/",
  "summary": "Use FT.SEARCH to find documents by full text, tags, and numeric ranges, and to return only the fields you want.",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-08-03T12:11:45-07:00",
  "page_type": "content",
  "content_hash": "e93b29829b94b2ff48ee1a523c76a89cfb464755dacf12ff143e88fbe28e03e1",
  "sections": [
    {
      "id": "return-everything",
      "title": "Return everything",
      "role": "returns",
      "text": "The `*` query matches every document. Use it to confirm the index is working. The first line of the result is the total number of matches:\n\nFoundational: Match every document with the wildcard query to confirm the index works\n\n**Difficulty:** Beginner\n\n**Commands:** FT.SEARCH\n\n**Complexity:**\n- FT.SEARCH: O(N)\n\n**Available in:** Redis CLI, Python\n\n##### Redis CLI\n\n[code example]\n\n##### Python\n\n[code example]\n\n\n\nThe `LIMIT 0 0` clause asks for zero documents, so you get just the count. By default `FT.SEARCH` returns the full document for each match, which is verbose. The rest of this page uses `RETURN` to keep the output readable."
    },
    {
      "id": "full-text-search",
      "title": "Full-text search",
      "role": "content",
      "text": "Fields you indexed as `TEXT` support full-text search: matching by word, regardless of position or surrounding text. To search a specific field, prefix the term with `@fieldname:`.\n\nThis finds products whose `name` contains the word *headphones*:\n\nFull-text search: Match a word within a TEXT field using the @field:term syntax\n\n**Difficulty:** Beginner\n\n**Commands:** FT.SEARCH\n\n**Complexity:**\n- FT.SEARCH: O(N)\n\n**Available in:** Redis CLI, Python\n\n##### Redis CLI\n\n[code example]\n\n##### Python\n\n[code example]\n\n\n\nFull-text matching is case-insensitive and word-based, so `headphones` matches `Headphones`. You can also search across all `TEXT` fields at once by leaving off the `@field:` prefix; for example, `FT.SEARCH idx:catalog \"wireless\"` matches any product with *wireless* in its name or description."
    },
    {
      "id": "match-an-exact-phrase",
      "title": "Match an exact phrase",
      "role": "content",
      "text": "To match an exact phrase &mdash; several words that must appear together and in order &mdash; wrap the phrase in escaped double quotes. This finds products whose description contains the phrase *noise cancelling*:\n\nExact phrase: Match an ordered, contiguous phrase in a TEXT field by wrapping it in escaped double quotes\n\n**Difficulty:** Intermediate\n\n**Commands:** FT.SEARCH\n\n**Complexity:**\n- FT.SEARCH: O(N)\n\n**Available in:** Redis CLI, Python\n\n##### Redis CLI\n\n[code example]\n\n##### Python\n\n[code example]\n\n\n\nWithout the quotes, `@description:noise cancelling` matches the two words independently: both must be present, but they can appear anywhere in the field and in any order. The quotes are what require them to sit together as a phrase."
    },
    {
      "id": "filter-by-tag",
      "title": "Filter by tag",
      "role": "content",
      "text": "Fields you indexed as `TAG` match on exact values. Tag values go inside curly braces: `@field:{value}`.\n\nThis finds every product in the `Audio` category and returns the name and price of each:\n\nTag filter: Match an exact TAG value using the @field:{value} syntax\n\n**Difficulty:** Beginner\n\n**Commands:** FT.SEARCH\n\n**Complexity:**\n- FT.SEARCH: O(N)\n\n**Available in:** Redis CLI, Python\n\n##### Redis CLI\n\n[code example]\n\n##### Python\n\n[code example]\n\n\n\nBecause `features` was indexed as a multi-value tag (the `[*]` from the [previous step](https://redis.io/docs/latest/develop/get-started/search-tutorial/indexing)), the same syntax filters on individual list elements. This finds every `waterproof` product:\n\nTag filter on arrays: Match a single element of a multi-value TAG field\n\n**Difficulty:** Beginner\n\n**Commands:** FT.SEARCH\n\n**Complexity:**\n- FT.SEARCH: O(N)\n\n**Available in:** Redis CLI, Python\n\n##### Redis CLI\n\n[code example]\n\n##### Python\n\n[code example]"
    },
    {
      "id": "filter-by-numeric-range",
      "title": "Filter by numeric range",
      "role": "content",
      "text": "Fields you indexed as `NUMERIC` match on ranges, written as `@field:[min max]`. This finds products priced at $100 or less, sorted from cheapest to most expensive with `SORTBY`:\n\nNumeric range: Match a NUMERIC field within [min max] and order results with SORTBY\n\n**Difficulty:** Beginner\n\n**Commands:** FT.SEARCH\n\n**Complexity:**\n- FT.SEARCH: O(N)\n\n**Available in:** Redis CLI, Python\n\n##### Redis CLI\n\n[code example]\n\n##### Python\n\n[code example]\n\n\n\nUse `-inf` and `+inf` for open-ended ranges. For example, `@price:[1000 +inf]` matches everything priced $1000 or more."
    },
    {
      "id": "combine-conditions",
      "title": "Combine conditions",
      "role": "content",
      "text": "Real questions usually combine several conditions. Listing expressions one after another means **AND**: every condition must match. This finds Audio products that also cost $100 or less:\n\nCombined query: AND multiple conditions by listing them together (tag plus numeric range)\n\n**Difficulty:** Intermediate\n\n**Commands:** FT.SEARCH\n\n**Complexity:**\n- FT.SEARCH: O(N)\n\n**Available in:** Redis CLI, Python\n\n##### Redis CLI\n\n[code example]\n\n##### Python\n\n[code example]\n\n\n\nOnly the BudsMini Earbuds satisfy both conditions. You can also express OR with `|` and negation with `-`. See [Combined queries](https://redis.io/docs/latest/develop/ai/search-and-query/query/combined) for the full set of operators."
    },
    {
      "id": "projection-return-only-what-you-need",
      "title": "Projection: return only what you need",
      "role": "content",
      "text": "You have already been using `RETURN` to pick fields. It is worth calling out on its own, because returning only the fields you need keeps responses small and fast:\n\n- `RETURN 2 name price` returns just those two fields.\n- Without `RETURN`, the full document comes back for every match.\n- `LIMIT <offset> <count>` controls how many results you get and is the basis for pagination. By default, `FT.SEARCH` returns the first 10 matches.\n\nThis returns the three most expensive products, newest pricing first, with only their name and price:\n\nProjection and paging: Return only chosen fields, sort, and page results with RETURN, SORTBY, and LIMIT\n\n**Difficulty:** Intermediate\n\n**Commands:** FT.SEARCH\n\n**Complexity:**\n- FT.SEARCH: O(N)\n\n**Available in:** Redis CLI, Python\n\n##### Redis CLI\n\n[code example]\n\n##### Python\n\n[code example]\n\n\n\nThe total is still `12` (the count of all matches), but only three documents are returned because of `LIMIT 0 3`.\n\n\nThe [Redis Insight Search workspace](https://redis.io/docs/latest/develop/tools/insight/search-workspace) has a query editor that understands your index schema. As you type `@`, it suggests field names and tag values, and it renders results as a table instead of the numbered list you see in `redis-cli`. It is a comfortable place to experiment with the queries on this page."
    },
    {
      "id": "next-steps",
      "title": "Next steps",
      "role": "content",
      "text": "`FT.SEARCH` finds and returns documents. When you need to *summarize* across many documents &mdash; counts, averages, totals per group &mdash; you use a different command. Continue to [aggregation](https://redis.io/docs/latest/develop/get-started/search-tutorial/aggregation)."
    }
  ],
  "examples": [
    {
      "id": "return-everything-ex0",
      "language": "plaintext",
      "code": "> FT.SEARCH idx:catalog \"*\" LIMIT 0 0\n1) (integer) 12",
      "section_id": "return-everything"
    },
    {
      "id": "return-everything-ex1",
      "language": "python",
      "code": "res = index.search(Query(\"*\").paging(0, 0))\nprint(\"Total products:\", res.total)  # >>> Total products: 12",
      "section_id": "return-everything"
    },
    {
      "id": "full-text-search-ex0",
      "language": "plaintext",
      "code": "> FT.SEARCH idx:catalog \"@name:headphones\" RETURN 1 name\n1) (integer) 1\n2) \"product:1\"\n3) 1) \"name\"\n   2) \"Aurora AcousticPro Headphones\"",
      "section_id": "full-text-search"
    },
    {
      "id": "full-text-search-ex1",
      "language": "python",
      "code": "res = index.search(Query(\"@name:headphones\").return_field(\"name\"))\nprint(res.docs)\n# >>> [Document {'id': 'product:1', ... 'name': 'Aurora AcousticPro Headphones'}]",
      "section_id": "full-text-search"
    },
    {
      "id": "match-an-exact-phrase-ex0",
      "language": "plaintext",
      "code": "> FT.SEARCH idx:catalog \"@description:\\\"noise cancelling\\\"\" RETURN 1 name\n1) (integer) 1\n2) \"product:1\"\n3) 1) \"name\"\n   2) \"Aurora AcousticPro Headphones\"",
      "section_id": "match-an-exact-phrase"
    },
    {
      "id": "match-an-exact-phrase-ex1",
      "language": "python",
      "code": "res = index.search(Query('@description:\"noise cancelling\"').return_field(\"name\"))\nprint(res.total, [d.name for d in res.docs])\n# >>> 1 ['Aurora AcousticPro Headphones']",
      "section_id": "match-an-exact-phrase"
    },
    {
      "id": "filter-by-tag-ex0",
      "language": "plaintext",
      "code": "> FT.SEARCH idx:catalog \"@category:{Audio}\" RETURN 2 name price\n1) (integer) 3\n2) \"product:2\"\n3) 1) \"name\"\n   2) \"Aurora BudsMini Earbuds\"\n   3) \"price\"\n   4) \"89.99\"\n4) \"product:3\"\n5) 1) \"name\"\n   2) \"Sonus Boom Portable Speaker\"\n   3) \"price\"\n   4) \"129.5\"\n6) \"product:1\"\n7) 1) \"name\"\n   2) \"Aurora AcousticPro Headphones\"\n   3) \"price\"\n   4) \"199.99\"",
      "section_id": "filter-by-tag"
    },
    {
      "id": "filter-by-tag-ex1",
      "language": "python",
      "code": "res = index.search(Query(\"@category:{Audio}\").return_fields(\"name\", \"price\"))\nprint(res.total, [d.name for d in res.docs])\n# >>> 3 ['Aurora BudsMini Earbuds', 'Sonus Boom Portable Speaker', ...]",
      "section_id": "filter-by-tag"
    },
    {
      "id": "filter-by-tag-ex2",
      "language": "plaintext",
      "code": "> FT.SEARCH idx:catalog \"@features:{waterproof}\" RETURN 1 name\n1) (integer) 2\n2) \"product:3\"\n3) 1) \"name\"\n   2) \"Sonus Boom Portable Speaker\"\n4) \"product:12\"\n5) 1) \"name\"\n   2) \"Vista Action Cam 4K\"",
      "section_id": "filter-by-tag"
    },
    {
      "id": "filter-by-tag-ex3",
      "language": "python",
      "code": "res = index.search(Query(\"@features:{waterproof}\").return_field(\"name\"))\nprint(res.total, [d.name for d in res.docs])\n# >>> 2 ['Sonus Boom Portable Speaker', 'Vista Action Cam 4K']",
      "section_id": "filter-by-tag"
    },
    {
      "id": "filter-by-numeric-range-ex0",
      "language": "plaintext",
      "code": "> FT.SEARCH idx:catalog \"@price:[0 100]\" SORTBY price ASC RETURN 2 name price\n1) (integer) 4\n2) \"product:10\"\n3) 1) \"price\"\n   2) \"24.99\"\n   3) \"name\"\n   4) \"Lumi Glow Smart Bulb\"\n4) \"product:7\"\n5) 1) \"price\"\n   2) \"59.99\"\n   3) \"name\"\n   4) \"Glide Pro Wireless Mouse\"\n6) \"product:9\"\n7) 1) \"price\"\n   2) \"79.99\"\n   3) \"name\"\n   4) \"Pulse Band Fitness Tracker\"\n8) \"product:2\"\n9) 1) \"price\"\n   2) \"89.99\"\n   3) \"name\"\n   4) \"Aurora BudsMini Earbuds\"",
      "section_id": "filter-by-numeric-range"
    },
    {
      "id": "filter-by-numeric-range-ex1",
      "language": "python",
      "code": "res = index.search(\n    Query(\"@price:[0 100]\").sort_by(\"price\", asc=True).return_fields(\"name\", \"price\")\n)\nprint([(d.name, d.price) for d in res.docs])\n# >>> [('Lumi Glow Smart Bulb', '24.99'), ('Glide Pro Wireless Mouse', '59.99'), ...]",
      "section_id": "filter-by-numeric-range"
    },
    {
      "id": "combine-conditions-ex0",
      "language": "plaintext",
      "code": "> FT.SEARCH idx:catalog \"@category:{Audio} @price:[0 100]\" RETURN 2 name price\n1) (integer) 1\n2) \"product:2\"\n3) 1) \"name\"\n   2) \"Aurora BudsMini Earbuds\"\n   3) \"price\"\n   4) \"89.99\"",
      "section_id": "combine-conditions"
    },
    {
      "id": "combine-conditions-ex1",
      "language": "python",
      "code": "res = index.search(\n    Query(\"@category:{Audio} @price:[0 100]\").return_fields(\"name\", \"price\")\n)\nprint(res.total, [d.name for d in res.docs])\n# >>> 1 ['Aurora BudsMini Earbuds']",
      "section_id": "combine-conditions"
    },
    {
      "id": "projection-return-only-what-you-need-ex0",
      "language": "plaintext",
      "code": "> FT.SEARCH idx:catalog \"*\" SORTBY price DESC RETURN 2 name price LIMIT 0 3\n1) (integer) 12\n2) \"product:4\"\n3) 1) \"price\"\n   2) \"1399\"\n   3) \"name\"\n   4) \"Pixma Vortex 15 Laptop\"\n4) \"product:5\"\n5) 1) \"price\"\n   2) \"329.99\"\n   3) \"name\"\n   4) \"Pixma UltraView 27 Monitor\"\n6) \"product:12\"\n7) 1) \"price\"\n   2) \"299\"\n   3) \"name\"\n   4) \"Vista Action Cam 4K\"",
      "section_id": "projection-return-only-what-you-need"
    },
    {
      "id": "projection-return-only-what-you-need-ex1",
      "language": "python",
      "code": "res = index.search(\n    Query(\"*\").sort_by(\"price\", asc=False).return_fields(\"name\", \"price\").paging(0, 3)\n)\nprint([(d.name, d.price) for d in res.docs])\n# >>> [('Pixma Vortex 15 Laptop', '1399'), ('Pixma UltraView 27 Monitor', '329.99'), ...]",
      "section_id": "projection-return-only-what-you-need"
    }
  ]
}
