Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RCBC-469: Support for Scoped Search Indexes #132

Merged
merged 1 commit into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ext/couchbase
157 changes: 131 additions & 26 deletions ext/couchbase.cxx

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions lib/couchbase/cluster.rb
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def analytics_query(statement, options = Options::Analytics::DEFAULT)
#
# @return [SearchResult]
def search_query(index_name, query, options = Options::Search::DEFAULT)
resp = @backend.document_search(index_name, JSON.generate(query), {}, options.to_backend)
resp = @backend.document_search(nil, nil, index_name, JSON.generate(query), {}, options.to_backend)
convert_search_result(resp, options)
end

Expand All @@ -202,7 +202,7 @@ def search_query(index_name, query, options = Options::Search::DEFAULT)
# @return [SearchResult]
def search(index_name, search_request, options = Options::Search::DEFAULT)
encoded_query, encoded_req = search_request.to_backend
resp = @backend.document_search(index_name, encoded_query, encoded_req, options.to_backend(show_request: false))
resp = @backend.document_search(nil, nil, index_name, encoded_query, encoded_req, options.to_backend(show_request: false))
convert_search_result(resp, options)
end

Expand Down
1 change: 1 addition & 0 deletions lib/couchbase/management.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ module Management
require "couchbase/management/query_index_manager"
require "couchbase/management/collection_query_index_manager"
require "couchbase/management/search_index_manager"
require "couchbase/management/scope_search_index_manager"
require "couchbase/management/user_manager"
require "couchbase/management/view_index_manager"
199 changes: 199 additions & 0 deletions lib/couchbase/management/scope_search_index_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# Copyright 2024. Couchbase, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

module Couchbase
module Management
# @api volatile
class ScopeSearchIndexManager
alias inspect to_s

# @param [Couchbase::Backend] backend
# @param [String] bucket_name
# @param [String] scope_name
def initialize(backend, bucket_name, scope_name)
@backend = backend
@bucket_name = bucket_name
@scope_name = scope_name
end

# Fetches an index from the server if it exists
#
# @param [String] index_name name of the index
# @param [GetIndexOptions] options
#
# @return [SearchIndex]
#
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def get_index(index_name, options = GetIndexOptions.new)
res = @backend.search_index_get(@bucket_name, @scope_name, index_name, options.timeout)
SearchIndexManager.extract_search_index(res)
end

# Fetches all indexes from the server
#
# @param [GetAllIndexesOptions] options
#
# @return [Array<SearchIndex>]
def get_all_indexes(options = GetAllIndexesOptions.new)
res = @backend.search_index_get_all(@bucket_name, @scope_name, options.timeout)
res[:indexes].map { |idx| SearchIndexManager.extract_search_index(idx) }
end

# Creates or updates the index
#
# @param [SearchIndex] index_definition the index definition
# @param [UpsertIndexOptions] options
#
# @return void
#
# @raise [ArgumentError] if name, type or source_type is empty
def upsert_index(index_definition, options = UpsertIndexOptions.new)
@backend.search_index_upsert(@bucket_name, @scope_name, index_definition.to_backend, options.timeout)
end

# Drops the index
#
# @param [String] index_name name of the index
# @param [DropIndexOptions] options
#
# @return void
#
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def drop_index(index_name, options = DropIndexOptions.new)
@backend.search_index_drop(@bucket_name, @scope_name, index_name, options.timeout)
end

# Retrieves the number of documents that have been indexed for an index
#
# @param [String] index_name name of the index
# @param [GetIndexedDocumentsCountOptions] options
#
# @return [Integer]
#
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def get_indexed_documents_count(index_name, options = GetIndexedDocumentsCountOptions.new)
res = @backend.search_index_get_documents_count(@bucket_name, @scope_name, index_name, options.timeout)
res[:count]
end

# Pauses updates and maintenance for the index
#
# @param [String] index_name name of the index
# @param [PauseIngestOptions] options
#
# @return void
#
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def pause_ingest(index_name, options = PauseIngestOptions.new)
@backend.search_index_pause_ingest(@bucket_name, @scope_name, index_name, options.timeout)
end

