CAntoniadis commited on
Commit
0de7101
·
verified ·
1 Parent(s): 67858ce

Update simple_search_engine/search_engine.py

Browse files
Files changed (1) hide show
  1. simple_search_engine/search_engine.py +28 -60
simple_search_engine/search_engine.py CHANGED
@@ -9,6 +9,7 @@ import numpy as np
9
 
10
  CORPUS_DIR = "../corpus"
11
 
 
12
  def _tokenize(text: str):
13
  return re.findall(r"\b\w+\b", text.lower())
14
 
@@ -19,11 +20,11 @@ class SimpleSearchEngine:
19
  self.documents: List[Dict] = []
20
 
21
  # TF-IDF
22
- self.vectorizer: TfidfVectorizer | None = None
23
  self.doc_tfidf = None
24
 
25
  # BM25
26
- self.bm25: BM25Okapi | None = None
27
  self._bm25_tokens = []
28
 
29
  def _load_documents(self):
@@ -45,16 +46,13 @@ class SimpleSearchEngine:
45
  data = json.load(f)
46
 
47
  text = data.get("tf_idf_text", "").strip()
48
- url = data.get("url", "")
49
- title = data.get("title", os.path.splitext(fname)[0])
50
-
51
  if not text:
52
  continue
53
 
54
  docs.append({
55
  "id": doc_id,
56
- "title": title,
57
- "url": url,
58
  "path": path,
59
  "text": text,
60
  })
@@ -75,7 +73,7 @@ class SimpleSearchEngine:
75
  return
76
 
77
  # TF-IDF
78
- self.vectorizer = TfidfVectorizer(analyzer="word", token_pattern=r"\b\w+\b")
79
  self.doc_tfidf = self.vectorizer.fit_transform(texts)
80
  print("TF-IDF index built.")
81
 
@@ -91,51 +89,32 @@ class SimpleSearchEngine:
91
  return np.zeros_like(scores)
92
  return (scores - min_s) / (max_s - min_s)
93
 
94
- def search_bm25(self, query: str, top_k: int = 5):
95
- if self.bm25 is None:
96
- raise RuntimeError("BM25 index not built. Call build_index() first.")
97
-
98
- q_tokens = _tokenize(query)
99
- scores = np.array(self.bm25.get_scores(q_tokens), dtype=float)
100
- print(f"[DEBUG][BM25] query={query}")
101
- print("[DEBUG][BM25] top5_scores=", scores[scores.argsort()[::-1][:5]])
102
 
 
 
103
  ranked_idx = scores.argsort()[::-1][:top_k]
104
 
105
  results = []
106
  for idx in ranked_idx:
107
- doc = self.documents[int(idx)]
108
- snippet = doc["text"][:200] + ("..." if len(doc["text"]) > 200 else "")
109
- results.append({
110
- "score": float(scores[int(idx)]),
111
- "title": doc["title"],
112
- "url": doc["url"],
113
- "path": doc["path"],
114
- "snippet": snippet,
115
- })
116
 
117
  return results
118
 
119
- # TF-IDF search
120
- def search(self, query: str, top_k: int = 5):
121
- if self.vectorizer is None or self.doc_tfidf is None:
122
- raise RuntimeError("Index not built. Call build_index() first.")
123
 
124
- query_vec = self.vectorizer.transform([query])
125
- similarities = linear_kernel(query_vec, self.doc_tfidf).flatten()
126
- top_idx = similarities.argsort()[::-1][:top_k]
127
 
128
  results = []
129
- for idx in top_idx:
130
  doc = self.documents[idx]
131
- snippet = doc["text"][:200] + ("..." if len(doc["text"]) > 200 else "")
132
- results.append({
133
- "score": float(similarities[idx]),
134
- "title": doc["title"],
135
- "url": doc["url"],
136
- "path": doc["path"],
137
- "snippet": snippet,
138
- })
139
 
140
  return results
141
 
@@ -148,8 +127,10 @@ class SimpleSearchEngine:
148
  tfidf_scores = linear_kernel(query_vec, self.doc_tfidf).flatten()
149
 
150
  # BM25 scores
151
- q_tokens = _tokenize(query)
152
- bm25_scores = np.array(self.bm25.get_scores(q_tokens), dtype=float)
 
 
153
 
154
  # Normalize
155
  tfidf_norm = self._minmax_normalize(tfidf_scores)
