123456789_123456789_123456789_123456789_123456789_

Module: Redis::Commands::Search

Overview

::Redis Query Engine (RediSearch, the FT.* command family). See ../../query-engine.html for the layered design and an abstractions-vs-raw-commands guide.

Replies are reshaped by ResultParser into SearchResult / Document (for FT.SEARCH), AggregateResult (for FT.AGGREGATE / FT.CURSOR READ), or plain Hashes/Arrays. Reshaping is identical under RESP2 and RESP3.

Constant Summary

Instance Method Summary

Instance Method Details

#create_index(name, schema, storage_type: "hash", prefix: nil, stopwords: nil, max_text_fields: false, skip_initial_scan: false, definition: nil, **options) ⇒ Search::Index

Create an index and return a high-level Search::Index bound to this client.

Unlike #ft_create (which returns "OK"), this returns a stateful Search::Index that remembers the schema and prefix and exposes +#add+/+#search+/+#aggregate+/etc.

Examples:

index = redis.create_index("idx", schema, prefix: "doc")
index.add("1", title: "hello")
index.search("hello").total # => 1

Parameters:

  • name (String)

    the index name

  • schema (Search::Schema)

    the field schema

  • storage_type (String)

    the data type to index (+"hash"+ or "json")

  • prefix (String, nil)

    key prefix for indexed/added documents

  • stopwords (Array<String>, nil)

    custom stopword list

  • max_text_fields (Boolean)

    emit MAXTEXTFIELDS

  • skip_initial_scan (Boolean)

    emit SKIPINITIALSCAN

  • definition (Search::IndexDefinition, nil)

    prebuilt index definition clause

Returns:

Raises:

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 112

def create_index(
  name, schema, storage_type: "hash",
  prefix: nil, stopwords: nil, max_text_fields: false,
  skip_initial_scan: false, definition: nil, **options
)
  raise Redis::CommandError, "schema must be a Schema object" unless schema.is_a?(Schema)

  begin
    Index.create(
      self, name, schema, storage_type,
      prefix: prefix, stopwords: stopwords,
      max_text_fields: max_text_fields,
      skip_initial_scan: skip_initial_scan,
      definition: definition, **options
    )
  rescue ArgumentError => e
    raise Redis::CommandError, e.message
  end
end

#ft_aggregate(index_name, query, *args) ⇒ Search::AggregateResult

Run an aggregation pipeline, or read the next batch of a cursor.

Examples:

req = Redis::Commands::Search::AggregateRequest.new("*")
        .group_by("@category", Redis::Commands::Search::Reducers.count.as("n"))
redis.ft_aggregate("idx", req) # => #<AggregateResult ...>

Parameters:

  • index_name (String)

    the index name

  • query (Search::AggregateRequest, Search::Cursor, String)

    an aggregate request, a cursor to read, or a raw query string followed by raw pipeline args

  • args (Array)

    raw pipeline tokens when query is a String (e.g. "GROUPBY", 1, "@x", "REDUCE", "COUNT", 0, "AS", "n")

Returns:

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 316

def ft_aggregate(index_name, query, *args)
  command =
    case query
    when AggregateRequest
      ["FT.AGGREGATE", index_name] + query.to_redis_args
    when Cursor
      ["FT.CURSOR", "READ", index_name] + query.build_args
    else
      # Raw query string: default to DIALECT 2 (matching redis-py) unless one was passed.
      base = ["FT.AGGREGATE", index_name, query, *args]
      base += ["DIALECT", DEFAULT_DIALECT] unless args.flatten.map(&:to_s).include?("DIALECT")
      base
    end

  send_command(command) { |reply| ResultParser.aggregate(reply) }
end

#ft_aliasadd(alias_name, index_name) ⇒ String

Add an alias for an index.

Parameters:

  • alias_name (String)

    the alias

  • index_name (String)

    the index the alias points to

Returns:

  • (String)

    "OK"

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 533

def ft_aliasadd(alias_name, index_name)
  send_command(["FT.ALIASADD", alias_name, index_name])
end

#ft_aliasdel(alias_name) ⇒ String

