Doanh Van Vu commited on
Commit
f879018
·
1 Parent(s): ff5d801

Implement fallback filtering in RecommendationService for mentor queries

Browse files

- Added logic to handle cases where no mentors are found with strict filters (rating/availability) by introducing a fallback mechanism that relaxes these constraints.
- Enhanced logging to provide detailed information about the filtering process and fallback attempts, improving traceability and debugging capabilities.
- Updated the filter construction to include logging for each filter applied based on mentee data.

Files changed (1) hide show
  1. services/recommendation_service.py +49 -5
services/recommendation_service.py CHANGED
@@ -105,8 +105,41 @@ class RecommendationService:
105
  pinecone_time = time.perf_counter() - pinecone_start
106
  logger.info(f"[RECOMMEND] Pinecone query completed in {pinecone_time:.3f}s: found {len(similar_mentors)} candidates")
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  if not similar_mentors:
109
- logger.warning("[RECOMMEND] No similar mentors found, returning empty list")
110
  return []
111
 
112
  metadata_start = time.perf_counter()
@@ -162,24 +195,35 @@ class RecommendationService:
162
  filter_dict = {}
163
 
164
  if mentee_data.get("min_rating"):
165
- filter_dict["rating"] = {"$gte": float(mentee_data["min_rating"])}
 
 
166
 
167
  if mentee_data.get("require_availability"):
168
  filter_dict["has_availability"] = True
 
169
 
170
  if mentee_data.get("skill_ids"):
171
- filter_dict["skill_ids"] = {"$in": [str(int(id)) for id in mentee_data["skill_ids"]]}
 
 
172
 
173
  if mentee_data.get("domain_ids"):
174
- filter_dict["domain_ids"] = {"$in": [str(int(id)) for id in mentee_data["domain_ids"]]}
 
 
175
 
176
  if mentee_data.get("career_id"):
177
- filter_dict["career_id"] = int(mentee_data["career_id"])
 
 
178
 
179
  if mentee_data.get("status"):
180
  filter_dict["status"] = str(mentee_data["status"])
 
181
  else:
182
  filter_dict["status"] = "ACTIVATED"
 
183
 
184
  return filter_dict if filter_dict else None
185
 
 
105
  pinecone_time = time.perf_counter() - pinecone_start
106
  logger.info(f"[RECOMMEND] Pinecone query completed in {pinecone_time:.3f}s: found {len(similar_mentors)} candidates")
107
 
108
+ if not similar_mentors and filter_dict:
109
+ has_strict_filters = "rating" in filter_dict or "has_availability" in filter_dict
110
+
111
+ if has_strict_filters:
112
+ logger.warning(f"[RECOMMEND] No results with strict filter (rating/availability), trying fallback with relaxed filter")
113
+ logger.info(f"[RECOMMEND] Original filter: {filter_dict}")
114
+
115
+ fallback_filter = {}
116
+ if mentee_data.get("skill_ids"):
117
+ fallback_filter["skill_ids"] = {"$in": [str(int(id)) for id in mentee_data["skill_ids"]]}
118
+ if mentee_data.get("domain_ids"):
119
+ fallback_filter["domain_ids"] = {"$in": [str(int(id)) for id in mentee_data["domain_ids"]]}
120
+ if mentee_data.get("career_id"):
121
+ fallback_filter["career_id"] = int(mentee_data["career_id"])
122
+ if mentee_data.get("status"):
123
+ fallback_filter["status"] = str(mentee_data["status"])
124
+ else:
125
+ fallback_filter["status"] = "ACTIVATED"
126
+
127
+ logger.info(f"[RECOMMEND] Fallback filter (removed rating/availability constraints): {fallback_filter}")
128
+
129
+ fallback_start = time.perf_counter()
130
+ similar_mentors = self.pinecone_service.query_similar(
131
+ query_vector=query_embedding,
132
+ top_k=top_k,
133
+ filter=fallback_filter if fallback_filter else None,
134
+ include_metadata=True
135
+ )
136
+ fallback_time = time.perf_counter() - fallback_start
137
+ logger.info(f"[RECOMMEND] Fallback query completed in {fallback_time:.3f}s: found {len(similar_mentors)} candidates")
138
+ else:
139
+ logger.warning(f"[RECOMMEND] No results found even without strict filters")
140
+
141
  if not similar_mentors:
142
+ logger.warning("[RECOMMEND] No similar mentors found after fallback, returning empty list")
143
  return []
144
 
145
  metadata_start = time.perf_counter()
 
195
  filter_dict = {}
196
 
197
  if mentee_data.get("min_rating"):
198
+ min_rating = float(mentee_data["min_rating"])
199
+ filter_dict["rating"] = {"$gte": min_rating}
200
+ logger.info(f"[RECOMMEND] Adding rating filter: >= {min_rating}")
201
 
202
  if mentee_data.get("require_availability"):
203
  filter_dict["has_availability"] = True
204
+ logger.info(f"[RECOMMEND] Adding availability filter: has_availability=True")
205
 
206
  if mentee_data.get("skill_ids"):
207
+ skill_ids = [str(int(id)) for id in mentee_data["skill_ids"]]
208
+ filter_dict["skill_ids"] = {"$in": skill_ids}
209
+ logger.info(f"[RECOMMEND] Adding skill_ids filter: {skill_ids}")
210
 
211
  if mentee_data.get("domain_ids"):
212
+ domain_ids = [str(int(id)) for id in mentee_data["domain_ids"]]
213
+ filter_dict["domain_ids"] = {"$in": domain_ids}
214
+ logger.info(f"[RECOMMEND] Adding domain_ids filter: {domain_ids}")
215
 
216
  if mentee_data.get("career_id"):
217
+ career_id = int(mentee_data["career_id"])
218
+ filter_dict["career_id"] = career_id
219
+ logger.info(f"[RECOMMEND] Adding career_id filter: {career_id}")
220
 
221
  if mentee_data.get("status"):
222
  filter_dict["status"] = str(mentee_data["status"])
223
+ logger.info(f"[RECOMMEND] Adding status filter: {mentee_data['status']}")
224
  else:
225
  filter_dict["status"] = "ACTIVATED"
226
+ logger.info(f"[RECOMMEND] Adding default status filter: ACTIVATED")
227
 
228
  return filter_dict if filter_dict else None
229