pinecone 5.4.0.dev4__tar.gz → 5.4.0.dev5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/PKG-INFO +2 -2
- pinecone-5.4.0.dev5/pinecone/__version__ +1 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/control/pinecone.py +8 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/shared/api_client.py +67 -6
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/shared/configuration.py +20 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/data/index.py +134 -2
- pinecone-5.4.0.dev5/pinecone/data/query_results_aggregator.py +193 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/__init__.py +4 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/base.py +10 -0
- pinecone-5.4.0.dev5/pinecone/grpc/future.py +86 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/index_grpc.py +70 -10
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/pinecone.py +3 -1
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/utils.py +9 -4
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pyproject.toml +6 -2
- pinecone-5.4.0.dev4/pinecone/__version__ +0 -1
- pinecone-5.4.0.dev4/pinecone/grpc/future.py +0 -34
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/LICENSE.txt +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/README.md +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/config/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/config/config.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/config/openapi.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/config/pinecone_config.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/control/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/control/index_host_store.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/control/langchain_import_warnings.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/control/repr_overrides.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/grpc/protos/vector_service_pb2.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/grpc/protos/vector_service_pb2.pyi +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/grpc/protos/vector_service_pb2_grpc.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/api/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/api/inference_api.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/api/manage_indexes_api.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/apis/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/collection_list.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/collection_model.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/configure_index_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/configure_index_request_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/configure_index_request_spec_pod.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/create_collection_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/create_index_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/deletion_protection.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/embed_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/embed_request_inputs.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/embed_request_parameters.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/embedding.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/embeddings_list.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/embeddings_list_usage.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/error_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/error_response_error.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/index_list.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/index_model.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/index_model_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/index_model_status.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/index_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/pod_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/pod_spec_metadata_config.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/model/serverless_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/control/models/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/api/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/api/data_plane_api.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/apis/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/delete_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/describe_index_stats_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/describe_index_stats_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/fetch_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/list_item.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/list_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/namespace_summary.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/pagination.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/protobuf_any.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/protobuf_null_value.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/query_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/query_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/query_vector.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/rpc_status.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/scored_vector.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/single_query_results.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/sparse_values.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/update_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/upsert_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/upsert_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/usage.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/model/vector.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/data/models/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/shared/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/shared/exceptions.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/shared/model_utils.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core/openapi/shared/rest.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/api/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/api/manage_indexes_api.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/apis/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/collection_list.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/collection_model.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/configure_index_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/configure_index_request_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/configure_index_request_spec_pod.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/create_collection_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/create_index_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/deletion_protection.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/error_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/error_response_error.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/index_list.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/index_model.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/index_model_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/index_model_status.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/index_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/pod_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/pod_spec_metadata_config.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/model/serverless_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_control/models/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/api/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/api/bulk_operations_api.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/api/vector_operations_api.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/apis/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/delete_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/describe_index_stats_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/describe_index_stats_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/fetch_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/import_error_mode.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/import_list_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/import_model.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/list_item.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/list_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/namespace_summary.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/pagination.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/protobuf_any.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/protobuf_null_value.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/query_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/query_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/query_vector.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/rpc_status.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/scored_vector.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/single_query_results.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/sparse_values.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/start_import_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/start_import_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/update_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/upsert_request.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/upsert_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/usage.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/model/vector.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/db_data/models/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/shared/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/shared/api_client.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/shared/configuration.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/shared/exceptions.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/shared/model_utils.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/core_ea/openapi/shared/rest.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/data/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/data/errors.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/data/features/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/data/features/bulk_import.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/data/sparse_vector_factory.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/data/vector_factory.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/deprecation_warnings.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/exceptions/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/exceptions/exceptions.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/channel_factory.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/config.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/grpc_runner.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/retry.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/sparse_values_factory.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/grpc/vector_factory_grpc.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/models/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/models/collection_description.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/models/collection_list.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/models/index_description.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/models/index_list.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/models/index_model.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/models/list_response.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/models/pod_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/models/serverless_spec.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/__init__.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/check_kwargs.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/constants.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/convert_to_list.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/deprecation_notice.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/docslinks.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/error_handling.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/fix_tuple_length.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/normalize_host.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/parse_args.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/repr_overrides.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/setup_openapi_client.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/user_agent.py +0 -0
- {pinecone-5.4.0.dev4 → pinecone-5.4.0.dev5}/pinecone/utils/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pinecone
|
|
3
|
-
Version: 5.4.0.
|
|
3
|
+
Version: 5.4.0.dev5
|
|
4
4
|
Summary: Pinecone client and SDK
|
|
5
5
|
Home-page: https://www.pinecone.io
|
|
6
6
|
License: Apache-2.0
|
|
@@ -35,7 +35,7 @@ Requires-Dist: grpcio (>=1.59.0) ; (python_version >= "3.11" and python_version
|
|
|
35
35
|
Requires-Dist: lz4 (>=3.1.3) ; extra == "grpc"
|
|
36
36
|
Requires-Dist: pinecone-plugin-inference (>=2.0.0,<3.0.0)
|
|
37
37
|
Requires-Dist: pinecone-plugin-interface (>=0.0.7,<0.0.8)
|
|
38
|
-
Requires-Dist: protobuf (>=
|
|
38
|
+
Requires-Dist: protobuf (>=4.25,<5.0) ; extra == "grpc"
|
|
39
39
|
Requires-Dist: protoc-gen-openapiv2 (>=0.0.1,<0.0.2) ; extra == "grpc"
|
|
40
40
|
Requires-Dist: python-dateutil (>=2.5.3)
|
|
41
41
|
Requires-Dist: tqdm (>=4.64.1)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
5.4.0.dev5
|
|
@@ -765,6 +765,14 @@ class Pinecone:
|
|
|
765
765
|
# Now you're ready to perform data operations
|
|
766
766
|
index.query(vector=[...], top_k=10)
|
|
767
767
|
```
|
|
768
|
+
|
|
769
|
+
Arguments:
|
|
770
|
+
name: The name of the index to target. If you specify the name of the index, the client will
|
|
771
|
+
fetch the host url from the Pinecone control plane.
|
|
772
|
+
host: The host url of the index to target. If you specify the host url, the client will use
|
|
773
|
+
the host url directly without making any additional calls to the control plane.
|
|
774
|
+
pool_threads: The number of threads to use when making parallel requests by calling index methods with optional kwarg async_req=True, or using methods that make use of parallelism automatically such as query_namespaces(). Default: 1
|
|
775
|
+
connection_pool_maxsize: The maximum number of connections to keep in the connection pool. Default: 5 * multiprocessing.cpu_count()
|
|
768
776
|
"""
|
|
769
777
|
if name == "" and host == "":
|
|
770
778
|
raise ValueError("Either name or host must be specified")
|
|
@@ -2,12 +2,31 @@ import json
|
|
|
2
2
|
import atexit
|
|
3
3
|
import mimetypes
|
|
4
4
|
from multiprocessing.pool import ThreadPool
|
|
5
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
5
6
|
import io
|
|
6
7
|
import os
|
|
7
8
|
import re
|
|
8
9
|
import typing
|
|
9
10
|
from urllib.parse import quote
|
|
10
11
|
from urllib3.fields import RequestField
|
|
12
|
+
import time
|
|
13
|
+
import random
|
|
14
|
+
|
|
15
|
+
def retry_api_call(
|
|
16
|
+
func, args=(), kwargs={}, retries=3, backoff=1, jitter=0.5
|
|
17
|
+
):
|
|
18
|
+
attempts = 0
|
|
19
|
+
while attempts < retries:
|
|
20
|
+
try:
|
|
21
|
+
return func(*args, **kwargs) # Attempt to call __call_api
|
|
22
|
+
except Exception as e:
|
|
23
|
+
attempts += 1
|
|
24
|
+
if attempts >= retries:
|
|
25
|
+
print(f"API call failed after {attempts} attempts: {e}")
|
|
26
|
+
raise # Re-raise exception if retries are exhausted
|
|
27
|
+
sleep_time = backoff * (2 ** (attempts - 1)) + random.uniform(0, jitter)
|
|
28
|
+
# print(f"Retrying ({attempts}/{retries}) in {sleep_time:.2f} seconds after error: {e}")
|
|
29
|
+
time.sleep(sleep_time)
|
|
11
30
|
|
|
12
31
|
|
|
13
32
|
from pinecone.core.openapi.shared import rest
|
|
@@ -52,6 +71,7 @@ class ApiClient(object):
|
|
|
52
71
|
"""
|
|
53
72
|
|
|
54
73
|
_pool = None
|
|
74
|
+
_threadpool_executor = None
|
|
55
75
|
|
|
56
76
|
def __init__(self, configuration=None, header_name=None, header_value=None, cookie=None, pool_threads=1):
|
|
57
77
|
if configuration is None:
|
|
@@ -74,6 +94,9 @@ class ApiClient(object):
|
|
|
74
94
|
self.close()
|
|
75
95
|
|
|
76
96
|
def close(self):
|
|
97
|
+
if self._threadpool_executor:
|
|
98
|
+
self._threadpool_executor.shutdown()
|
|
99
|
+
self._threadpool_executor = None
|
|
77
100
|
if self._pool:
|
|
78
101
|
self._pool.close()
|
|
79
102
|
self._pool.join()
|
|
@@ -91,6 +114,12 @@ class ApiClient(object):
|
|
|
91
114
|
self._pool = ThreadPool(self.pool_threads)
|
|
92
115
|
return self._pool
|
|
93
116
|
|
|
117
|
+
@property
|
|
118
|
+
def threadpool_executor(self):
|
|
119
|
+
if self._threadpool_executor is None:
|
|
120
|
+
self._threadpool_executor = ThreadPoolExecutor(max_workers=self.pool_threads)
|
|
121
|
+
return self._threadpool_executor
|
|
122
|
+
|
|
94
123
|
@property
|
|
95
124
|
def user_agent(self):
|
|
96
125
|
"""User agent for this API client"""
|
|
@@ -316,6 +345,7 @@ class ApiClient(object):
|
|
|
316
345
|
response_type: typing.Optional[typing.Tuple[typing.Any]] = None,
|
|
317
346
|
auth_settings: typing.Optional[typing.List[str]] = None,
|
|
318
347
|
async_req: typing.Optional[bool] = None,
|
|
348
|
+
async_threadpool_executor: typing.Optional[bool] = None,
|
|
319
349
|
_return_http_data_only: typing.Optional[bool] = None,
|
|
320
350
|
collection_formats: typing.Optional[typing.Dict[str, str]] = None,
|
|
321
351
|
_preload_content: bool = True,
|
|
@@ -376,8 +406,9 @@ class ApiClient(object):
|
|
|
376
406
|
If parameter async_req is False or missing,
|
|
377
407
|
then the method will return the response directly.
|
|
378
408
|
"""
|
|
379
|
-
if
|
|
380
|
-
return self.
|
|
409
|
+
if async_threadpool_executor:
|
|
410
|
+
return self.threadpool_executor.submit(
|
|
411
|
+
self.__call_api,
|
|
381
412
|
resource_path,
|
|
382
413
|
method,
|
|
383
414
|
path_params,
|
|
@@ -396,9 +427,8 @@ class ApiClient(object):
|
|
|
396
427
|
_check_type,
|
|
397
428
|
)
|
|
398
429
|
|
|
399
|
-
|
|
400
|
-
self.__call_api
|
|
401
|
-
(
|
|
430
|
+
if not async_req:
|
|
431
|
+
return self.__call_api(
|
|
402
432
|
resource_path,
|
|
403
433
|
method,
|
|
404
434
|
path_params,
|
|
@@ -415,7 +445,35 @@ class ApiClient(object):
|
|
|
415
445
|
_request_timeout,
|
|
416
446
|
_host,
|
|
417
447
|
_check_type,
|
|
418
|
-
)
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
return self.pool.apply_async(
|
|
451
|
+
retry_api_call,
|
|
452
|
+
args=(
|
|
453
|
+
self.__call_api, # Pass the API call function as the first argument
|
|
454
|
+
(
|
|
455
|
+
resource_path,
|
|
456
|
+
method,
|
|
457
|
+
path_params,
|
|
458
|
+
query_params,
|
|
459
|
+
header_params,
|
|
460
|
+
body,
|
|
461
|
+
post_params,
|
|
462
|
+
files,
|
|
463
|
+
response_type,
|
|
464
|
+
auth_settings,
|
|
465
|
+
_return_http_data_only,
|
|
466
|
+
collection_formats,
|
|
467
|
+
_preload_content,
|
|
468
|
+
_request_timeout,
|
|
469
|
+
_host,
|
|
470
|
+
_check_type,
|
|
471
|
+
),
|
|
472
|
+
{}, # empty kwargs dictionary
|
|
473
|
+
3, # retries
|
|
474
|
+
1, # backoff time
|
|
475
|
+
0.5 # jitter
|
|
476
|
+
)
|
|
419
477
|
)
|
|
420
478
|
|
|
421
479
|
def request(
|
|
@@ -665,6 +723,7 @@ class Endpoint(object):
|
|
|
665
723
|
self.params_map["all"].extend(
|
|
666
724
|
[
|
|
667
725
|
"async_req",
|
|
726
|
+
"async_threadpool_executor",
|
|
668
727
|
"_host_index",
|
|
669
728
|
"_preload_content",
|
|
670
729
|
"_request_timeout",
|
|
@@ -679,6 +738,7 @@ class Endpoint(object):
|
|
|
679
738
|
self.openapi_types = root_map["openapi_types"]
|
|
680
739
|
extra_types = {
|
|
681
740
|
"async_req": (bool,),
|
|
741
|
+
"async_threadpool_executor": (bool, ),
|
|
682
742
|
"_host_index": (none_type, int),
|
|
683
743
|
"_preload_content": (bool,),
|
|
684
744
|
"_request_timeout": (none_type, float, (float,), [float], int, (int,), [int]),
|
|
@@ -828,6 +888,7 @@ class Endpoint(object):
|
|
|
828
888
|
response_type=self.settings["response_type"],
|
|
829
889
|
auth_settings=self.settings["auth"],
|
|
830
890
|
async_req=kwargs["async_req"],
|
|
891
|
+
async_threadpool_executor=kwargs.get("async_threadpool_executor", None),
|
|
831
892
|
_check_type=kwargs["_check_return_type"],
|
|
832
893
|
_return_http_data_only=kwargs["_return_http_data_only"],
|
|
833
894
|
_preload_content=kwargs["_preload_content"],
|
|
@@ -469,3 +469,23 @@ class Configuration(object):
|
|
|
469
469
|
"""Fix base path."""
|
|
470
470
|
self._base_path = value
|
|
471
471
|
self.server_index = None
|
|
472
|
+
|
|
473
|
+
def __repr__(self):
|
|
474
|
+
attrs = [
|
|
475
|
+
f"host={self.host}",
|
|
476
|
+
f"api_key=***",
|
|
477
|
+
f"api_key_prefix={self.api_key_prefix}",
|
|
478
|
+
f"access_token={self.access_token}",
|
|
479
|
+
f"connection_pool_maxsize={self.connection_pool_maxsize}",
|
|
480
|
+
f"username={self.username}",
|
|
481
|
+
f"password={self.password}",
|
|
482
|
+
f"discard_unknown_keys={self.discard_unknown_keys}",
|
|
483
|
+
f"disabled_client_side_validations={self.disabled_client_side_validations}",
|
|
484
|
+
f"server_index={self.server_index}",
|
|
485
|
+
f"server_variables={self.server_variables}",
|
|
486
|
+
f"server_operation_index={self.server_operation_index}",
|
|
487
|
+
f"server_operation_variables={self.server_operation_variables}",
|
|
488
|
+
f"ssl_ca_cert={self.ssl_ca_cert}",
|
|
489
|
+
|
|
490
|
+
]
|
|
491
|
+
return f"Configuration({', '.join(attrs)})"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from tqdm.autonotebook import tqdm
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
import json
|
|
4
5
|
from typing import Union, List, Optional, Dict, Any
|
|
5
6
|
|
|
6
7
|
from pinecone.config import ConfigBuilder
|
|
@@ -33,6 +34,10 @@ from ..utils import (
|
|
|
33
34
|
)
|
|
34
35
|
from .features.bulk_import import ImportFeatureMixin
|
|
35
36
|
from .vector_factory import VectorFactory
|
|
37
|
+
from .query_results_aggregator import QueryResultsAggregator, QueryNamespacesResults
|
|
38
|
+
|
|
39
|
+
from multiprocessing.pool import ApplyResult
|
|
40
|
+
from concurrent.futures import as_completed
|
|
36
41
|
|
|
37
42
|
from pinecone_plugin_interface import load_and_install as install_plugins
|
|
38
43
|
|
|
@@ -65,6 +70,7 @@ _OPENAPI_ENDPOINT_PARAMS = (
|
|
|
65
70
|
"_check_return_type",
|
|
66
71
|
"_host_index",
|
|
67
72
|
"async_req",
|
|
73
|
+
"async_threadpool_executor",
|
|
68
74
|
)
|
|
69
75
|
|
|
70
76
|
|
|
@@ -103,6 +109,9 @@ class Index(ImportFeatureMixin):
|
|
|
103
109
|
self._openapi_config = ConfigBuilder.build_openapi_config(self.config, openapi_config)
|
|
104
110
|
self._pool_threads = pool_threads
|
|
105
111
|
|
|
112
|
+
if kwargs.get("connection_pool_maxsize", None):
|
|
113
|
+
self._openapi_config.connection_pool_maxsize = kwargs.get("connection_pool_maxsize")
|
|
114
|
+
|
|
106
115
|
self._vector_api = setup_openapi_client(
|
|
107
116
|
api_client_klass=ApiClient,
|
|
108
117
|
api_klass=DataPlaneApi,
|
|
@@ -387,7 +396,7 @@ class Index(ImportFeatureMixin):
|
|
|
387
396
|
Union[SparseValues, Dict[str, Union[List[float], List[int]]]]
|
|
388
397
|
] = None,
|
|
389
398
|
**kwargs,
|
|
390
|
-
) -> QueryResponse:
|
|
399
|
+
) -> Union[QueryResponse, ApplyResult]:
|
|
391
400
|
"""
|
|
392
401
|
The Query operation searches a namespace, using a query vector.
|
|
393
402
|
It retrieves the ids of the most similar items in a namespace, along with their similarity scores.
|
|
@@ -429,6 +438,39 @@ class Index(ImportFeatureMixin):
|
|
|
429
438
|
and namespace name.
|
|
430
439
|
"""
|
|
431
440
|
|
|
441
|
+
response = self._query(
|
|
442
|
+
*args,
|
|
443
|
+
top_k=top_k,
|
|
444
|
+
vector=vector,
|
|
445
|
+
id=id,
|
|
446
|
+
namespace=namespace,
|
|
447
|
+
filter=filter,
|
|
448
|
+
include_values=include_values,
|
|
449
|
+
include_metadata=include_metadata,
|
|
450
|
+
sparse_vector=sparse_vector,
|
|
451
|
+
**kwargs,
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
if kwargs.get("async_req", False) or kwargs.get("async_threadpool_executor", False):
|
|
455
|
+
return response
|
|
456
|
+
else:
|
|
457
|
+
return parse_query_response(response)
|
|
458
|
+
|
|
459
|
+
def _query(
|
|
460
|
+
self,
|
|
461
|
+
*args,
|
|
462
|
+
top_k: int,
|
|
463
|
+
vector: Optional[List[float]] = None,
|
|
464
|
+
id: Optional[str] = None,
|
|
465
|
+
namespace: Optional[str] = None,
|
|
466
|
+
filter: Optional[Dict[str, Union[str, float, int, bool, List, dict]]] = None,
|
|
467
|
+
include_values: Optional[bool] = None,
|
|
468
|
+
include_metadata: Optional[bool] = None,
|
|
469
|
+
sparse_vector: Optional[
|
|
470
|
+
Union[SparseValues, Dict[str, Union[List[float], List[int]]]]
|
|
471
|
+
] = None,
|
|
472
|
+
**kwargs,
|
|
473
|
+
) -> QueryResponse:
|
|
432
474
|
if len(args) > 0:
|
|
433
475
|
raise ValueError(
|
|
434
476
|
"The argument order for `query()` has changed; please use keyword arguments instead of positional arguments. Example: index.query(vector=[0.1, 0.2, 0.3], top_k=10, namespace='my_namespace')"
|
|
@@ -453,6 +495,7 @@ class Index(ImportFeatureMixin):
|
|
|
453
495
|
("sparse_vector", sparse_vector),
|
|
454
496
|
]
|
|
455
497
|
)
|
|
498
|
+
|
|
456
499
|
response = self._vector_api.query(
|
|
457
500
|
QueryRequest(
|
|
458
501
|
**args_dict,
|
|
@@ -461,7 +504,96 @@ class Index(ImportFeatureMixin):
|
|
|
461
504
|
),
|
|
462
505
|
**{k: v for k, v in kwargs.items() if k in _OPENAPI_ENDPOINT_PARAMS},
|
|
463
506
|
)
|
|
464
|
-
return
|
|
507
|
+
return response
|
|
508
|
+
|
|
509
|
+
@validate_and_convert_errors
|
|
510
|
+
def query_namespaces(
|
|
511
|
+
self,
|
|
512
|
+
vector: List[float],
|
|
513
|
+
namespaces: List[str],
|
|
514
|
+
top_k: Optional[int] = None,
|
|
515
|
+
filter: Optional[Dict[str, Union[str, float, int, bool, List, dict]]] = None,
|
|
516
|
+
include_values: Optional[bool] = None,
|
|
517
|
+
include_metadata: Optional[bool] = None,
|
|
518
|
+
sparse_vector: Optional[
|
|
519
|
+
Union[SparseValues, Dict[str, Union[List[float], List[int]]]]
|
|
520
|
+
] = None,
|
|
521
|
+
**kwargs,
|
|
522
|
+
) -> QueryNamespacesResults:
|
|
523
|
+
"""The query_namespaces() method is used to make a query to multiple namespaces in parallel and combine the results into one result set.
|
|
524
|
+
|
|
525
|
+
Since several asynchronous calls are made on your behalf when calling this method, you will need to tune the pool_threads and connection_pool_maxsize parameter of the Index constructor to suite your workload.
|
|
526
|
+
|
|
527
|
+
Examples:
|
|
528
|
+
|
|
529
|
+
```python
|
|
530
|
+
from pinecone import Pinecone
|
|
531
|
+
|
|
532
|
+
pc = Pinecone(api_key="your-api-key")
|
|
533
|
+
index = pc.Index(
|
|
534
|
+
host="index-name",
|
|
535
|
+
pool_threads=32,
|
|
536
|
+
connection_pool_maxsize=32
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
query_vec = [0.1, 0.2, 0.3] # An embedding that matches the index dimension
|
|
540
|
+
combined_results = index.query_namespaces(
|
|
541
|
+
vector=query_vec,
|
|
542
|
+
namespaces=['ns1', 'ns2', 'ns3', 'ns4'],
|
|
543
|
+
top_k=10,
|
|
544
|
+
filter={'genre': {"$eq": "drama"}},
|
|
545
|
+
include_values=True,
|
|
546
|
+
include_metadata=True
|
|
547
|
+
)
|
|
548
|
+
for vec in combined_results.matches:
|
|
549
|
+
print(vec.id, vec.score)
|
|
550
|
+
print(combined_results.usage)
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
vector (List[float]): The query vector, must be the same length as the dimension of the index being queried.
|
|
555
|
+
namespaces (List[str]): The list of namespaces to query.
|
|
556
|
+
top_k (Optional[int], optional): The number of results you would like to request from each namespace. Defaults to 10.
|
|
557
|
+
filter (Optional[Dict[str, Union[str, float, int, bool, List, dict]]], optional): Pass an optional filter to filter results based on metadata. Defaults to None.
|
|
558
|
+
include_values (Optional[bool], optional): Boolean field indicating whether vector values should be included with results. Defaults to None.
|
|
559
|
+
include_metadata (Optional[bool], optional): Boolean field indicating whether vector metadata should be included with results. Defaults to None.
|
|
560
|
+
sparse_vector (Optional[ Union[SparseValues, Dict[str, Union[List[float], List[int]]]] ], optional): If you are working with a dotproduct index, you can pass a sparse vector as part of your hybrid search. Defaults to None.
|
|
561
|
+
|
|
562
|
+
Returns:
|
|
563
|
+
QueryNamespacesResults: A QueryNamespacesResults object containing the combined results from all namespaces, as well as the combined usage cost in read units.
|
|
564
|
+
"""
|
|
565
|
+
if namespaces is None or len(namespaces) == 0:
|
|
566
|
+
raise ValueError("At least one namespace must be specified")
|
|
567
|
+
if len(vector) == 0:
|
|
568
|
+
raise ValueError("Query vector must not be empty")
|
|
569
|
+
|
|
570
|
+
overall_topk = top_k if top_k is not None else 10
|
|
571
|
+
aggregator = QueryResultsAggregator(top_k=overall_topk)
|
|
572
|
+
|
|
573
|
+
target_namespaces = set(namespaces) # dedup namespaces
|
|
574
|
+
async_futures = [
|
|
575
|
+
self.query(
|
|
576
|
+
vector=vector,
|
|
577
|
+
namespace=ns,
|
|
578
|
+
top_k=overall_topk,
|
|
579
|
+
filter=filter,
|
|
580
|
+
include_values=include_values,
|
|
581
|
+
include_metadata=include_metadata,
|
|
582
|
+
sparse_vector=sparse_vector,
|
|
583
|
+
async_threadpool_executor=True,
|
|
584
|
+
_preload_content=False,
|
|
585
|
+
**kwargs,
|
|
586
|
+
)
|
|
587
|
+
for ns in target_namespaces
|
|
588
|
+
]
|
|
589
|
+
|
|
590
|
+
for result in as_completed(async_futures):
|
|
591
|
+
raw_result = result.result()
|
|
592
|
+
response = json.loads(raw_result.data.decode("utf-8"))
|
|
593
|
+
aggregator.add_results(response)
|
|
594
|
+
|
|
595
|
+
final_results = aggregator.get_results()
|
|
596
|
+
return final_results
|
|
465
597
|
|
|
466
598
|
@validate_and_convert_errors
|
|
467
599
|
def update(
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
from typing import List, Tuple, Optional, Any, Dict
|
|
2
|
+
import json
|
|
3
|
+
import heapq
|
|
4
|
+
from pinecone.core.openapi.data.models import Usage
|
|
5
|
+
from pinecone.core.openapi.data.models import QueryResponse as OpenAPIQueryResponse
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, asdict
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class ScoredVectorWithNamespace:
|
|
12
|
+
namespace: str
|
|
13
|
+
score: float
|
|
14
|
+
id: str
|
|
15
|
+
values: List[float]
|
|
16
|
+
sparse_values: dict
|
|
17
|
+
metadata: dict
|
|
18
|
+
|
|
19
|
+
def __init__(self, aggregate_results_heap_tuple: Tuple[float, int, object, str]):
|
|
20
|
+
json_vector = aggregate_results_heap_tuple[2]
|
|
21
|
+
self.namespace = aggregate_results_heap_tuple[3]
|
|
22
|
+
self.id = json_vector.get("id") # type: ignore
|
|
23
|
+
self.score = json_vector.get("score") # type: ignore
|
|
24
|
+
self.values = json_vector.get("values") # type: ignore
|
|
25
|
+
self.sparse_values = json_vector.get("sparse_values", None) # type: ignore
|
|
26
|
+
self.metadata = json_vector.get("metadata", None) # type: ignore
|
|
27
|
+
|
|
28
|
+
def __getitem__(self, key):
|
|
29
|
+
if hasattr(self, key):
|
|
30
|
+
return getattr(self, key)
|
|
31
|
+
else:
|
|
32
|
+
raise KeyError(f"'{key}' not found in ScoredVectorWithNamespace")
|
|
33
|
+
|
|
34
|
+
def get(self, key, default=None):
|
|
35
|
+
return getattr(self, key, default)
|
|
36
|
+
|
|
37
|
+
def __repr__(self):
|
|
38
|
+
return json.dumps(self._truncate(asdict(self)), indent=4)
|
|
39
|
+
|
|
40
|
+
def __json__(self):
|
|
41
|
+
return self._truncate(asdict(self))
|
|
42
|
+
|
|
43
|
+
def _truncate(self, obj, max_items=2):
|
|
44
|
+
"""
|
|
45
|
+
Recursively traverse and truncate lists that exceed max_items length.
|
|
46
|
+
Only display the "... X more" message if at least 2 elements are hidden.
|
|
47
|
+
"""
|
|
48
|
+
if obj is None:
|
|
49
|
+
return None # Skip None values
|
|
50
|
+
elif isinstance(obj, list):
|
|
51
|
+
filtered_list = [self._truncate(i, max_items) for i in obj if i is not None]
|
|
52
|
+
if len(filtered_list) > max_items:
|
|
53
|
+
# Show the truncation message only if more than 1 item is hidden
|
|
54
|
+
remaining_items = len(filtered_list) - max_items
|
|
55
|
+
if remaining_items > 1:
|
|
56
|
+
return filtered_list[:max_items] + [f"... {remaining_items} more"]
|
|
57
|
+
else:
|
|
58
|
+
# If only 1 item remains, show it
|
|
59
|
+
return filtered_list
|
|
60
|
+
return filtered_list
|
|
61
|
+
elif isinstance(obj, dict):
|
|
62
|
+
# Recursively process dictionaries, omitting None values
|
|
63
|
+
return {k: self._truncate(v, max_items) for k, v in obj.items() if v is not None}
|
|
64
|
+
return obj
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class QueryNamespacesResults:
|
|
69
|
+
usage: Usage
|
|
70
|
+
matches: List[ScoredVectorWithNamespace]
|
|
71
|
+
|
|
72
|
+
def __getitem__(self, key):
|
|
73
|
+
if hasattr(self, key):
|
|
74
|
+
return getattr(self, key)
|
|
75
|
+
else:
|
|
76
|
+
raise KeyError(f"'{key}' not found in QueryNamespacesResults")
|
|
77
|
+
|
|
78
|
+
def get(self, key, default=None):
|
|
79
|
+
return getattr(self, key, default)
|
|
80
|
+
|
|
81
|
+
def __repr__(self):
|
|
82
|
+
return json.dumps(
|
|
83
|
+
{
|
|
84
|
+
"usage": self.usage.to_dict(),
|
|
85
|
+
"matches": [match.__json__() for match in self.matches],
|
|
86
|
+
},
|
|
87
|
+
indent=4,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class QueryResultsAggregregatorNotEnoughResultsError(Exception):
|
|
92
|
+
def __init__(self):
|
|
93
|
+
super().__init__(
|
|
94
|
+
"Cannot interpret results without at least two matches. In order to aggregate results from multiple queries, top_k must be greater than 1 in order to correctly infer the similarity metric from scores."
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class QueryResultsAggregatorInvalidTopKError(Exception):
|
|
99
|
+
def __init__(self, top_k: int):
|
|
100
|
+
super().__init__(
|
|
101
|
+
f"Invalid top_k value {top_k}. To aggregate results from multiple queries the top_k must be at least 2."
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class QueryResultsAggregator:
|
|
106
|
+
def __init__(self, top_k: int):
|
|
107
|
+
if top_k < 2:
|
|
108
|
+
raise QueryResultsAggregatorInvalidTopKError(top_k)
|
|
109
|
+
self.top_k = top_k
|
|
110
|
+
self.usage_read_units = 0
|
|
111
|
+
self.heap: List[Tuple[float, int, object, str]] = []
|
|
112
|
+
self.insertion_counter = 0
|
|
113
|
+
self.is_dotproduct = None
|
|
114
|
+
self.read = False
|
|
115
|
+
self.final_results: Optional[QueryNamespacesResults] = None
|
|
116
|
+
|
|
117
|
+
def _is_dotproduct_index(self, matches):
|
|
118
|
+
# The interpretation of the score depends on the similar metric used.
|
|
119
|
+
# Unlike other index types, in indexes configured for dotproduct,
|
|
120
|
+
# a higher score is better. We have to infer this is the case by inspecting
|
|
121
|
+
# the order of the scores in the results.
|
|
122
|
+
for i in range(1, len(matches)):
|
|
123
|
+
if matches[i].get("score") > matches[i - 1].get("score"): # Found an increase
|
|
124
|
+
return False
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
def _dotproduct_heap_item(self, match, ns):
|
|
128
|
+
return (match.get("score"), -self.insertion_counter, match, ns)
|
|
129
|
+
|
|
130
|
+
def _non_dotproduct_heap_item(self, match, ns):
|
|
131
|
+
return (-match.get("score"), -self.insertion_counter, match, ns)
|
|
132
|
+
|
|
133
|
+
def _process_matches(self, matches, ns, heap_item_fn):
|
|
134
|
+
for match in matches:
|
|
135
|
+
self.insertion_counter += 1
|
|
136
|
+
if len(self.heap) < self.top_k:
|
|
137
|
+
heapq.heappush(self.heap, heap_item_fn(match, ns))
|
|
138
|
+
else:
|
|
139
|
+
# Assume we have dotproduct scores sorted in descending order
|
|
140
|
+
if self.is_dotproduct and match["score"] < self.heap[0][0]:
|
|
141
|
+
# No further matches can improve the top-K heap
|
|
142
|
+
break
|
|
143
|
+
elif not self.is_dotproduct and match["score"] > -self.heap[0][0]:
|
|
144
|
+
# No further matches can improve the top-K heap
|
|
145
|
+
break
|
|
146
|
+
heapq.heappushpop(self.heap, heap_item_fn(match, ns))
|
|
147
|
+
|
|
148
|
+
def add_results(self, results: Dict[str, Any]):
|
|
149
|
+
if self.read:
|
|
150
|
+
# This is mainly just to sanity check in test cases which get quite confusing
|
|
151
|
+
# if you read results twice due to the heap being emptied when constructing
|
|
152
|
+
# the ordered results.
|
|
153
|
+
raise ValueError("Results have already been read. Cannot add more results.")
|
|
154
|
+
|
|
155
|
+
matches = results.get("matches", [])
|
|
156
|
+
ns: str = results.get("namespace", "")
|
|
157
|
+
if isinstance(results, OpenAPIQueryResponse):
|
|
158
|
+
self.usage_read_units += results.usage.read_units
|
|
159
|
+
else:
|
|
160
|
+
self.usage_read_units += results.get("usage", {}).get("readUnits", 0)
|
|
161
|
+
|
|
162
|
+
if len(matches) == 0:
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
if self.is_dotproduct is None:
|
|
166
|
+
if len(matches) == 1:
|
|
167
|
+
# This condition should match the second time we add results containing
|
|
168
|
+
# only one match. We need at least two matches in a single response in order
|
|
169
|
+
# to infer the similarity metric
|
|
170
|
+
raise QueryResultsAggregregatorNotEnoughResultsError()
|
|
171
|
+
self.is_dotproduct = self._is_dotproduct_index(matches)
|
|
172
|
+
|
|
173
|
+
if self.is_dotproduct:
|
|
174
|
+
self._process_matches(matches, ns, self._dotproduct_heap_item)
|
|
175
|
+
else:
|
|
176
|
+
self._process_matches(matches, ns, self._non_dotproduct_heap_item)
|
|
177
|
+
|
|
178
|
+
def get_results(self) -> QueryNamespacesResults:
|
|
179
|
+
if self.read:
|
|
180
|
+
if self.final_results is not None:
|
|
181
|
+
return self.final_results
|
|
182
|
+
else:
|
|
183
|
+
# I don't think this branch can ever actually be reached, but the type checker disagrees
|
|
184
|
+
raise ValueError("Results have already been read. Cannot get results again.")
|
|
185
|
+
self.read = True
|
|
186
|
+
|
|
187
|
+
self.final_results = QueryNamespacesResults(
|
|
188
|
+
usage=Usage(read_units=self.usage_read_units),
|
|
189
|
+
matches=[
|
|
190
|
+
ScoredVectorWithNamespace(heapq.heappop(self.heap)) for _ in range(len(self.heap))
|
|
191
|
+
][::-1],
|
|
192
|
+
)
|
|
193
|
+
return self.final_results
|
|
@@ -47,20 +47,24 @@ index.query(vector=[...], top_k=10)
|
|
|
47
47
|
from .index_grpc import GRPCIndex
|
|
48
48
|
from .pinecone import PineconeGRPC
|
|
49
49
|
from .config import GRPCClientConfig
|
|
50
|
+
from .future import PineconeGrpcFuture
|
|
50
51
|
|
|
51
52
|
from pinecone.core.grpc.protos.vector_service_pb2 import (
|
|
52
53
|
Vector as GRPCVector,
|
|
53
54
|
SparseValues as GRPCSparseValues,
|
|
54
55
|
Vector,
|
|
55
56
|
SparseValues,
|
|
57
|
+
DeleteResponse as GRPCDeleteResponse,
|
|
56
58
|
)
|
|
57
59
|
|
|
58
60
|
__all__ = [
|
|
59
61
|
"GRPCIndex",
|
|
60
62
|
"PineconeGRPC",
|
|
63
|
+
"GRPCDeleteResponse",
|
|
61
64
|
"GRPCClientConfig",
|
|
62
65
|
"GRPCVector",
|
|
63
66
|
"GRPCSparseValues",
|
|
64
67
|
"Vector",
|
|
65
68
|
"SparseValues",
|
|
69
|
+
"PineconeGrpcFuture",
|
|
66
70
|
]
|
|
@@ -10,6 +10,7 @@ from .channel_factory import GrpcChannelFactory
|
|
|
10
10
|
from pinecone import Config
|
|
11
11
|
from .config import GRPCClientConfig
|
|
12
12
|
from .grpc_runner import GrpcRunner
|
|
13
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
13
14
|
|
|
14
15
|
from pinecone_plugin_interface import load_and_install as install_plugins
|
|
15
16
|
|
|
@@ -29,10 +30,12 @@ class GRPCIndexBase(ABC):
|
|
|
29
30
|
config: Config,
|
|
30
31
|
channel: Optional[Channel] = None,
|
|
31
32
|
grpc_config: Optional[GRPCClientConfig] = None,
|
|
33
|
+
pool_threads: Optional[int] = None,
|
|
32
34
|
_endpoint_override: Optional[str] = None,
|
|
33
35
|
):
|
|
34
36
|
self.config = config
|
|
35
37
|
self.grpc_client_config = grpc_config or GRPCClientConfig()
|
|
38
|
+
self.pool_threads = pool_threads
|
|
36
39
|
|
|
37
40
|
self._endpoint_override = _endpoint_override
|
|
38
41
|
|
|
@@ -58,6 +61,13 @@ class GRPCIndexBase(ABC):
|
|
|
58
61
|
except Exception as e:
|
|
59
62
|
_logger.error(f"Error loading plugins in GRPCIndex: {e}")
|
|
60
63
|
|
|
64
|
+
@property
|
|
65
|
+
def threadpool_executor(self):
|
|
66
|
+
if self._pool is None:
|
|
67
|
+
pt = self.pool_threads or 10
|
|
68
|
+
self._pool = ThreadPoolExecutor(max_workers=pt)
|
|
69
|
+
return self._pool
|
|
70
|
+
|
|
61
71
|
@property
|
|
62
72
|
@abstractmethod
|
|
63
73
|
def stub_class(self):
|