be52af70
tangwang
first commit
|
1
2
3
4
|
"""
Search API routes.
"""
|
16c42787
tangwang
feat: implement r...
|
5
|
from fastapi import APIRouter, HTTPException, Query, Request
|
be52af70
tangwang
first commit
|
6
|
from typing import Optional
|
16c42787
tangwang
feat: implement r...
|
7
|
import uuid
|
be52af70
tangwang
first commit
|
8
9
10
11
12
13
14
15
|
from ..models import (
SearchRequest,
ImageSearchRequest,
SearchResponse,
DocumentResponse,
ErrorResponse
)
|
16c42787
tangwang
feat: implement r...
|
16
|
from context.request_context import create_request_context, set_current_request_context, clear_current_request_context
|
be52af70
tangwang
first commit
|
17
18
19
20
|
router = APIRouter(prefix="/search", tags=["search"])
|
16c42787
tangwang
feat: implement r...
|
21
22
23
24
25
26
27
28
29
30
31
|
def extract_request_info(request: Request) -> tuple[str, str]:
"""Extract request ID and user ID from HTTP request"""
# Try to get request ID from headers
reqid = request.headers.get('X-Request-ID') or str(uuid.uuid4())[:8]
# Try to get user ID from headers or default to anonymous
uid = request.headers.get('X-User-ID') or request.headers.get('User-ID') or 'anonymous'
return reqid, uid
|
be52af70
tangwang
first commit
|
32
|
@router.post("/", response_model=SearchResponse)
|
16c42787
tangwang
feat: implement r...
|
33
|
async def search(request: SearchRequest, http_request: Request):
|
be52af70
tangwang
first commit
|
34
35
36
37
38
39
40
41
42
43
|
"""
Execute text search query.
Supports:
- Multi-language query processing
- Boolean operators (AND, OR, RANK, ANDNOT)
- Semantic search with embeddings
- Custom ranking functions
- Filters and aggregations
"""
|
16c42787
tangwang
feat: implement r...
|
44
45
46
47
48
49
50
|
reqid, uid = extract_request_info(http_request)
# Create request context
context = create_request_context(reqid=reqid, uid=uid)
# Set context in thread-local storage
set_current_request_context(context)
|
be52af70
tangwang
first commit
|
51
52
|
try:
|
16c42787
tangwang
feat: implement r...
|
53
54
55
56
57
58
59
|
# Log request start
context.logger.info(
f"收到搜索请求 | IP: {http_request.client.host if http_request.client else 'unknown'} | "
f"用户代理: {http_request.headers.get('User-Agent', 'unknown')[:100]}",
extra={'reqid': context.reqid, 'uid': context.uid}
)
|
be52af70
tangwang
first commit
|
60
|
# Get searcher from app state
|
bb3c5ef8
tangwang
灌入数据流程跑通
|
61
|
from api.app import get_searcher
|
be52af70
tangwang
first commit
|
62
63
|
searcher = get_searcher()
|
16c42787
tangwang
feat: implement r...
|
64
|
# Execute search with context (using backend defaults from config)
|
be52af70
tangwang
first commit
|
65
66
67
68
69
|
result = searcher.search(
query=request.query,
size=request.size,
from_=request.from_,
filters=request.filters,
|
16c42787
tangwang
feat: implement r...
|
70
|
min_score=request.min_score,
|
c86c8237
tangwang
支持聚合。过滤项补充了逻辑,但是有问题
|
71
72
73
|
context=context,
aggregations=request.aggregations,
sort_by=request.sort_by,
|
1f071951
tangwang
补充调试信息,记录包括各个阶段的 ...
|
74
75
|
sort_order=request.sort_order,
debug=request.debug
|
be52af70
tangwang
first commit
|
76
77
|
)
|
16c42787
tangwang
feat: implement r...
|
78
79
80
|
# Include performance summary in response
performance_summary = context.get_summary() if context else None
|
be52af70
tangwang
first commit
|
81
82
83
84
85
86
87
|
# Convert to response model
return SearchResponse(
hits=result.hits,
total=result.total,
max_score=result.max_score,
took_ms=result.took_ms,
aggregations=result.aggregations,
|
16c42787
tangwang
feat: implement r...
|
88
|
query_info=result.query_info,
|
1f071951
tangwang
补充调试信息,记录包括各个阶段的 ...
|
89
90
|
performance_info=performance_summary,
debug_info=result.debug_info
|
be52af70
tangwang
first commit
|
91
92
93
|
)
except Exception as e:
|
16c42787
tangwang
feat: implement r...
|
94
95
96
97
98
99
100
|
# Log error in context
if context:
context.set_error(e)
context.logger.error(
f"搜索请求失败 | 错误: {str(e)}",
extra={'reqid': context.reqid, 'uid': context.uid}
)
|
be52af70
tangwang
first commit
|
101
|
raise HTTPException(status_code=500, detail=str(e))
|
16c42787
tangwang
feat: implement r...
|
102
103
104
|
finally:
# Clear thread-local context
clear_current_request_context()
|
be52af70
tangwang
first commit
|
105
106
107
|
@router.post("/image", response_model=SearchResponse)
|
16c42787
tangwang
feat: implement r...
|
108
|
async def search_by_image(request: ImageSearchRequest, http_request: Request):
|
be52af70
tangwang
first commit
|
109
110
111
112
113
|
"""
Search by image similarity.
Uses image embeddings to find visually similar products.
"""
|
16c42787
tangwang
feat: implement r...
|
114
115
116
117
118
119
120
121
|
reqid, uid = extract_request_info(http_request)
# Create request context
context = create_request_context(reqid=reqid, uid=uid)
# Set context in thread-local storage
set_current_request_context(context)
|
be52af70
tangwang
first commit
|
122
|
try:
|
16c42787
tangwang
feat: implement r...
|
123
124
125
126
127
128
129
|
# Log request start
context.logger.info(
f"收到图片搜索请求 | 图片URL: {request.image_url} | "
f"IP: {http_request.client.host if http_request.client else 'unknown'}",
extra={'reqid': context.reqid, 'uid': context.uid}
)
|
bb3c5ef8
tangwang
灌入数据流程跑通
|
130
|
from api.app import get_searcher
|
be52af70
tangwang
first commit
|
131
132
133
134
135
136
137
138
139
|
searcher = get_searcher()
# Execute image search
result = searcher.search_by_image(
image_url=request.image_url,
size=request.size,
filters=request.filters
)
|
16c42787
tangwang
feat: implement r...
|
140
141
142
|
# Include performance summary in response
performance_summary = context.get_summary() if context else None
|
be52af70
tangwang
first commit
|
143
144
145
146
147
148
|
return SearchResponse(
hits=result.hits,
total=result.total,
max_score=result.max_score,
took_ms=result.took_ms,
aggregations=result.aggregations,
|
16c42787
tangwang
feat: implement r...
|
149
150
|
query_info=result.query_info,
performance_info=performance_summary
|
be52af70
tangwang
first commit
|
151
152
153
|
)
except ValueError as e:
|
16c42787
tangwang
feat: implement r...
|
154
155
156
157
158
159
|
if context:
context.set_error(e)
context.logger.error(
f"图片搜索请求参数错误 | 错误: {str(e)}",
extra={'reqid': context.reqid, 'uid': context.uid}
)
|
be52af70
tangwang
first commit
|
160
161
|
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
|
16c42787
tangwang
feat: implement r...
|
162
163
164
165
166
167
|
if context:
context.set_error(e)
context.logger.error(
f"图片搜索请求失败 | 错误: {str(e)}",
extra={'reqid': context.reqid, 'uid': context.uid}
)
|
be52af70
tangwang
first commit
|
168
|
raise HTTPException(status_code=500, detail=str(e))
|
16c42787
tangwang
feat: implement r...
|
169
170
171
|
finally:
# Clear thread-local context
clear_current_request_context()
|
be52af70
tangwang
first commit
|
172
173
174
175
176
177
178
179
|
@router.get("/{doc_id}", response_model=DocumentResponse)
async def get_document(doc_id: str):
"""
Get a single document by ID.
"""
try:
|
bb3c5ef8
tangwang
灌入数据流程跑通
|
180
|
from api.app import get_searcher
|
be52af70
tangwang
first commit
|
181
182
183
184
185
186
187
188
189
190
191
192
193
|
searcher = get_searcher()
doc = searcher.get_document(doc_id)
if doc is None:
raise HTTPException(status_code=404, detail=f"Document {doc_id} not found")
return DocumentResponse(id=doc_id, source=doc)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
|