Source code for document_stores.vector_store_factory

"""
向量存储工厂模式实现

提供统一的向量存储创建接口,支持自动后端选择、配置验证、
错误回退和存储迁移功能。
"""

import importlib
import logging
import os
from typing import Any, Dict, List, Optional, Type, TypedDict

from .implementations.base_vector_store import BaseVectorStore, VectorStoreConfigError, VectorStoreError


[docs] class BackendInfo(TypedDict): class_name: str module: str dependencies: List[str] description: str
[docs] class VectorStoreFactory: """ 向量存储工厂类。 负责根据配置创建合适的向量存储后端,提供自动回退、 配置验证和存储迁移功能。 """ # 支持的存储后端映射 _BACKENDS: Dict[str, BackendInfo] = { "memory": { "class_name": "InMemoryVectorStore", "module": "document_stores.implementations.memory_vector_store", "dependencies": [], "description": "内存存储,适用于开发和小规模场景", }, "faiss": { "class_name": "FAISSVectorStore", "module": "document_stores.implementations.faiss_vector_store", "dependencies": ["faiss-cpu"], "description": "FAISS高性能向量检索,支持持久化", }, "milvus": { "class_name": "MilvusStore", "module": "document_stores.implementations.milvus_store", "dependencies": ["pymilvus"], "description": "Milvus分布式向量数据库,适用于生产环境", }, } # 回退策略:优先级从高到低 _FALLBACK_ORDER = ["faiss", "memory"]
[docs] def __init__(self) -> None: """初始化工厂类""" self.logger = logging.getLogger("VectorStoreFactory") self._backend_cache: Dict[str, Type[BaseVectorStore]] = {} # 缓存已加载的后端类
[docs] @classmethod def create( cls, config: Dict[str, Any], auto_fallback: bool = True, validate_config: bool = True ) -> BaseVectorStore: """ 创建向量存储实例。 Args: config: 存储配置字典 auto_fallback: 是否启用自动回退机制 validate_config: 是否验证配置 Returns: 向量存储实例 Raises: VectorStoreError: 创建失败时抛出 """ factory = cls() return factory._create_store(config, auto_fallback, validate_config)
def _create_store( self, config: Dict[str, Any], auto_fallback: bool = True, validate_config: bool = True ) -> BaseVectorStore: """ 内部创建存储实例的方法。 Args: config: 存储配置 auto_fallback: 自动回退 validate_config: 验证配置 Returns: 向量存储实例 """ # 获取存储类型 store_type = config.get("type", "memory").lower() # 配置验证 if validate_config: self._validate_config(config, store_type) # 尝试创建主要存储后端 try: store = self._create_backend(store_type, config) if store.initialize(): self.logger.info(f"成功创建 {store_type} 向量存储") return store else: raise VectorStoreError(f"{store_type} 初始化失败") except Exception as e: self.logger.warning(f"创建 {store_type} 存储失败: {str(e)}") if not auto_fallback: raise VectorStoreError(f"创建 {store_type} 存储失败: {str(e)}") # 自动回退机制 if auto_fallback: return self._create_fallback_store(config, exclude=[store_type]) raise VectorStoreError("无法创建任何可用的向量存储后端") def _create_backend(self, store_type: str, config: Dict[str, Any]) -> BaseVectorStore: """ 创建指定类型的存储后端。 Args: store_type: 存储类型 config: 配置字典 Returns: 存储实例 """ if store_type not in self._BACKENDS: raise VectorStoreConfigError(f"不支持的存储类型: {store_type}") backend_info = self._BACKENDS[store_type] # 检查依赖 self._check_dependencies(store_type, backend_info["dependencies"]) # 获取存储类 store_class = self._get_backend_class(store_type, backend_info) # 创建实例 return store_class(config) def _get_backend_class(self, store_type: str, backend_info: BackendInfo) -> Type[BaseVectorStore]: """ 获取存储后端类。 Args: store_type: 存储类型 backend_info: 后端信息 Returns: 存储类 """ if self._BACKENDS.get(store_type) != backend_info: raise VectorStoreConfigError(f"不支持的存储类型或模块: {store_type}") # 检查缓存 if store_type in self._backend_cache: return self._backend_cache[store_type] try: # Only the three maintained backend modules may be loaded. if store_type == "memory": module = importlib.import_module("document_stores.implementations.memory_vector_store") elif store_type == "faiss": module = importlib.import_module("document_stores.implementations.faiss_vector_store") elif store_type == "milvus": module = importlib.import_module("document_stores.implementations.milvus_store") else: raise VectorStoreConfigError(f"不支持的存储类型: {store_type}") store_class = getattr(module, backend_info["class_name"]) # 验证类是否继承自BaseVectorStore if not isinstance(store_class, type) or not issubclass(store_class, BaseVectorStore): raise VectorStoreError(f"{backend_info['class_name']} 必须继承自 BaseVectorStore") # 缓存类引用 self._backend_cache[store_type] = store_class return store_class except ImportError as e: raise VectorStoreError(f"无法导入存储模块 {backend_info['module']}: {str(e)}") except AttributeError as e: raise VectorStoreError(f"模块中不存在类 {backend_info['class_name']}: {str(e)}") def _check_dependencies(self, store_type: str, dependencies: List[str]) -> None: """ 检查存储后端的依赖是否满足。 Args: store_type: 存储类型 dependencies: 依赖包列表 """ missing_deps = [] for dep in dependencies: try: # 处理包名映射 if dep == "faiss-cpu": importlib.import_module("faiss") elif dep == "pymilvus": importlib.import_module("pymilvus") else: raise VectorStoreConfigError(f"不支持的依赖: {dep}") except ImportError: missing_deps.append(dep) if missing_deps: deps_str = ", ".join(missing_deps) raise VectorStoreError( f"{store_type} 存储需要以下依赖: {deps_str}\n" f"请运行: pip install {' '.join(missing_deps)}" ) def _create_fallback_store(self, config: Dict[str, Any], exclude: Optional[List[str]] = None) -> BaseVectorStore: """ 创建回退存储后端。 Args: config: 配置 exclude: 排除的存储类型列表 Returns: 存储实例 """ exclude = exclude or [] for fallback_type in self._FALLBACK_ORDER: if fallback_type in exclude: continue try: self.logger.info(f"尝试回退到 {fallback_type} 存储") # 创建回退配置 fallback_config = config.copy() fallback_config["type"] = fallback_type store = self._create_backend(fallback_type, fallback_config) if store.initialize(): self.logger.warning(f"已回退到 {fallback_type} 存储") return store except Exception as e: self.logger.warning(f"回退到 {fallback_type} 存储失败: {str(e)}") continue raise VectorStoreError("所有存储后端都不可用") def _validate_config(self, config: Dict[str, Any], store_type: str) -> None: """ 验证存储配置。 Args: config: 配置字典 store_type: 存储类型 """ # 基础配置验证 required_fields = ["type"] for field in required_fields: if field not in config: raise VectorStoreConfigError(f"缺少必需的配置字段: {field}") # 向量维度验证 vector_dim = config.get("vector_dimension", 384) if not isinstance(vector_dim, int) or vector_dim <= 0: raise VectorStoreConfigError("vector_dimension 必须是正整数") # 相似度函数验证 similarity = config.get("similarity", "dot_product") valid_similarities = ["dot_product", "cosine", "euclidean"] if similarity not in valid_similarities: raise VectorStoreConfigError(f"similarity 必须是以下之一: {', '.join(valid_similarities)}") # 存储类型特定验证 if store_type == "faiss": self._validate_faiss_config(config.get("faiss", {})) elif store_type == "milvus": self._validate_milvus_config(config.get("milvus", {})) def _validate_faiss_config(self, faiss_config: Dict[str, Any]) -> None: """ 验证FAISS配置。 Args: faiss_config: FAISS配置字典 """ # 存储路径 storage_path = faiss_config.get("storage_path", "./data/faiss") try: os.makedirs(storage_path, exist_ok=True) except Exception as e: raise VectorStoreConfigError(f"无法创建FAISS存储路径 {storage_path}: {str(e)}") # 索引类型验证 index_type = faiss_config.get("index_type", "Flat") valid_index_types = ["Flat", "IVF", "HNSW"] if not any(index_type.startswith(t) for t in valid_index_types): raise VectorStoreConfigError(f"不支持的FAISS索引类型: {index_type}") def _validate_milvus_config(self, milvus_config: Dict[str, Any]) -> None: """ 验证Milvus配置。 Args: milvus_config: Milvus配置字典 """ # 连接配置 port = milvus_config.get("port", 19530) if not isinstance(port, int) or port <= 0: raise VectorStoreConfigError("Milvus端口必须是正整数") # 集合名称 collection_name = milvus_config.get("collection_name", "documents") if not collection_name or not isinstance(collection_name, str): raise VectorStoreConfigError("Milvus collection_name 必须是非空字符串")
[docs] @classmethod def get_available_backends(cls) -> Dict[str, Dict[str, Any]]: """ 获取可用的存储后端信息。 Returns: 后端信息字典 """ factory = cls() available = {} for backend_type, backend_info in cls._BACKENDS.items(): try: factory._check_dependencies(backend_type, backend_info["dependencies"]) factory._get_backend_class(backend_type, backend_info) available[backend_type] = { "description": backend_info["description"], "dependencies": backend_info["dependencies"], "available": True, } except VectorStoreError: available[backend_type] = { "description": backend_info["description"], "dependencies": backend_info["dependencies"], "available": False, } return available
[docs] @classmethod def migrate_storage( cls, source_config: Dict[str, Any], target_config: Dict[str, Any], batch_size: int = 1000 ) -> bool: """ 存储迁移功能。 Args: source_config: 源存储配置 target_config: 目标存储配置 batch_size: 批量迁移大小 Returns: 迁移成功返回True """ logger = logging.getLogger("VectorStoreMigration") try: from .migration.vector_migration import VectorStoreMigrator return VectorStoreMigrator().migrate( source_config, target_config, batch_size=batch_size, verify_migration=True, backup_before_migration=False, ) except Exception as e: logger.error(f"存储迁移失败: {str(e)}") return False
# 便捷函数
[docs] def create_vector_store(config: Dict[str, Any], auto_fallback: bool = True) -> BaseVectorStore: """ 创建向量存储的便捷函数。 Args: config: 存储配置 auto_fallback: 启用自动回退 Returns: 向量存储实例 """ return VectorStoreFactory.create(config, auto_fallback)
[docs] def get_available_backends() -> Dict[str, Dict[str, Any]]: """ 获取可用存储后端的便捷函数。 Returns: 后端信息字典 """ return VectorStoreFactory.get_available_backends()
[docs] def recommend_backend(requirements: Optional[Dict[str, Any]] = None) -> str: """ 推荐存储后端的便捷函数。 Args: requirements: 需求字典 Returns: 推荐的存储类型 """ return VectorStoreFactory.get_recommended_backend(requirements)