123456789_123456789_123456789_123456789_123456789_

Module: Mongoid::SearchIndexable::ClassMethods

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Extended In:
Defined in: lib/mongoid/search_indexable.rb

Overview

Implementations for the feature’s class-level methods.

Instance Method Summary

Instance Method Details

#create_search_indexesArray<String>

Request the creation of all registered search indices. Note that the search indexes are created asynchronously, and may take several minutes to be fully available.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 109

def create_search_indexes
  return if search_index_specs.empty?

  collection.search_indexes.create_many(search_index_specs)
end

#get_indexes(names) ⇒ Array<Hash> (private)

Retrieves the index records for the indexes with the given names.

Parameters:

Returns:

[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 282

def get_indexes(names)
  collection.search_indexes.select { |i| names.include?(i['name']) }
end

#infer_vector_path(spec) ⇒ String (private)

Infers the vector field path from the index definition by locating the first field declared with type ‘vector’.

Parameters:

  • spec (Hash)

    The vector search index spec.

Returns:

  • (String)

    the field path.

[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 322

def infer_vector_path(spec)
  field_list = spec.dig(:definition, :fields) || spec.dig(:definition, 'fields') || []
  vector_field = field_list.find { |f| (f[:type] || f['type']) == 'vector' }

  unless vector_field
    raise ArgumentError,
          "Cannot infer vector path on #{name}: no 'vector' type field in index definition; specify path:"
  end

  (vector_field[:path] || vector_field['path']).to_s
end

#remove_search_index(name: nil, id: nil)

Removes the search index specified by the given name or id. Either name OR id must be given, but not both.

Parameters:

  • name (String | nil)

    the name of the index to remove

  • id (String | nil)

    the id of the index to remove

[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 151

def remove_search_index(name: nil, id: nil)
  logger.info(
    "MONGOID: Removing search index '#{name || id}' " \
    "on collection '#{collection.name}'."
  )

  collection.search_indexes.drop_one(name: name, id: id)
end

#remove_search_indexes

Note:

It would be nice if this could remove ONLY the search indexes

Request the removal of all registered search indexes. Note that the search indexes are removed asynchronously, and may take several minutes to be fully deleted.

that have been declared on the model, but because the model may not name the index, we can’t guarantee that we’ll know the name or id of the corresponding indexes. It is not unreasonable to assume, though, that the intention is for the model to declare, one-to-one, all desired search indexes, so removing all search indexes ought to suffice. If a specific index or set of indexes needs to be removed instead, consider using search_indexes.each with remove_search_index.

[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 172

def remove_search_indexes
  search_indexes.each do |spec|
    remove_search_index id: spec['id']
  end
end

#resolve_vector_index(index, path) ⇒ Array<String> (private)

Resolves the index name and vector path from the declared specs, applying inference when either is omitted.

Parameters:

  • index (String | Symbol | nil)

    The requested index name.

  • path (String | Symbol | nil)

    The requested field path.

Returns:

  • (Array<String>)

    the resolved [ index_name, field_path ] pair.

Raises:

  • (ArgumentError)
[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 293

def resolve_vector_index(index, path)
  vector_specs = search_index_specs.select { |s| s[:type] == 'vectorSearch' }

  raise ArgumentError, "No vector search indexes declared on #{name}" if vector_specs.empty?

  spec = if index
           found = vector_specs.find { |s| s[:name] == index.to_s }
           raise ArgumentError, "No vector search index '#{index}' declared on #{name}" unless found

           found
         elsif vector_specs.size == 1
           vector_specs.first
         else
           raise ArgumentError,
                 "#{name} has multiple vector search indexes; specify index: to select one"
         end

  resolved_index = spec[:name] || 'default'
  resolved_path  = path ? path.to_s : infer_vector_path(spec)

  [ resolved_index, resolved_path ]
end

#search_index(name_or_defn, defn = nil)

Adds an index definition for the provided single or compound keys.

Examples:

Create a basic index.

class Person
  include Mongoid::Document
  field :name, type: String
  search_index({ ... })
  search_index :name_of_index, { ... }
end

Parameters:

  • name_or_defn (Symbol | String | Hash)

    Either the name of the index to define, or the index definition.

  • defn (Hash) (defaults to: nil)

    The search index definition.

[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 191

def search_index(name_or_defn, defn = nil)
  name = name_or_defn
  name, defn = nil, name if name.is_a?(Hash)

  spec = { definition: defn }.tap { |s| s[:name] = name.to_s if name }
  search_index_specs.push(spec)
end

#search_indexes(options = {})

A convenience method for querying the search indexes available on the current model’s collection.

Parameters:

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

    the options to pass through to the search index query.

Options Hash (options):

  • :id (String)

    The id of the specific index to query (optional)

  • :name (String)

    The name of the specific index to query (optional)

  • :aggregate (Hash)

    The options hash to pass to the aggregate command (optional)

[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 142

def search_indexes(options = {})
  collection.search_indexes(options)
end

#vector_search(vector, index: nil, path: nil, limit: 10, num_candidates: nil, filter: nil, pipeline: []) ⇒ Array<Mongoid::Document>

Performs an Atlas Vector Search query and returns matching documents. Each returned document has a vector_search_score attribute populated with its relevance score.

The vector field (given by path:) is excluded from the returned documents by default, as vectors are large and rarely useful after retrieval.

Examples:

Search by an explicit query vector.

Article.vector_search(embedding, limit: 5, filter: { status: 'published' })

Parameters:

  • vector (Array<Numeric>)

    The query vector.

  • index (String | Symbol | nil)

    The name of the vector search index to use (optional if only one is declared on the model).

  • path (String | Symbol | nil)

    The field containing the stored vector (optional if unambiguous from the index definition).

  • limit (Integer)

    The maximum number of results (default: 10).

  • num_candidates (Integer | nil)

    The number of candidates to consider during the ANN search; defaults to limit * 10.

  • filter (Hash | nil)

    An optional MongoDB filter to pre-filter candidates before scoring.

  • pipeline (Array)

    Additional aggregation stages to append after the vector search and score projection.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 252

def vector_search(vector, index: nil, path: nil, limit: 10, num_candidates: nil, filter: nil, pipeline: []) # rubocop:disable Metrics/ParameterLists
  resolved_index, resolved_path = resolve_vector_index(index, path)
  num_candidates ||= limit * 10

  vs_options = {
    'index' => resolved_index,
    'path' => resolved_path,
    'queryVector' => vector,
    'numCandidates' => num_candidates,
    'limit' => limit
  }
  vs_options['filter'] = filter if filter

  agg_pipeline = [
    { '$vectorSearch' => vs_options },
    { '$addFields'    => { 'vector_search_score' => { '$meta' => 'vectorSearchScore' } } },
    { '$project'      => { resolved_path => 0 } }
  ]
  agg_pipeline.concat(Array(pipeline))

  collection.aggregate(agg_pipeline).map { |doc| instantiate(doc) }
end

#vector_search_index(name_or_defn, defn = nil)

Adds a vector search index definition. Also defines a read-only vector_search_score field on the model the first time it is called, which is populated on documents returned by #vector_search.

Examples:

Create a vector search index.

class Person
  include Mongoid::Document
  vector_search_index({ fields: [...] })
  vector_search_index :my_vector_index, { fields: [...] }
end

Parameters:

  • name_or_defn (Symbol | String | Hash)

    Either the name of the index to define, or the index definition.

  • defn (Hash) (defaults to: nil)

    The vector search index definition.

[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 213

def vector_search_index(name_or_defn, defn = nil)
  name = name_or_defn
  name, defn = nil, name if name.is_a?(Hash)

  spec = { type: 'vectorSearch', definition: defn }.tap { |s| s[:name] = name.to_s if name }
  search_index_specs.push(spec)

  return if fields.key?('vector_search_score')

  field :vector_search_score, type: Float
  attr_readonly :vector_search_score
end

#wait_for_search_indexes(names, interval: 5) {|SearchIndexable::Status| ... }

Waits for the named search indexes to be created.

Parameters:

  • names (Array<String>)

    the list of index names to wait for

  • interval (Integer)

    the number of seconds to wait before polling again (only used when a progress callback is given).

Yields:

[ GitHub ]

  
# File 'lib/mongoid/search_indexable.rb', line 122

def wait_for_search_indexes(names, interval: 5)
  loop do
    status = Status.new(get_indexes(names))
    yield status if block_given?
    break if status.ready?

    sleep interval
  end
end