blob: fecb09d4fa9f4f515cab7b69a4ce82214eeb538d [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
"""Builder to build batch vector search over multiple query vectors."""
from abc import ABC, abstractmethod
from copy import copy
from pypaimon.catalog.table_query_auth import reject_search_under_query_auth
from pypaimon.table.source.vector_search_builder import (
AbstractVectorSearchBuilderImpl,
)
from pypaimon.table.source.search_types import BatchVectorSearchRead # noqa: F401
class BatchVectorSearchBuilder(ABC):
"""Builder to build batch vector search; result ``i`` matches vector ``i``."""
@abstractmethod
def with_limit(self, limit):
# type: (int) -> BatchVectorSearchBuilder
"""The top k results to return per query vector."""
pass
@abstractmethod
def with_vector_column(self, name):
# type: (str) -> BatchVectorSearchBuilder
"""The vector column to search."""
pass
@abstractmethod
def with_query_vectors(self, vectors):
# type: (list) -> BatchVectorSearchBuilder
"""The query vectors (list of list of floats); result i matches vectors[i]."""
pass
def with_option(self, key, value):
# type: (str, str) -> BatchVectorSearchBuilder
"""Option for vector indexes."""
raise NotImplementedError(
"%s does not support vector options."
% self.__class__.__name__)
def with_options(self, options):
# type: (dict) -> BatchVectorSearchBuilder
"""Options for vector indexes."""
raise NotImplementedError(
"%s does not support vector options."
% self.__class__.__name__)
@abstractmethod
def with_filter(self, predicate):
# type: (Predicate) -> BatchVectorSearchBuilder
"""Scalar predicate used to pre-filter rows before vector search."""
pass
@abstractmethod
def with_partition_filter(self, partition_filter):
# type: (Predicate) -> BatchVectorSearchBuilder
"""Partition predicate used to prune index manifest entries."""
pass
@abstractmethod
def new_vector_search_scan(self):
# type: () -> VectorSearchScan
"""Create vector search scan to scan index files."""
pass
@abstractmethod
def new_batch_vector_search_read(self):
# type: () -> BatchVectorSearchRead
"""Create batch vector search read to read index files."""
pass
def execute_batch_local(self):
# type: () -> List[GlobalIndexResult]
"""Execute batch vector search locally; result i matches query vector i."""
return self.new_batch_vector_search_read().read_batch_plan(
self.new_vector_search_scan().scan()
)
class BatchVectorSearchBuilderImpl(AbstractVectorSearchBuilderImpl,
BatchVectorSearchBuilder):
"""Implementation for BatchVectorSearchBuilder."""
_native_batch_search = True
def __init__(self, table):
super().__init__(table)
self._query_vectors = None
def with_query_vectors(self, vectors):
# type: (list) -> BatchVectorSearchBuilder
self._query_vectors = vectors
return self
def execute_batch_local(self):
from pypaimon.table.source.search_dispatch import execute_vector_search
return execute_vector_search(self, self._query_vectors, batch=True)
def new_batch_vector_search_read(self):
# type: () -> BatchVectorSearchRead
reject_search_under_query_auth(self._table)
if self._limit <= 0:
raise ValueError("Limit must be positive, set via with_limit()")
if self._vector_column is None:
raise ValueError("Vector column must be set via with_vector_column()")
if not self._query_vectors:
raise ValueError(
"Query vectors must be set via with_query_vectors()")
from pypaimon.table.source.search_dispatch import create_vector_read
execution = copy(self)
execution._options = dict(self._options)
execution._query_vectors = [copy(vector) for vector in self._query_vectors]
return create_vector_read(execution, batch=True)