# Resumes updates and maintenance for an index
#
# @param [String] index_name name of the index
# @param [ResumeIngestOptions] options
#
# @return void
#
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def resume_ingest(index_name, options = ResumeIngestOptions.new)
@backend.search_index_resume_ingest(@bucket_name, @scope_name, index_name, options.timeout)
end

# Allows querying against the index
#
# @param [String] index_name name of the index
# @param [AllowQueryingOptions] options
#
# @return void
#
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def allow_querying(index_name, options = AllowQueryingOptions.new)
@backend.search_index_allow_querying(@bucket_name, @scope_name, index_name, options.timeout)
end

# Disallows querying against the index
#
# @param [String] index_name name of the index
# @param [DisallowQueryingOptions] options
#
# @return void
#
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def disallow_querying(index_name, options = DisallowQueryingOptions.new)
@backend.search_index_disallow_querying(@bucket_name, @scope_name, index_name, options.timeout)
end

# Freeze the assignment of index partitions to nodes
#
# @param [String] index_name name of the index
# @param [FreezePlanOptions] options
#
# @return void
#
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def freeze_plan(index_name, options = FreezePlanOptions.new)
@backend.search_index_freeze_plan(@bucket_name, @scope_name, index_name, options.timeout)
end

# Unfreeze the assignment of index partitions to nodes
#
# @param [String] index_name name of the index
# @param [UnfreezePlanOptions] options
#
# @return void
#
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def unfreeze_plan(index_name, options = UnfreezePlanOptions.new)
@backend.search_index_unfreeze_plan(@bucket_name, @scope_name, index_name, options.timeout)
end

# Allows to see how a document is analyzed against a specific index
#
# @param [String] index_name name of the index
# @param [Hash] document the document to be analyzed
#
# @return [Array<Hash>]
#
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def analyze_document(index_name, document, options = AnalyzeDocumentOptions.new)
res = @backend.search_index_analyze_document(@bucket_name, @scope_name, index_name, JSON.generate(document), options.timeout)
JSON.parse(res[:analysis])
end

GetIndexOptions = SearchIndexManager::GetIndexOptions
GetAllIndexesOptions = SearchIndexManager::GetAllIndexesOptions
UpsertIndexOptions = SearchIndexManager::UpsertIndexOptions
DropIndexOptions = SearchIndexManager::DropIndexOptions
GetIndexedDocumentsCountOptions = SearchIndexManager::GetIndexedDocumentsCountOptions
PauseIngestOptions = SearchIndexManager::PauseIngestOptions
ResumeIngestOptions = SearchIndexManager::ResumeIngestOptions
AllowQueryingOptions = SearchIndexManager::AllowQueryingOptions
DisallowQueryingOptions = SearchIndexManager::DisallowQueryingOptions
FreezePlanOptions = SearchIndexManager::FreezePlanOptions
UnfreezePlanOptions = SearchIndexManager::UnfreezePlanOptions
AnalyzeDocumentOptions = SearchIndexManager::AnalyzeDocumentOptions
end
end
end
48 changes: 32 additions & 16 deletions lib/couchbase/management/search_index_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ def initialize(backend)
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def get_index(index_name, options = GetIndexOptions.new)
res = @backend.search_index_get(index_name, options.timeout)
extract_search_index(res)
res = @backend.search_index_get(nil, nil, index_name, options.timeout)
self.class.extract_search_index(res)
end

# Fetches all indexes from the server
Expand All @@ -44,8 +44,8 @@ def get_index(index_name, options = GetIndexOptions.new)
#
# @return [Array<SearchIndex>]
def get_all_indexes(options = GetAllIndexesOptions.new)
res = @backend.search_index_get_all(options.timeout)
res[:indexes].map { |idx| extract_search_index(idx) }
res = @backend.search_index_get_all(nil, nil, options.timeout)
res[:indexes].map { |idx| self.class.extract_search_index(idx) }
end