@@ -157,24 +138,11 @@ class SimpleSearchEngine:
157
 
158
  # Combine
159
  hybrid_scores = alpha * tfidf_norm + (1 - alpha) * bm25_norm
160
- print(f"[DEBUG][HYBRID] query={query} alpha={alpha}")
161
- print(
162
- "[DEBUG][HYBRID] top5_hybrid=",
163
- hybrid_scores[hybrid_scores.argsort()[::-1][:5]]
164
- )
165
-
166
  ranked_idx = hybrid_scores.argsort()[::-1][:top_k]
167
 
168
  results = []
169
  for idx in ranked_idx:
170
- doc = self.documents[int(idx)]
171
- snippet = doc["text"][:200] + ("..." if len(doc["text"]) > 200 else "")
172
- results.append({
173
- "score": float(hybrid_scores[int(idx)]),
174
- "title": doc["title"],
175
- "url": doc["url"],
176
- "path": doc["path"],
177
- "snippet": snippet,
178
- })
179
-
180
- return results
 
9
 
10
  CORPUS_DIR = "../corpus"
11
 
12
+
13
  def _tokenize(text: str):
14
  return re.findall(r"\b\w+\b", text.lower())
15
 
 
20
  self.documents: List[Dict] = []
21
 
22
  # TF-IDF
23
+ self.vectorizer = None
24
  self.doc_tfidf = None
25
 
26
  # BM25
27
+ self.bm25 = None
28
  self._bm25_tokens = []
29
 
30
  def _load_documents(self):
 
46
  data = json.load(f)
47
 
48
  text = data.get("tf_idf_text", "").strip()
 
 
 
49
  if not text:
50
  continue
51
 
52
  docs.append({
53
  "id": doc_id,
54
+ "title": data.get("title", os.path.splitext(fname)[0]),
55
+ "url": data.get("url", ""),
56
  "path": path,
57
  "text": text,
58
  })
 
73
  return
74
 
75
  # TF-IDF
76
+ self.vectorizer = TfidfVectorizer(token_pattern=r"\b\w+\b")
77
  self.doc_tfidf = self.vectorizer.fit_transform(texts)
78
  print("TF-IDF index built.")
79
 
 
89
  return np.zeros_like(scores)
90
  return (scores - min_s) / (max_s - min_s)
91
 
92
+ def search(self, query: str, top_k: int = 5):
93
+ if self.vectorizer is None or self.doc_tfidf is None:
94
+ raise RuntimeError("Index not built. Call build_index() first.")
 
 
 
 
 
95
 
96
+ query_vec = self.vectorizer.transform([query])
97
+ scores = linear_kernel(query_vec, self.doc_tfidf).flatten()
98
  ranked_idx = scores.argsort()[::-1][:top_k]
99
 
100
  results = []
101
  for idx in ranked_idx:
102
+ doc = self.documents[idx]
103
+ results.append(doc)
 
 
 
 
 
 
 
104
 
105
  return results
106
 
107
+ def search_bm25(self, query: str, top_k: int = 5):
108
+ if self.bm25 is None:
109
+ raise RuntimeError("BM25 index not built. Call build_index() first.")
 
110
 
111
+ scores = np.array(self.bm25.get_scores(_tokenize(query)))
112
+ ranked_idx = scores.argsort()[::-1][:top_k]
 
113
 
114
  results = []
115
+ for idx in ranked_idx:
116
  doc = self.documents[idx]
117
+ results.append(doc)
 
 
 
 
 
 
 
118
 
119
  return results
120
 
 
127
  tfidf_scores = linear_kernel(query_vec, self.doc_tfidf).flatten()
128
 
129
  # BM25 scores
130
+ bm25_scores = np.array(
131
+ self.bm25.get_scores(_tokenize(query)),
132
+ dtype=float
133
+ )
134
 
135
  # Normalize
136
  tfidf_norm = self._minmax_normalize(tfidf_scores)
 
138
 
139
  # Combine
140
  hybrid_scores = alpha * tfidf_norm + (1 - alpha) * bm25_norm
 
 
 
 
 
 
141
  ranked_idx = hybrid_scores.argsort()[::-1][:top_k]
142
 
143
  results = []
144
  for idx in ranked_idx:
145
+ doc = self.documents[idx]
146
+ results.append(doc)
147
+
148
+ return results