ktsn-ud commited on
Commit
59424a5
·
1 Parent(s): 5feeb19

cc.ja.300.binのパスの参照先をfiles.jsonに一本化

Browse files
Files changed (2) hide show
  1. api/search/engine.py +51 -23
  2. config/search_model.json +0 -1
api/search/engine.py CHANGED
@@ -96,9 +96,11 @@ class SearchEngine:
96
  word_sim_enable=bool(search("word_sim.enable")),
97
  word_sim_alpha=float(search("word_sim.alpha")),
98
  word_sim_topk_k=int(search("word_sim.topk_k", 3)),
99
- word_sim_rerank=(search("word_sim.rerank", "pair_avg") or "pair_avg").lower(),
 
 
100
  query_subword_enable=bool(search("query_subword.enable")),
101
- query_subword_path=search("query_subword.path"),
102
  query_subword_oov_weight=float(search("query_subword.oov_weight")),
103
  org_boost_exact=float(search("organization.boost.exact", 1.0)),
104
  org_boost_prefix=float(search("organization.boost.prefix", 0.7)),
@@ -132,7 +134,9 @@ class SearchEngine:
132
  log.warning(f"failed to load synonyms_cache: {e}")
133
 
134
  try:
135
- custom_path = field_getter("config/search_model.json")("synonyms.sources.custom_json")
 
 
136
  if custom_path and os.path.exists(custom_path):
137
  with open(custom_path, encoding="utf-8") as f:
138
  self.custom_synonyms = json.load(f)
@@ -143,8 +147,14 @@ class SearchEngine:
143
  with open(files("projects.projects_json"), encoding="utf-8") as f:
144
  self.projects = json.load(f)
145
  self.project_map = {p["projectId"]: p for p in self.projects}
146
- self.org_norms = {p["projectId"]: normalize_text_for_org(p.get("organization") or "") for p in self.projects}
147
- self.reading_norms = {p["projectId"]: normalize_text_for_org(p.get("reading") or "") for p in self.projects}
 
 
 
 
 
 
148
 
149
  # BM25F assets
150
  with open(files("bm25.bm25_meta"), encoding="utf-8") as f:
@@ -169,7 +179,11 @@ class SearchEngine:
169
  # doc_vectors.npy は topk 方式では不要
170
 
171
  # fastText OOV
172
- if self.cfg.query_subword_enable and self.cfg.query_subword_path and os.path.exists(self.cfg.query_subword_path):
 
 
 
 
173
  try:
174
  import fasttext
175
 
@@ -246,7 +260,7 @@ class SearchEngine:
246
  denom_sum = 0.0
247
  num_sum = 0.0
248
  for field, weight in fw.items():
249
- fobj = (fields.get(field) or {})
250
  tf = float((fobj.get("tf") or {}).get(t, 0))
251
  if tf <= 0.0:
252
  continue
@@ -314,8 +328,8 @@ class SearchEngine:
314
  fields = d.get("fields") or {}
315
  doc_terms = set()
316
  for fname in self.cfg.target_fields:
317
- fobj = (fields.get(fname) or {})
318
- tf = (fobj.get("tf") or {})
319
  doc_terms.update(tf.keys())
320
  if not doc_terms:
321
  sims_all[i] = 0.0
@@ -371,8 +385,8 @@ class SearchEngine:
371
  fields = d.get("fields") or {}
372
  doc_terms = set()
373
  for fname in self.cfg.target_fields:
374
- fobj = (fields.get(fname) or {})
375
- tf = (fobj.get("tf") or {})
376
  doc_terms.update(tf.keys())
377
  if not doc_terms:
378
  sims_all[i] = 0.0
@@ -442,9 +456,15 @@ class SearchEngine:
442
  # Relative threshold anchored to the top fused score
443
  score_with_boost = fused_filter + boost
444
  top = float(np.max(score_with_boost)) if score_with_boost.size > 0 else 0.0
445
- rel_cut = top * float(self.cfg.fused_rel_top_ratio) if top > 0 else self.cfg.fused_min
 
 
446
  fused_cut = max(float(self.cfg.fused_min), rel_cut)
447
- keep = ((bm25 >= self.cfg.bm25_min) | (ws_filter >= self.cfg.word_sim_min) | (score_with_boost >= self.cfg.fused_min)) & (score_with_boost >= fused_cut)
 
 
 
 
448
  order = np.argsort(-score_with_boost) # descending by fused
449
  selected_idx: List[int] = []
450
  for i in order:
@@ -454,7 +474,11 @@ class SearchEngine:
454
  break
455
  # Single-step fallback: if zero, relax the relative cut and use absolute thresholds only
456
  if len(selected_idx) == 0:
457
- keep2 = (bm25 >= self.cfg.bm25_min) | (ws_filter >= self.cfg.word_sim_min) | (score_with_boost >= self.cfg.fused_min)
 
 
 
 
458
  for i in order:
459
  if keep2[i]:
460
  selected_idx.append(int(i))
@@ -477,15 +501,19 @@ class SearchEngine:
477
  # build debug details for selected docs
478
  details = []
479
  for i in selected_idx:
480
- details.append({
481
- "projectId": ids[i],
482
- "bm25": float(bm25[i]),
483
- "ws_filter_topk": float(ws_filter[i]),
484
- "ws_rerank_pairavg": float(ws_rerank[i]) if ws_rerank is not None else None,
485
- "org_boost": float(boost[i]),
486
- "fused_filter": float(fused_filter[i]),
487
- "fused_final": float(final_scores[i]),
488
- })
 
 
 
 
489
  return pairs, {"details": details}
