vomebook commited on
Commit
59e85fd
·
verified ·
1 Parent(s): bb77bc6

perf: reduce shallow search work and reuse exact counts across pages

Browse files
Files changed (1) hide show
  1. app.py +36 -7
app.py CHANGED
@@ -38,6 +38,7 @@ source_name_order: dict[str, list[int]] = {}
38
  source_size_order: dict[str, list[int]] = {}
39
  record_map: dict[str, dict] = {}
40
  record_map_index: dict[str, int] = {}
 
41
  sources: list[dict] = []
42
  source_counts: dict[str, int] = {}
43
  folder_tree_data: dict[str, list[dict]] = {}
@@ -790,17 +791,26 @@ def load_json_gz(path: Path):
790
  return json.loads(gzip.decompress(path.read_bytes()).decode("utf-8"))
791
 
792
  def build_indexes() -> None:
793
- global word_index, latin_all_index, latin_file_index, latin_vocabulary_all, source_records_map, extension_counts, source_extension_counts, name_order, size_order, source_name_order, source_size_order
794
  clear_metadata_match_cache()
795
  word_index = {}
796
  latin_all_index = {}
797
  latin_file_index = {}
798
  latin_vocabulary_all = set()
799
  source_records_map = {}
 
800
  extension_counts = {}
801
  source_extension_counts = {}
802
  for idx, rec in enumerate(records):
803
  source = rec["source"]
 
 
 
 
 
 
 
 
804
  extension = rec["extension"]
805
  source_records_map.setdefault(source, []).append(idx)
806
  extension_counts[extension] = extension_counts.get(extension, 0) + 1
@@ -870,10 +880,26 @@ def relevance_page(indices, query_tokens: list[str], search_paths: bool, start:
870
  limit = start + page_size
871
  if limit <= 0:
872
  return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
873
  if start >= 1000:
874
- indices = list(indices)
875
- if start >= len(indices):
876
- return []
877
  if len(indices) >= 10000:
878
  scores = {idx: score_record(idx, query_tokens, search_paths) for idx in indices}
879
  if len(scores) == len(indices):
@@ -1177,13 +1203,16 @@ def fulltext_search(q="", sources_filter=None, folders=None, min_size=None, max_
1177
  source_slugs = sources_filter if sources_filter is not None else list(source_counts)
1178
  if not source_slugs:
1179
  return {"results": [], "total": 0, "page": max(1, page), "page_size": page_size}
1180
- matched_doc_ids = set()
1181
  sqlite_started = time.perf_counter()
1182
  for source_slug in source_slugs:
1183
- matched_doc_ids.update(f"{source_slug}:{doc_number}" for doc_number in fulltext_databases.search_source(source_slug, q, exact))
 
 
 
 
1184
  if timings is not None:
1185
  timings["sqlite"] = (time.perf_counter() - sqlite_started) * 1000
1186
- content_indices = {idx for doc_id in matched_doc_ids if (idx := record_map_index.get(doc_id)) is not None}
1187
  indices = set(content_indices)
1188
  metadata_started = time.perf_counter()
1189
  indices.update(metadata_matches(q, exact, search_paths))
 
38
  source_size_order: dict[str, list[int]] = {}
39
  record_map: dict[str, dict] = {}
40
  record_map_index: dict[str, int] = {}
41
+ source_doc_number_index: dict[str, dict[int, int]] = {}
42
  sources: list[dict] = []
43
  source_counts: dict[str, int] = {}
44
  folder_tree_data: dict[str, list[dict]] = {}
 
791
  return json.loads(gzip.decompress(path.read_bytes()).decode("utf-8"))
792
 
793
  def build_indexes() -> None:
794
+ global word_index, latin_all_index, latin_file_index, latin_vocabulary_all, source_records_map, source_doc_number_index, extension_counts, source_extension_counts, name_order, size_order, source_name_order, source_size_order
795
  clear_metadata_match_cache()
796
  word_index = {}
797
  latin_all_index = {}
798
  latin_file_index = {}
799
  latin_vocabulary_all = set()
800
  source_records_map = {}
801
+ source_doc_number_index = {}
802
  extension_counts = {}
803
  source_extension_counts = {}
804
  for idx, rec in enumerate(records):
805
  source = rec["source"]
806
+ id_source, separator, number_text = rec["doc_id"].partition(":")
807
+ try:
808
+ number = int(number_text)
809
+ except ValueError:
810
+ pass
811
+ else:
812
+ if separator and str(number) == number_text:
813
+ source_doc_number_index.setdefault(id_source, {})[number] = idx
814
  extension = rec["extension"]
815
  source_records_map.setdefault(source, []).append(idx)
816
  extension_counts[extension] = extension_counts.get(extension, 0) + 1
 
880
  limit = start + page_size
881
  if limit <= 0:
882
  return []
883
+ indices = list(indices)
884
+ if start >= len(indices):
885
+ return []
886
+ if start < 1000 and len(indices) >= 10000 and query_tokens and all(
887
+ re.fullmatch(r"[\u4e00-\u9fff\u3400-\u4dbf]{1,2}", token) for token in query_tokens
888
+ ):
889
+ potential = metadata_prefilter(query_tokens, search_paths)
890
+ if potential is not None and len(potential) >= limit:
891
+ candidates = set(indices)
892
+ potential.intersection_update(candidates)
893
+ if len(candidates) == len(indices) and len(potential) >= limit:
894
+ # Only maximum-score hits can make unseen candidates irrelevant.
895
+ maximum = (5 if search_paths else 3) * len(query_tokens)
896
+ highest = []
897
+ for idx in name_order:
898
+ if idx in potential and score_record(idx, query_tokens, search_paths) == maximum:
899
+ highest.append(idx)
900
+ if len(highest) == limit:
901
+ return highest[start:limit]
902
  if start >= 1000:
 
 
 
903
  if len(indices) >= 10000:
904
  scores = {idx: score_record(idx, query_tokens, search_paths) for idx in indices}
905
  if len(scores) == len(indices):
 
1203
  source_slugs = sources_filter if sources_filter is not None else list(source_counts)
1204
  if not source_slugs:
1205
  return {"results": [], "total": 0, "page": max(1, page), "page_size": page_size}
1206
+ content_indices = set()
1207
  sqlite_started = time.perf_counter()
1208
  for source_slug in source_slugs:
1209
+ number_index = source_doc_number_index.get(source_slug, {})
1210
+ content_indices.update(
1211
+ idx for doc_number in fulltext_databases.search_source(source_slug, q, exact)
1212
+ if (idx := number_index.get(doc_number)) is not None
1213
+ )
1214
  if timings is not None:
1215
  timings["sqlite"] = (time.perf_counter() - sqlite_started) * 1000
 
1216
  indices = set(content_indices)
1217
  metadata_started = time.perf_counter()
1218
  indices.update(metadata_matches(q, exact, search_paths))