Module: Mongoid::SearchIndexable::ClassMethods

Defined in:
lib/mongoid/search_indexable.rb

Overview

Implementations for the feature's class-level methods.

Instance Method Summary collapse

Instance Method Details

#auto_embed_search(text, index: nil, path: nil, limit: 10, num_candidates: nil, filter: nil, exact: false, model: nil, pipeline: []) ⇒ Array<Mongoid::Document>

Performs an Atlas Vector Search query using auto-embedding. Atlas generates the query vector from the supplied text at query time; no pre-computed embedding is required.

Each returned document has a vector_search_score attribute populated with its relevance score. Unlike vector_search, the indexed text field is retained in returned documents.

Examples:

Search by text.

Article.auto_embed_search('machine learning', limit: 5)

Exact nearest-neighbor search (no numCandidates).

Article.auto_embed_search('deep learning', exact: true, limit: 5)


378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/mongoid/search_indexable.rb', line 378

def auto_embed_search(text, index: nil, path: nil, limit: 10, num_candidates: nil, filter: nil, exact: false, model: nil, pipeline: []) # rubocop:disable Metrics/ParameterLists
  resolved_index, resolved_path = resolve_auto_embed_index(index, path)

  vs_options = {
    'index' => resolved_index,
    'path' => resolved_path,
    'query' => { 'text' => text },
    'limit' => limit
  }
  vs_options['numCandidates'] = num_candidates || (limit * 10) unless exact
  vs_options['exact'] = true if exact
  vs_options['filter'] = filter if filter
  vs_options['model'] = model if model

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

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

#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.



161
162
163
164
165
166
167
# File 'lib/mongoid/search_indexable.rb', line 161

def create_search_indexes
  return if search_index_specs.empty?

  Threaded.with_collection_management do
    collection.search_indexes.create_many(search_index_specs)
  end
end

#remove_search_index(name: nil, id: nil) ⇒ Object

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



207
208
209
210
211
212
213
214
215
216
# File 'lib/mongoid/search_indexable.rb', line 207

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

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

#remove_search_indexesObject

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.



230
231
232
233
234
# File 'lib/mongoid/search_indexable.rb', line 230

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

#search_index(name_or_defn, defn = nil) ⇒ Object

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


249
250
251
252
253
254
255
# File 'lib/mongoid/search_indexable.rb', line 249

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 = {}) ⇒ Object

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

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)



196
197
198
199
200
# File 'lib/mongoid/search_indexable.rb', line 196

def search_indexes(options = {})
  Threaded.with_collection_management do
    collection.search_indexes(options)
  end
end

#vector_search(vector, index: nil, path: nil, limit: 10, num_candidates: nil, exact: false, 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' })


324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/mongoid/search_indexable.rb', line 324

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

  vs_options = {
    'index' => resolved_index,
    'path' => resolved_path,
    'queryVector' => vector,
    'limit' => limit
  }
  vs_options['numCandidates'] = num_candidates || (limit * 10) unless exact
  vs_options['exact'] = true if exact
  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) ⇒ Object

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

Create a flat vector search index.

class Person
  include Mongoid::Document
  vector_search_index fields: [
    { type: 'vector', path: 'embedding', numDimensions: 1536,
      similarity: 'cosine', indexingMethod: 'flat' }
  ]
end


280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/mongoid/search_indexable.rb', line 280

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

  validate_vector_index_definition!(defn)

  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| ... } ⇒ Object

Waits for the named search indexes to be created.

Yields:



176
177
178
179
180
181
182
183
184
# File 'lib/mongoid/search_indexable.rb', line 176

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