""" 索引API路由。 提供全量和增量索引接口,供外部Java程序调用。 """ from fastapi import APIRouter, HTTPException from typing import List from pydantic import BaseModel import logging logger = logging.getLogger(__name__) router = APIRouter(prefix="/indexer", tags=["indexer"]) class BulkIndexRequest(BaseModel): tenant_id: str recreate_index: bool = False batch_size: int = 500 class BatchSpuRequest(BaseModel): tenant_id: str spu_ids: List[str] @router.post("/bulk") async def bulk_index(request: BulkIndexRequest): """全量索引接口""" try: from ..app import get_bulk_indexing_service service = get_bulk_indexing_service() if service is None: raise HTTPException(status_code=503, detail="Bulk indexing service is not initialized") return service.bulk_index( tenant_id=request.tenant_id, recreate_index=request.recreate_index, batch_size=request.batch_size ) except HTTPException: raise except Exception as e: logger.error(f"Error in bulk indexing for tenant_id={request.tenant_id}: {e}", exc_info=True) raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}") @router.post("/spus") async def get_spu_documents(request: BatchSpuRequest): """获取SPU文档接口(支持单个或批量)""" try: from ..app import get_incremental_service if not request.spu_ids: raise HTTPException(status_code=400, detail="spu_ids cannot be empty") if len(request.spu_ids) > 100: raise HTTPException(status_code=400, detail="Maximum 100 SPU IDs allowed per request") service = get_incremental_service() if service is None: raise HTTPException(status_code=503, detail="Incremental indexer service is not initialized") success_list, failed_list = [], [] for spu_id in request.spu_ids: try: doc = service.get_spu_document(tenant_id=request.tenant_id, spu_id=spu_id) (success_list if doc else failed_list).append({ "spu_id": spu_id, "document": doc } if doc else { "spu_id": spu_id, "error": "SPU not found or deleted" }) except Exception as e: failed_list.append({"spu_id": spu_id, "error": str(e)}) return { "success": success_list, "failed": failed_list, "total": len(request.spu_ids), "success_count": len(success_list), "failed_count": len(failed_list) } except HTTPException: raise except Exception as e: logger.error(f"Error getting SPU documents for tenant_id={request.tenant_id}: {e}", exc_info=True) raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}") @router.get("/health") async def indexer_health_check(): """检查索引服务健康状态""" try: from ..app import get_incremental_service from sqlalchemy import text service = get_incremental_service() if service is None: return {"status": "unavailable", "database": "unknown", "preloaded_data": {"category_mappings": 0}} try: with service.db_engine.connect() as conn: conn.execute(text("SELECT 1")) db_status = "connected" except Exception as e: db_status = f"disconnected: {str(e)}" return { "status": "available", "database": db_status, "preloaded_data": {"category_mappings": len(service.category_id_to_name)} } except Exception as e: logger.error(f"Error checking indexer health: {e}", exc_info=True) return {"status": "error", "message": str(e)}