// Copyright 2026 Google LLC
//
// 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.

syntax = "proto3";

package google.cloud.vectorsearch.v1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/cloud/vectorsearch/v1/common.proto";
import "google/cloud/vectorsearch/v1/data_object.proto";
import "google/cloud/vectorsearch/v1/embedding_config.proto";
import "google/protobuf/struct.proto";

option csharp_namespace = "Google.Cloud.VectorSearch.V1";
option go_package = "cloud.google.com/go/vectorsearch/apiv1/vectorsearchpb;vectorsearchpb";
option java_multiple_files = true;
option java_outer_classname = "DataObjectSearchServiceProto";
option java_package = "com.google.cloud.vectorsearch.v1";
option php_namespace = "Google\\Cloud\\VectorSearch\\V1";
option ruby_package = "Google::Cloud::VectorSearch::V1";

// Service for searching data objects.
service DataObjectSearchService {
  option (google.api.default_host) = "vectorsearch.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform";

  // Searches data objects.
  rpc SearchDataObjects(SearchDataObjectsRequest)
      returns (SearchDataObjectsResponse) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*/collections/*}/dataObjects:search"
      body: "*"
    };
  }

  // Queries data objects.
  rpc QueryDataObjects(QueryDataObjectsRequest)
      returns (QueryDataObjectsResponse) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*/collections/*}/dataObjects:query"
      body: "*"
    };
  }

  // Aggregates data objects.
  rpc AggregateDataObjects(AggregateDataObjectsRequest)
      returns (AggregateDataObjectsResponse) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*/collections/*}/dataObjects:aggregate"
      body: "*"
    };
  }

  // Batch searches data objects.
  rpc BatchSearchDataObjects(BatchSearchDataObjectsRequest)
      returns (BatchSearchDataObjectsResponse) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*/collections/*}/dataObjects:batchSearch"
      body: "*"
    };
  }
}

// Aggregation methods.
enum AggregationMethod {
  // Should not be used.
  AGGREGATION_METHOD_UNSPECIFIED = 0;

  // Count the number of data objects that match the filter.
  COUNT = 1;
}

// Defines a output fields struct for data in DataObject.
message OutputFields {
  // Optional. The fields from the data fields to include in the output.
  repeated string data_fields = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The fields from the vector fields to include in the output.
  repeated string vector_fields = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The fields from the DataObject metadata to include in the output.
  repeated string metadata_fields = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Represents a hint to the search index engine.
message SearchHint {
  // Message to specify the index to use for the search.
  message IndexHint {
    // Required. The resource name of the index to use for the search.
    // The index must be in the same project, location, and collection.
    // Format:
    // `projects/{project}/locations/{location}/collections/{collection}/indexes/{index}`
    string name = 1 [
      (google.api.field_behavior) = REQUIRED,
      (google.api.resource_reference) = {
        type: "vectorsearch.googleapis.com/Index"
      }
    ];
  }

  // KnnHint will be used if search should be explicitly done on system's
  // default K-Nearest Neighbor (KNN) index engine.
  message KnnHint {}

  // The type of index to use.
  oneof index_type {
    // Optional. If set, the search will use the system's default
    // K-Nearest Neighbor (KNN) index engine.
    KnnHint knn_hint = 3 [(google.api.field_behavior) = OPTIONAL];

    // Optional. Specifies that the search should use a particular index.
    IndexHint index_hint = 4 [(google.api.field_behavior) = OPTIONAL];
  }
}

// A single search request within a batch operation.
message Search {
  // The type of search to perform.
  oneof search_type {
    // A vector-based search.
    VectorSearch vector_search = 1;

    // A semantic search.
    SemanticSearch semantic_search = 2;

    // A text search operation.
    TextSearch text_search = 3;
  }
}

// Defines a search operation using a query vector.
message VectorSearch {
  // Specifies the type of vector to use for the query.
  oneof vector_type {
    // A dense vector for the query.
    DenseVector vector = 1;

    // A sparse vector for the query.
    SparseVector sparse_vector = 2;
  }

  // Required. The vector field to search.
  string search_field = 8 [(google.api.field_behavior) = REQUIRED];

  // Optional. A JSON filter expression, e.g. {"genre": {"$eq": "sci-fi"}},
  // represented as a google.protobuf.Struct.
  google.protobuf.Struct filter = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The number of nearest neighbors to return.
  optional int32 top_k = 5 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Mask specifying which fields to return.
  OutputFields output_fields = 7 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Sets the search hint. If no strategy is specified, the service
  // will use an index if one is available, and fall back to the default KNN
  // search otherwise.
  SearchHint search_hint = 9 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The distance metric to use for the KNN search. If not specified,
  // DOT_PRODUCT will be used as the default.
  DistanceMetric distance_metric = 11 [(google.api.field_behavior) = OPTIONAL];
}

// Defines a semantic search operation.
message SemanticSearch {
  // Required. The query text, which is used to generate an embedding according
  // to the embedding model specified in the collection config.
  string search_text = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The vector field to search.
  string search_field = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The task type of the query embedding.
  EmbeddingTaskType task_type = 5 [(google.api.field_behavior) = REQUIRED];

  // Optional. The fields to return in the search results.
  OutputFields output_fields = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A JSON filter expression, e.g. {"genre": {"$eq": "sci-fi"}},
  // represented as a google.protobuf.Struct.
  google.protobuf.Struct filter = 6 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The number of data objects to return.
  optional int32 top_k = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Sets the search hint. If no strategy is specified, the service
  // will use an index if one is available, and fall back to KNN search
  // otherwise.
  SearchHint search_hint = 7 [(google.api.field_behavior) = OPTIONAL];
}

// Defines a text search operation.
message TextSearch {
  // Required. The query text.
  string search_text = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The data field names to search.
  repeated string data_field_names = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. The fields to return in the search results.
  OutputFields output_fields = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The number of results to return.
  optional int32 top_k = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A JSON filter expression, e.g. `{"genre": {"$eq": "sci-fi"}}`,
  // represented as a `google.protobuf.Struct`.
  google.protobuf.Struct filter = 5 [(google.api.field_behavior) = OPTIONAL];
}

// Request for performing a single search.
message SearchDataObjectsRequest {
  // The query to search for.
  oneof search_type {
    // A vector search operation.
    VectorSearch vector_search = 2;

    // A semantic search operation.
    SemanticSearch semantic_search = 4;

    // Optional. A text search operation.
    TextSearch text_search = 7 [(google.api.field_behavior) = OPTIONAL];
  }

  // Required. The resource name of the Collection for which to search.
  // Format: `projects/{project}/locations/{location}/collections/{collection}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "vectorsearch.googleapis.com/Collection"
    }
  ];

  // Optional. The standard list page size. Only supported for KNN. If not set,
  // up to search_type.top_k results will be returned. The maximum value is
  // 1000; values above 1000 will be coerced to 1000.
  int32 page_size = 5 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The standard list page token.
  // Typically obtained via
  // [SearchDataObjectsResponse.next_page_token][google.cloud.vectorsearch.v1.SearchDataObjectsResponse.next_page_token]
  // of the previous
  // [DataObjectSearchService.SearchDataObjects][google.cloud.vectorsearch.v1.DataObjectSearchService.SearchDataObjects]
  // call.
  string page_token = 6 [(google.api.field_behavior) = OPTIONAL];
}

// A single search result.
message SearchResult {
  // Output only. The matching data object.
  DataObject data_object = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Similarity distance or ranker score returned by
  // BatchSearchDataObjects.
  optional double distance = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Response for a search request.
message SearchDataObjectsResponse {
  // Output only. The list of dataObjects that match the search criteria.
  repeated SearchResult results = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. A token to retrieve next page of results.
  // Pass to [DataObjectSearchService.SearchDataObjectsRequest.page_token][] to
  // obtain that page.
  string next_page_token = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Request message for
// [DataObjectSearchService.AggregateDataObjects][google.cloud.vectorsearch.v1.DataObjectSearchService.AggregateDataObjects].
message AggregateDataObjectsRequest {
  // Required. The resource name of the Collection for which to query.
  // Format: `projects/{project}/locations/{location}/collections/{collection}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "vectorsearch.googleapis.com/Collection"
    }
  ];

  // Optional. A JSON filter expression, e.g. {"genre": {"$eq": "sci-fi"}},
  // represented as a google.protobuf.Struct.
  google.protobuf.Struct filter = 2 [(google.api.field_behavior) = OPTIONAL];

  // Required. The aggregation method to apply to the query.
  AggregationMethod aggregate = 3 [(google.api.field_behavior) = REQUIRED];
}

// Response message for
// [DataObjectSearchService.AggregateDataObjects][google.cloud.vectorsearch.v1.DataObjectSearchService.AggregateDataObjects].
message AggregateDataObjectsResponse {
  // Output only. The aggregated results of the query.
  repeated google.protobuf.Struct aggregate_results = 1
      [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Request message for
// [DataObjectSearchService.QueryDataObjects][google.cloud.vectorsearch.v1.DataObjectSearchService.QueryDataObjects].
message QueryDataObjectsRequest {
  // Required. The resource name of the Collection for which to query.
  // Format: `projects/{project}/locations/{location}/collections/{collection}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "vectorsearch.googleapis.com/Collection"
    }
  ];

  // Optional. A JSON filter expression, e.g. {"genre": {"$eq": "sci-fi"}},
  // represented as a google.protobuf.Struct.
  google.protobuf.Struct filter = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Mask specifying which fields to return.
  OutputFields output_fields = 7 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The standard list page size. Default is 100.
  // The maximum value is 1000; values above 1000 will be coerced to 1000.
  int32 page_size = 5 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The standard list page token.
  // Typically obtained via
  // [QueryDataObjectsResponse.next_page_token][google.cloud.vectorsearch.v1.QueryDataObjectsResponse.next_page_token]
  // of the previous
  // [DataObjectSearchService.QueryDataObjects][google.cloud.vectorsearch.v1.DataObjectSearchService.QueryDataObjects]
  // call.
  string page_token = 6 [(google.api.field_behavior) = OPTIONAL];
}

// Response message for
// [DataObjectSearchService.QueryDataObjects][google.cloud.vectorsearch.v1.DataObjectSearchService.QueryDataObjects].
message QueryDataObjectsResponse {
  // Output only. The list of dataObjects that match the query.
  repeated DataObject data_objects = 4
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. A token to retrieve next page of results.
  // Pass to [DataObjectSearchService.QueryDataObjectsRequest.page_token][] to
  // obtain that page.
  string next_page_token = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// A request to perform a batch of search operations.
message BatchSearchDataObjectsRequest {
  // Options for combining the results of the batch search operations.
  message CombineResultsOptions {
    // Required. The ranker to use for combining the results.
    Ranker ranker = 1 [(google.api.field_behavior) = REQUIRED];

    // Optional. Mask specifying which fields to return.
    OutputFields output_fields = 2 [(google.api.field_behavior) = OPTIONAL];

    // Optional. The number of results to return. If not set, a default value
    // will be used.
    int32 top_k = 3 [(google.api.field_behavior) = OPTIONAL];
  }

  // Required. The resource name of the Collection for which to search.
  // Format: `projects/{project}/locations/{location}/collections/{collection}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "vectorsearch.googleapis.com/Collection"
    }
  ];

  // Required. A list of search requests to execute in parallel.
  repeated Search searches = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. Options for combining the results of the batch search operations.
  CombineResultsOptions combine = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Defines a ranker to combine results from multiple searches.
message Ranker {
  // The ranking method to use.
  oneof ranker {
    // Reciprocal Rank Fusion ranking.
    ReciprocalRankFusion rrf = 1;
  }
}

// Defines the Reciprocal Rank Fusion (RRF) algorithm for result ranking.
message ReciprocalRankFusion {
  // Required. The weights to apply to each search result set during fusion.
  repeated double weights = 1 [(google.api.field_behavior) = REQUIRED];
}

// A response from a batch search operation.
message BatchSearchDataObjectsResponse {
  // Output only. A list of search responses, one for each request in the batch.
  // If a ranker is used, a single ranked list of results is returned.
  repeated SearchDataObjectsResponse results = 1
      [(google.api.field_behavior) = OUTPUT_ONLY];
}