Remove an index alias.

Parameters:

  • alias_name (String)

    the alias

Returns:

  • (String)

    "OK"

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 550

def ft_aliasdel(alias_name)
  send_command(["FT.ALIASDEL", alias_name])
end

#ft_aliaslist(index_name) ⇒ Array<String>

List all aliases associated with an index (Redis 8.10+).

Parameters:

  • index_name (String)

    the index name

Returns:

  • (Array<String>)

    the aliases pointing to the index (empty when none)

Raises:

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 559

def ft_aliaslist(index_name)
  send_command(["FT.ALIASLIST", index_name])
end

#ft_aliasupdate(alias_name, index_name) ⇒ String

Repoint an existing alias to a different index (or create it if absent).

Parameters:

  • alias_name (String)

    the alias

  • index_name (String)

    the index the alias should point to

Returns:

  • (String)

    "OK"

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 542

def ft_aliasupdate(alias_name, index_name)
  send_command(["FT.ALIASUPDATE", alias_name, index_name])
end

#ft_alter(index_name, field_or_args) ⇒ String

Add a field to an existing index's schema (+FT.ALTER ... SCHEMA ADD+).

Parameters:

  • index_name (String)

    the index name

  • field_or_args (Search::Field, Array)

    a Search::Field (rendered via #to_args) or a raw token array

Returns:

  • (String)

    "OK"

Raises:

  • (ArgumentError)

    if field_or_args is neither a Search::Field nor an Array

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 349

def ft_alter(index_name, field_or_args)
  args = [index_name, "SCHEMA", "ADD"]
  if field_or_args.respond_to?(:to_args)
    args += field_or_args.to_args
  elsif field_or_args.is_a?(Array)
    args += field_or_args
  else
    raise ArgumentError, "field_or_args must be a Field object or an array"
  end
  send_command([:"FT.ALTER", *args])
end

#ft_config_get(option) ⇒ Hash

Get a runtime Search::Query Engine configuration option.

Parameters:

  • option (String)

    the option name, or "*" for all options

Returns:

  • (Hash)

    option name => value

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 602

def ft_config_get(option)
  send_command(["FT.CONFIG", "GET", option]) { |reply| ResultParser.config_get(reply) }
end

#ft_config_set(option, value) ⇒ String

Set a runtime Search::Query Engine configuration option.

Parameters:

  • option (String)

    the option name (or "*")

  • value (String, Integer)

    the value

Returns:

  • (String)

    "OK"

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 594

def ft_config_set(option, value)
  send_command(["FT.CONFIG", "SET", option, value])
end

#ft_create(index_name, schema, storage_type = nil, prefix: nil, stopwords: nil, max_text_fields: false, skip_initial_scan: false, definition: nil, temporary: nil, no_term_offsets: false, no_highlight: false, no_field_flags: false, no_term_frequencies: false, **_options) ⇒ String

Create a search index over HASH or JSON keys.

Examples:

schema = Redis::Commands::Search::Schema.build { text_field :title }
redis.ft_create("idx", schema, prefix: "doc")
  # => "OK"

Parameters:

  • index_name (String)

    the index name

  • schema (Search::Schema)

    the field schema; the SCHEMA clause is rendered from it

  • storage_type (String, Symbol, nil) (defaults to: nil)

    the data type to index, e.g. "HASH" or "JSON" (emitted as ON <type>); ignored when definition is given

  • prefix (String, nil)

    index keys whose name starts with "<prefix>:"; ignored when definition is given

  • stopwords (Array<String>, nil)

    a custom stopword list (emits STOPWORDS)

  • max_text_fields (Boolean)

    emit MAXTEXTFIELDS

  • skip_initial_scan (Boolean)

    emit SKIPINITIALSCAN (do not backfill existing keys)

  • definition (Search::IndexDefinition, nil)

    a prebuilt ON .../PREFIX/FILTER/... clause; when given it takes precedence over storage_type+/+prefix

  • temporary (Integer, nil)

    index lifetime in seconds (emits TEMPORARY <seconds>)

  • no_term_offsets (Boolean)

    emit NOOFFSETS

  • no_highlight (Boolean)

    emit NOHL

  • no_field_flags (Boolean)

    emit NOFIELDS

  • no_term_frequencies (Boolean)

    emit NOFREQS

Returns:

  • (String)

    "OK"

Raises:

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 37

def ft_create(
  index_name, schema, storage_type = nil,
  prefix: nil, stopwords: nil, max_text_fields: false,
  skip_initial_scan: false, definition: nil, temporary: nil,
  no_term_offsets: false, no_highlight: false,
  no_field_flags: false, no_term_frequencies: false, **_options
)
  raise ArgumentError, "schema must be a Schema object" unless schema.is_a?(Schema)

  args = [index_name]

  # Use IndexDefinition if provided, otherwise use legacy parameters
  if definition
    # The definition supplies the ON/PREFIX/FILTER clause. When it doesn't declare an index
    # type, fall back to the storage_type keyword so e.g. a JSON index isn't silently created
    # as HASH. Normalize to the uppercase HASH/JSON form some Query Engine versions require.
    args += ["ON", storage_type.to_s.upcase] if definition.index_type.nil? && storage_type
    args += definition.args
  else
    # Normalize the ON token to HASH/JSON; a lowercase value is rejected by some
    # Query Engine versions (and IndexType/the docs use the uppercase form).
    args += ["ON", storage_type.to_s.upcase] if storage_type
    args += ["PREFIX", 1, "#{prefix}:"] if prefix
  end

  args << "MAXTEXTFIELDS" if max_text_fields

  if temporary
    args << "TEMPORARY"
    args << temporary
  end

  args << "NOOFFSETS" if no_term_offsets
  args << "NOHL" if no_highlight
  args << "NOFIELDS" if no_field_flags
  args << "NOFREQS" if no_term_frequencies
  args << "SKIPINITIALSCAN" if skip_initial_scan

  # Stopwords
  if stopwords
    args += ['STOPWORDS', stopwords.size]
    stopwords.each do |stopword|
      args << stopword
    end
  end

  # Schema Fields
  args += ["SCHEMA"]
  schema.fields.each do |field|
    args += field.to_args
  end

  send_command([:"FT.CREATE", *args])
end

#ft_cursor_del(index_name, cursor_id) ⇒ String

Discard an aggregation cursor.

Parameters:

  • index_name (String)

    the index name

  • cursor_id (Integer)

    the cursor id

Returns:

  • (String)

    "OK"

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 376

def ft_cursor_del(index_name, cursor_id)
  send_command(["FT.CURSOR", "DEL", index_name, cursor_id])
end

#ft_cursor_read(index_name, cursor_id) ⇒ Search::AggregateResult

Read the next batch of results from an aggregation cursor.

Parameters:

  • index_name (String)

    the index name

  • cursor_id (Integer)

    the cursor id returned by a previous WITHCURSOR aggregation

Returns:

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 367

def ft_cursor_read(index_name, cursor_id)
  send_command(["FT.CURSOR", "READ", index_name, cursor_id]) { |reply| ResultParser.aggregate(reply) }
end

#ft_dictadd(dict_name, *terms) ⇒ Integer

Add terms to a custom dictionary.

Parameters:

  • dict_name (String)

    the dictionary name

  • terms (Array<String>)

    the terms to add

Returns:

  • (Integer)

    the number of new terms added

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 568

def ft_dictadd(dict_name, *terms)
  send_command(["FT.DICTADD", dict_name] + terms)
end

#ft_dictdel(dict_name, *terms) ⇒ Integer

Remove terms from a custom dictionary.

Parameters:

  • dict_name (String)

    the dictionary name

  • terms (Array<String>)

    the terms to remove

Returns:

  • (Integer)

    the number of terms removed

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 577

def ft_dictdel(dict_name, *terms)
  send_command(["FT.DICTDEL", dict_name] + terms)
end

#ft_dictdump(dict_name) ⇒ Array<String>

Dump all terms in a custom dictionary.

Parameters:

  • dict_name (String)

    the dictionary name

Returns:

  • (Array<String>)

    the terms in the dictionary

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 585

def ft_dictdump(dict_name)
  send_command(["FT.DICTDUMP", dict_name])
end

#ft_dropindex(index_name, delete_documents: false) ⇒ String

Drop an index.

Parameters:

  • index_name (String)

    the index name

  • delete_documents (Boolean)

    also delete the indexed documents (+DD+)

Returns:

  • (String)

    "OK"

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 297

def ft_dropindex(index_name, delete_documents: false)
  args = ["FT.DROPINDEX", index_name]
  args << 'DD' if delete_documents
  send_command(args)
end

#ft_explain(index_name, query) ⇒ String

Return the execution plan for a query without running it.

Parameters:

  • index_name (String)

    the index name

  • query (String)

    the query string

Returns:

  • (String)

    a human-readable description of the query plan

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 338

def ft_explain(index_name, query)
  send_command(["FT.EXPLAIN", index_name, query])
end

#ft_hybrid_search(index_name, query:, combine_method: nil, post_processing: nil, params_substitution: nil, timeout: nil, cursor: nil, **_options) ⇒ Search::HybridResult

Run a hybrid (lexical + vector) search.

Parameters:

Returns:

  • (Search::HybridResult)

    the fused result rows, total, warnings and execution time (or, for a WITHCURSOR query, the per-leg cursor ids)

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 400

def ft_hybrid_search(
  index_name, query:, combine_method: nil, post_processing: nil,
  params_substitution: nil, timeout: nil, cursor: nil, **_options
)
  args = ["FT.HYBRID", index_name]
  args.concat(query.args)
  args.concat(combine_method.args) if combine_method
  args.concat(post_processing.build_args) if post_processing
  if params_substitution
    args << "PARAMS" << params_substitution.size * 2
    params_substitution.each do |key, value|
      args << key.to_s << value
    end
  end
  args.concat(["TIMEOUT", timeout]) if timeout
  args.concat(cursor.build_args) if cursor
  # NOTE: unlike FT.SEARCH/FT.AGGREGATE, FT.HYBRID does NOT accept a DIALECT token (the
  # server rejects it: "DIALECT is not supported in FT.HYBRID or any of its subqueries").
  # Its legs use the server's search-default-dialect config, so do not append DEFAULT_DIALECT.
  send_command(args) { |reply| ResultParser.hybrid(reply) }
end

#ft_info(index_name) ⇒ Hash

Return information and statistics about an index.

Examples:

redis.ft_info("idx")["num_docs"] # => 42

Parameters:

  • index_name (String)

    the index name

Returns:

  • (Hash)

    index metadata (e.g. "index_name", "num_docs", "attributes")

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 288

def ft_info(index_name)
  send_command(["FT.INFO", index_name]) { |reply| ResultParser.hashify_info(reply) }
end

#ft_profile(index_name, *args) ⇒ Array

Profile the execution of a SEARCH or AGGREGATE query (timing/heuristics).

Parameters:

  • index_name (String)

    the index name

  • args (Array)

    the profile arguments, e.g. "SEARCH", "QUERY", "<query>"

Returns:

  • (Array)

    the raw profile reply (results plus a profiling tree)

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 385

def ft_profile(index_name, *args)
  send_command(["FT.PROFILE", index_name] + args)
end

#ft_search(index_name, query, **options) ⇒ Search::SearchResult

Search an index.

Examples:

redis.ft_search("idx", "@title:hello", limit: [0, 10], with_scores: true)
  # => #<SearchResult total=1 ...>

raw vector (KNN) query

redis.ft_search("idx", "(*)=>[KNN 2 @vec $v]", params: { v: blob }, dialect: 2)

Parameters:

  • index_name (String)

    the index (or alias) name

  • query (String)

    the query string (use Search::Query#to_redis_args.first to build one)

  • options (Hash)

    search options translated to FT.SEARCH tokens

Options Hash (**options):

  • :no_content (Boolean)

    return ids only (+NOCONTENT+); documents have no fields

  • :verbatim (Boolean)

    disable stemming (+VERBATIM+)

  • :no_stopwords (Boolean)

    do not remove stopwords (+NOSTOPWORDS+)

  • :with_scores (Boolean)

    include the relevance score on each document (+WITHSCORES+)

  • :with_payloads (Boolean)

    include each document's payload (+WITHPAYLOADS+)

  • :scorer (String)

    scoring function name (+SCORER+), e.g. "BM25"+/+"TFIDF"

  • :explain_score (Boolean)

    include a score explanation (+EXPLAINSCORE+)

  • :language (String)

    stemming language (+LANGUAGE+)

  • :slop (Integer)

    allowed term reordering distance (+SLOP+)

  • :in_order (Boolean)

    require terms in query order (+INORDER+)

  • :timeout (Integer)

    per-query timeout in milliseconds (+TIMEOUT+)

  • :expander (String)

    custom query expander (+EXPANDER+)

  • :limit_fields (Array<String>)

    restrict full-text matching to these fields (+INFIELDS+)

  • :limit (Array(Integer, Integer))

    [offset, count] paging (+LIMIT+)

  • :sortby (Array(String, String))

    [field, "ASC"|"DESC"] (+SORTBY+)

  • :sort_by (String)

    sort field (convenience; pair with :asc)

  • :asc (Boolean)

    sort ascending when :sort_by is used (default; pass false for descending)

  • :filter (Array<Array>)

    numeric filters, each [field, min, max] (+FILTER+)

  • :geo_filter (Array<Array>)

    geo filters, each [field, lon, lat, radius, unit]

  • :limit_ids (Array<String>)

    restrict to these keys (+INKEYS+)

  • :return (Array<String>)

    only return these fields (+RETURN+)

  • :summarize (Hash)

    SUMMARIZE options (+:fields+, :frags, :len, :separator)

  • :highlight (Hash)

    HIGHLIGHT options (+:fields+, :tags)

  • :params (Hash, Array)

    query parameter substitutions (+PARAMS+)

  • :dialect (Integer)

    query dialect version (+DIALECT+)

  • :decode_fields (Hash{String=>Boolean})

    field name => whether to JSON-decode its value in the returned Search::Document

Returns:

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 173

def ft_search(index_name, query, **options)
  args = [index_name, query]

  args << "NOCONTENT" if options[:no_content]
  args << "VERBATIM" if options[:verbatim]
  args << "NOSTOPWORDS" if options[:no_stopwords]
  # EXPLAINSCORE requires WITHSCORES, so emit WITHSCORES whenever an explanation is asked for.
  args << "WITHSCORES" if options[:with_scores] || options[:explain_score]
  args << "WITHPAYLOADS" if options[:with_payloads]
  args << "SCORER" << options[:scorer] if options[:scorer]
  args << "EXPLAINSCORE" if options[:explain_score]
  args << "LANGUAGE" << options[:language] if options[:language]
  args << "SLOP" << options[:slop] if options[:slop]
  args << "INORDER" if options[:in_order]
  args << "TIMEOUT" << options[:timeout] if options[:timeout]
  args << "EXPANDER" << options[:expander] if options[:expander]
  if options[:limit_fields] && !options[:limit_fields].empty?
    args << "INFIELDS" << options[:limit_fields].size
    args.concat(options[:limit_fields].map(&:to_s))
  end
  args << "LIMIT" << options[:limit][0] << options[:limit][1] if options[:limit]

  # Handle both :sortby (array format) and :sort_by (convenience format)
  if options[:sortby]
    args << "SORTBY" << options[:sortby][0] << options[:sortby][1]
  elsif options[:sort_by]
    # Default to ASC when :asc is omitted (matching Index#search, Query#sort_by and the
    # server's own SORTBY default); only an explicit asc: false sorts descending.
    direction = options[:asc] == false ? 'DESC' : 'ASC'
    args << "SORTBY" << options[:sort_by] << direction
  end

  options[:filter]&.each do |field, min, max|
    args << "FILTER" << field << min << max
  end

  options[:geo_filter]&.each do |field, lon, lat, radius, unit|
    args << "GEOFILTER" << field << lon << lat << radius << unit
  end

  if options[:limit_ids] && !options[:limit_ids].empty?
    args << "INKEYS" << options[:limit_ids].size
    args.concat(options[:limit_ids])
  end

  if options[:return] && !options[:return].empty?
    args << "RETURN" << options[:return].size
    args.concat(options[:return])
  end

  if options[:summarize]
    args << "SUMMARIZE"
    if options[:summarize][:fields]&.any?
      args << "FIELDS" << options[:summarize][:fields].size
      args.concat(options[:summarize][:fields].map(&:to_s))
    end
    args << "FRAGS" << options[:summarize][:frags] if options[:summarize][:frags]
    args << "LEN" << options[:summarize][:len] if options[:summarize][:len]
    args << "SEPARATOR" << options[:summarize][:separator] if options[:summarize][:separator]
  end

  if options[:highlight]
    args << "HIGHLIGHT"
    if options[:highlight][:fields]&.any?
      args << "FIELDS" << options[:highlight][:fields].size
      args.concat(options[:highlight][:fields].map(&:to_s))
    end
    if options[:highlight][:tags]
      args << "TAGS" << options[:highlight][:tags][0] << options[:highlight][:tags][1]
    end
  end

  if options[:params]
    if options[:params].is_a?(Hash)
      args << "PARAMS" << (options[:params].length * 2)
      options[:params].each do |k, v|
        args << k.to_s << v
      end
    else
      args << "PARAMS" << options[:params].length
      args.concat(options[:params])
    end
  end

  # Default to DIALECT 2 (matching redis-py) unless the caller specified one. An explicit
  # dialect: nil (e.g. flowing from an unset Query option) falls back to the default too, so
  # it behaves the same as omitting the keyword rather than deferring to the server default.
  dialect = options[:dialect] || DEFAULT_DIALECT
  args << "DIALECT" << dialect

  # WITHSCORES is emitted for explain_score too (EXPLAINSCORE requires it), so the RESP2
  # parser must expect a score column in the same cases or it mis-reads the reply layout.
  with_scores = options[:with_scores] || options[:explain_score]
  with_payloads = options[:with_payloads]
  no_content = options[:no_content]
  decode_fields = options[:decode_fields] || {}

  send_command(["FT.SEARCH"] + args.flatten.compact) do |reply|
    ResultParser.search(
      reply,
      with_scores: !!with_scores,
      with_payloads: !!with_payloads,
      no_content: !!no_content,
      decode_fields: decode_fields
    )
  end
end

#ft_spellcheck(index_name, query, distance: nil, include: nil, exclude: nil) ⇒ Hash{String=>Array<Hash>}

Perform spelling correction over a query against an index.

Examples:

redis.ft_spellcheck("idx", "hello wrld")
  # => { "wrld" => [{ "suggestion" => "world", "score" => 0.5 }] }

Parameters:

  • index_name (String)

    the index name

  • query (String)

    the query whose terms are checked

  • distance (Integer, nil)

    maximum Levenshtein distance for suggestions (+DISTANCE+)

  • include (String, nil)

    a custom dictionary to include terms from (+TERMS INCLUDE+)

  • exclude (String, nil)

    a custom dictionary to exclude terms from (+TERMS EXCLUDE+)

Returns:

  • (Hash{String=>Array<Hash>})

    each misspelled term mapped to an array of { "suggestion" => String, "score" => Numeric }

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 487

def ft_spellcheck(index_name, query, distance: nil, include: nil, exclude: nil)
  args = ["FT.SPELLCHECK", index_name, query]
  args += ["DISTANCE", distance] if distance
  args += ["TERMS", "INCLUDE", include] if include
  args += ["TERMS", "EXCLUDE", exclude] if exclude

  send_command(args) { |reply| ResultParser.spellcheck(reply) }
end

#ft_sugadd(key, string, score, options = {}) ⇒ Integer

Add a suggestion string to an auto-complete dictionary.

Parameters:

  • key (String)

    the suggestion dictionary key

  • string (String)

    the suggestion text

  • score (Numeric)

    the suggestion weight

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :incr (Boolean)

    increment the existing score instead of replacing it (+INCR+)

  • :payload (String)

    an opaque payload to store with the suggestion (+PAYLOAD+)

Returns:

  • (Integer)

    the current size of the suggestion dictionary

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 431

def ft_sugadd(key, string, score, options = {})
  args = ["FT.SUGADD", key, string, score]
  args << 'INCR' if options[:incr]
  args << 'PAYLOAD' << options[:payload] if options[:payload]
  send_command(args)
end

#ft_sugdel(key, string) ⇒ Integer

Delete a string from a suggestion dictionary.

Parameters:

  • key (String)

    the suggestion dictionary key

  • string (String)

    the suggestion text to delete

Returns:

  • (Integer)

    1 if the suggestion existed and was deleted, 0 otherwise

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 470

def ft_sugdel(key, string)
  send_command(["FT.SUGDEL", key, string])
end

#ft_sugget(key, prefix, options = {}) ⇒ Array<String>

Get auto-complete suggestions for a prefix.

Parameters:

  • key (String)

    the suggestion dictionary key

  • prefix (String)

    the prefix to complete

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :fuzzy (Boolean)

    perform a fuzzy prefix match (+FUZZY+)

  • :with_scores (Boolean)

    also return each suggestion's score (+WITHSCORES+)

  • :with_payloads (Boolean)

    also return each suggestion's payload (+WITHPAYLOADS+)

  • :max (Integer)

    maximum number of suggestions (+MAX+)

Returns:

  • (Array<String>)

    the suggestions, interleaved with scores/payloads when requested

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 448

def ft_sugget(key, prefix, options = {})
  args = ["FT.SUGGET", key, prefix]
  args << 'FUZZY' if options[:fuzzy]
  args << 'WITHSCORES' if options[:withscores] || options[:with_scores]
  args << 'WITHPAYLOADS' if options[:withpayloads] || options[:with_payloads]
  args << 'MAX' << options[:max] if options[:max]
  send_command(args)
end

#ft_suglen(key) ⇒ Integer

Get the number of entries in a suggestion dictionary.

Parameters:

  • key (String)

    the suggestion dictionary key

Returns:

  • (Integer)

    the number of suggestions

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 461

def ft_suglen(key)
  send_command(["FT.SUGLEN", key])
end

#ft_syndump(index_name) ⇒ Hash{String=>Array<String>}

Dump the synonym groups of an index.

Parameters:

  • index_name (String)

    the index name

Returns:

  • (Hash{String=>Array<String>})

    each term mapped to the synonym group ids it belongs to

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 514

def ft_syndump(index_name)
  send_command(["FT.SYNDUMP", index_name]) { |reply| ResultParser.syndump(reply) }
end

#ft_synupdate(index_name, group_id, *terms, skip_initial_scan: false) ⇒ String

Add or update a synonym group on an index.

Parameters:

  • index_name (String)

    the index name

  • group_id (String)

    the synonym group id

  • terms (Array<String>)

    the terms to add to the group

  • skip_initial_scan (Boolean)

    do not re-scan existing documents (+SKIPINITIALSCAN+)

Returns:

  • (String)

    "OK"

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 503

def ft_synupdate(index_name, group_id, *terms, skip_initial_scan: false)
  args = [index_name, group_id]
  args << "SKIPINITIALSCAN" if skip_initial_scan
  args += terms
  send_command(["FT.SYNUPDATE"] + args)
end

#ft_tagvals(index_name, field_name) ⇒ Array<String>

List the distinct values of a TAG field.

Parameters:

  • index_name (String)

    the index name

  • field_name (String)

    the TAG field name

Returns:

  • (Array<String>)

    the distinct tag values (normalized to lowercase unless the field is case-sensitive)

[ GitHub ]

  
# File 'lib/redis/commands/modules/search/miscellaneous.rb', line 524

def ft_tagvals(index_name, field_name)
  send_command(["FT.TAGVALS", index_name, field_name])
end