# `Redis.Search`
[🔗](https://github.com/joshrotenberg/redis_ex/blob/v0.7.1/lib/redis/search.ex#L1)

High-level search API for Redis, inspired by Meilisearch.

Wraps the RediSearch `FT.*` commands with an Elixir-friendly interface:
keyword-based schemas, map-based documents, Elixir filter expressions
instead of raw query strings, and parsed result structs.

For raw command access, see `Redis.Commands.Search`.

## Quick Start

    # Create an index
    Redis.Search.create_index(conn, "movies",
      prefix: "movie:",
      fields: [
        title: :text,
        year: {:numeric, sortable: true},
        genres: :tag
      ]
    )

    # Add documents as maps
    Redis.Search.add(conn, "movies", "movie:1", %{
      title: "The Dark Knight",
      year: 2008,
      genres: "action,thriller"
    })

    # Search with Elixir filters
    Redis.Search.find(conn, "movies", "dark knight",
      where: [year: {:gt, 2000}, genres: "action"],
      sort: {:year, :desc},
      limit: 10
    )
    #=> {:ok, %Redis.Search.Result{total: 1, results: [%{id: "movie:1", ...}]}}

## Filter Syntax

The `:where` option accepts a keyword list compiled to RediSearch query syntax:

  * `field: "value"` -- text match (`@field:value`)
  * `field: {:match, "hello world"}` -- phrase match (`@field:(hello world)`)
  * `field: {:gt, n}` -- greater than (`@field:[(n +inf]`)
  * `field: {:gte, n}` -- greater than or equal (`@field:[n +inf]`)
  * `field: {:lt, n}` -- less than (`@field:[-inf (n]`)
  * `field: {:lte, n}` -- less than or equal (`@field:[-inf n]`)
  * `field: {:between, min, max}` -- range (`@field:[min max]`)
  * `field: {:tag, "val"}` -- exact tag (`@field:{val}`)
  * `field: {:any, ["a", "b"]}` -- tag OR (`@field:{a|b}`)

## Options

  * `:where` -- filter keyword list (see above)
  * `:sort` -- `{field, :asc | :desc}`
  * `:limit` -- max results (integer) or `{offset, count}`
  * `:return` -- list of fields to return
  * `:nocontent` -- return only IDs (boolean)
  * `:dialect` -- RediSearch query dialect version
  * `:coerce` -- auto-coerce numeric strings (default: true)

# `add`

Adds a document to an index.

Auto-detects hash vs JSON based on the index type. Pass `:on` to
override if the index hasn't been inspected yet.

    Redis.Search.add(conn, "movies", "movie:1", %{
      title: "Inception",
      year: 2010,
      genres: "sci-fi,thriller"
    })

# `add_many`

Adds multiple documents via pipeline.

    Redis.Search.add_many(conn, "movies", [
      {"movie:1", %{title: "Inception", year: 2010}},
      {"movie:2", %{title: "Interstellar", year: 2014}}
    ])

# `aggregate`

Runs an aggregation query.

    Redis.Search.aggregate(conn, "movies",
      group_by: :genres,
      reduce: [count: "total"],
      sort: {:total, :desc},
      limit: 10
    )

    # Multiple reducers
    Redis.Search.aggregate(conn, "movies",
      group_by: [:city],
      reduce: [
        count: "total",
        avg: {:score, "avg_score"}
      ]
    )

## Reducers

  * `count: "alias"` -- COUNT
  * `sum: {:field, "alias"}` -- SUM
  * `avg: {:field, "alias"}` -- AVG
  * `min: {:field, "alias"}` -- MIN
  * `max: {:field, "alias"}` -- MAX

# `create_index`

Creates a search index.

Fields are specified as a keyword list:

    Redis.Search.create_index(conn, "idx", fields: [name: :text, age: :numeric])
    Redis.Search.create_index(conn, "idx",
      on: :json,
      prefix: "doc:",
      fields: [
        title: :text,
        score: {:numeric, sortable: true},
        tags: :tag
      ]
    )

## Options

  * `:fields` (required) -- keyword list of `{name, type}` or `{name, {type, opts...}}`
  * `:on` -- `:hash` (default) or `:json`
  * `:prefix` -- key prefix string or list
  * `:stopwords` -- list of stopwords or `0` for none
  * `:language` -- default language

# `drop_index`

Drops a search index. Pass `dd: true` to also delete indexed documents.

# `find`

Searches an index with Elixir-friendly filters.

    # Simple full-text search
    Redis.Search.find(conn, "movies", "dark knight")

    # With filters
    Redis.Search.find(conn, "movies", "batman",
      where: [year: {:gt, 2000}, genres: {:tag, "action"}],
      sort: {:year, :desc},
      limit: 10,
      return: [:title, :year]
    )

See module docs for the full filter syntax.

# `index_info`

Returns index info as a map.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