490
 
491
  def get_projects(self) -> List[Dict[str, Any]]:
 
96
  word_sim_enable=bool(search("word_sim.enable")),
97
  word_sim_alpha=float(search("word_sim.alpha")),
98
  word_sim_topk_k=int(search("word_sim.topk_k", 3)),
99
+ word_sim_rerank=(
100
+ search("word_sim.rerank", "pair_avg") or "pair_avg"
101
+ ).lower(),
102
  query_subword_enable=bool(search("query_subword.enable")),
103
+ query_subword_path=files("embeddings.fasttext_bin"),
104
  query_subword_oov_weight=float(search("query_subword.oov_weight")),
105
  org_boost_exact=float(search("organization.boost.exact", 1.0)),
106
  org_boost_prefix=float(search("organization.boost.prefix", 0.7)),
 
134
  log.warning(f"failed to load synonyms_cache: {e}")
135
 
136
  try:
137
+ custom_path = field_getter("config/search_model.json")(
138
+ "synonyms.sources.custom_json"
139
+ )
140
  if custom_path and os.path.exists(custom_path):
141
  with open(custom_path, encoding="utf-8") as f:
142
  self.custom_synonyms = json.load(f)
 
147
  with open(files("projects.projects_json"), encoding="utf-8") as f:
148
  self.projects = json.load(f)
149
  self.project_map = {p["projectId"]: p for p in self.projects}
150
+ self.org_norms = {
151
+ p["projectId"]: normalize_text_for_org(p.get("organization") or "")
152
+ for p in self.projects
153
+ }
154
+ self.reading_norms = {
155
+ p["projectId"]: normalize_text_for_org(p.get("reading") or "")
156
+ for p in self.projects
157
+ }
158
 
159
  # BM25F assets
160
  with open(files("bm25.bm25_meta"), encoding="utf-8") as f:
 
179
  # doc_vectors.npy は topk 方式では不要
180
 
181
  # fastText OOV
182
+ if (
183
+ self.cfg.query_subword_enable
184
+ and self.cfg.query_subword_path
185
+ and os.path.exists(self.cfg.query_subword_path)
186
+ ):
187
  try:
188
  import fasttext
189
 
 
260
  denom_sum = 0.0
261
  num_sum = 0.0
262
  for field, weight in fw.items():
263
+ fobj = fields.get(field) or {}
264
  tf = float((fobj.get("tf") or {}).get(t, 0))
265
  if tf <= 0.0:
266
  continue
 
328
  fields = d.get("fields") or {}
329
  doc_terms = set()
330
  for fname in self.cfg.target_fields:
331
+ fobj = fields.get(fname) or {}
332
+ tf = fobj.get("tf") or {}
333
  doc_terms.update(tf.keys())
334
  if not doc_terms:
335
  sims_all[i] = 0.0
 
385
  fields = d.get("fields") or {}
386
  doc_terms = set()
387
  for fname in self.cfg.target_fields:
388
+ fobj = fields.get(fname) or {}
389
+ tf = fobj.get("tf") or {}
390
  doc_terms.update(tf.keys())
391
  if not doc_terms:
392
  sims_all[i] = 0.0
 
456
  # Relative threshold anchored to the top fused score
457
  score_with_boost = fused_filter + boost
458
  top = float(np.max(score_with_boost)) if score_with_boost.size > 0 else 0.0
459
+ rel_cut = (
460
+ top * float(self.cfg.fused_rel_top_ratio) if top > 0 else self.cfg.fused_min
461
+ )
462
  fused_cut = max(float(self.cfg.fused_min), rel_cut)
463
+ keep = (
464
+ (bm25 >= self.cfg.bm25_min)
465
+ | (ws_filter >= self.cfg.word_sim_min)
466
+ | (score_with_boost >= self.cfg.fused_min)
467
+ ) & (score_with_boost >= fused_cut)
468
  order = np.argsort(-score_with_boost) # descending by fused
469
  selected_idx: List[int] = []
470
  for i in order:
 
474
  break
475
  # Single-step fallback: if zero, relax the relative cut and use absolute thresholds only
476
  if len(selected_idx) == 0:
477
+ keep2 = (
478
+ (bm25 >= self.cfg.bm25_min)
479
+ | (ws_filter >= self.cfg.word_sim_min)
480
+ | (score_with_boost >= self.cfg.fused_min)
481
+ )
482
  for i in order:
483
  if keep2[i]:
484
  selected_idx.append(int(i))
 
501
  # build debug details for selected docs
502
  details = []
503
  for i in selected_idx:
504
+ details.append(
505
+ {
506
+ "projectId": ids[i],
507
+ "bm25": float(bm25[i]),
508
+ "ws_filter_topk": float(ws_filter[i]),
509
+ "ws_rerank_pairavg": float(ws_rerank[i])
510
+ if ws_rerank is not None
511
+ else None,
512
+ "org_boost": float(boost[i]),
513
+ "fused_filter": float(fused_filter[i]),
514
+ "fused_final": float(final_scores[i]),
515
+ }
516
+ )
517
  return pairs, {"details": details}
518
 
519
  def get_projects(self) -> List[Dict[str, Any]]:
config/search_model.json CHANGED
@@ -51,7 +51,6 @@
51
  },
52
  "query_subword": {
53
  "enable": true,
54
- "path": "resources/embeddings/cc.ja.300.bin",
55
  "oov_weight": 0.8,
56
  "cache_size": 50000
57
  },
 
51
  },
52
  "query_subword": {
53
  "enable": true,
 
54
  "oov_weight": 0.8,
55
  "cache_size": 50000
56
  },