# Creates or updates the index
Expand All @@ -58,6 +58,8 @@ def get_all_indexes(options = GetAllIndexesOptions.new)
# @raise [ArgumentError] if name, type or source_type is empty
def upsert_index(index_definition, options = UpsertIndexOptions.new)
@backend.search_index_upsert(
nil,
nil,
{
name: index_definition.name,
type: index_definition.type,
Expand All @@ -82,7 +84,7 @@ def upsert_index(index_definition, options = UpsertIndexOptions.new)
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def drop_index(index_name, options = DropIndexOptions.new)
@backend.search_index_drop(index_name, options.timeout)
@backend.search_index_drop(nil, nil, index_name, options.timeout)
end

# Retrieves the number of documents that have been indexed for an index
Expand All @@ -95,7 +97,7 @@ def drop_index(index_name, options = DropIndexOptions.new)
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def get_indexed_documents_count(index_name, options = GetIndexedDocumentsCountOptions.new)
res = @backend.search_index_get_documents_count(index_name, options.timeout)
res = @backend.search_index_get_documents_count(nil, nil, index_name, options.timeout)
res[:count]
end

Expand Down Expand Up @@ -140,7 +142,7 @@ def get_stats(options = GetIndexStatsOptions.new)
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def pause_ingest(index_name, options = PauseIngestOptions.new)
@backend.search_index_pause_ingest(index_name, options.timeout)
@backend.search_index_pause_ingest(nil, nil, index_name, options.timeout)
end

# Resumes updates and maintenance for an index
Expand All @@ -153,7 +155,7 @@ def pause_ingest(index_name, options = PauseIngestOptions.new)
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def resume_ingest(index_name, options = ResumeIngestOptions.new)
@backend.search_index_resume_ingest(index_name, options.timeout)
@backend.search_index_resume_ingest(nil, nil, index_name, options.timeout)
end

# Allows querying against the index
Expand All @@ -166,7 +168,7 @@ def resume_ingest(index_name, options = ResumeIngestOptions.new)
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def allow_querying(index_name, options = AllowQueryingOptions.new)
@backend.search_index_allow_querying(index_name, options.timeout)
@backend.search_index_allow_querying(nil, nil, index_name, options.timeout)
end

# Disallows querying against the index
Expand All @@ -179,7 +181,7 @@ def allow_querying(index_name, options = AllowQueryingOptions.new)
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def disallow_querying(index_name, options = DisallowQueryingOptions.new)
@backend.search_index_disallow_querying(index_name, options.timeout)
@backend.search_index_disallow_querying(nil, nil, index_name, options.timeout)
end

# Freeze the assignment of index partitions to nodes
Expand All @@ -192,7 +194,7 @@ def disallow_querying(index_name, options = DisallowQueryingOptions.new)
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def freeze_plan(index_name, options = FreezePlanOptions.new)
@backend.search_index_freeze_plan(index_name, options.timeout)
@backend.search_index_freeze_plan(nil, nil, index_name, options.timeout)
end

# Unfreeze the assignment of index partitions to nodes
Expand All @@ -205,7 +207,7 @@ def freeze_plan(index_name, options = FreezePlanOptions.new)
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def unfreeze_plan(index_name, options = UnfreezePlanOptions.new)
@backend.search_index_unfreeze_plan(index_name, options.timeout)
@backend.search_index_unfreeze_plan(nil, nil, index_name, options.timeout)
end

# Allows to see how a document is analyzed against a specific index
Expand All @@ -218,7 +220,7 @@ def unfreeze_plan(index_name, options = UnfreezePlanOptions.new)
# @raise [ArgumentError]
# @raise [Error::IndexNotFound]
def analyze_document(index_name, document, options = AnalyzeDocumentOptions.new)
res = @backend.search_index_analyze_document(index_name, JSON.generate(document), options.timeout)
res = @backend.search_index_analyze_document(nil, nil, index_name, JSON.generate(document), options.timeout)
JSON.parse(res[:analysis])
end

Expand Down Expand Up @@ -352,9 +354,8 @@ def initialize
end
end

private

def extract_search_index(resp)
# @api private
def self.extract_search_index(resp)
SearchIndex.new do |index|
index.name = resp[:name]
index.type = resp[:type]
Expand Down Expand Up @@ -403,6 +404,21 @@ def initialize
@source_type = "couchbase"
yield self if block_given?
end

# @api private
def to_backend
{
name: name,
type: type,
uuid: uuid,
params: (JSON.generate(params) if params),
source_name: source_name,
source_type: source_type,
source_uuid: source_uuid,
source_params: (JSON.generate(source_params) if source_params),
plan_params: (JSON.generate(plan_params) if plan_params),
}
end
end
end
end
Loading
Loading