vomebook commited on
Commit
8eedc99
·
verified ·
1 Parent(s): 958e254

perf: accelerate complete wildcard and literal candidate scans

Browse files
Files changed (1) hide show
  1. app.py +24 -1
app.py CHANGED
@@ -61,12 +61,15 @@ FULLTEXT_MATCH_CACHE_TTL_SECONDS = 300
61
  FULLTEXT_MATCH_CACHE_MAX_ENTRIES = 16
62
  FULLTEXT_MATCH_CACHE_MAX_TOTAL_IDS = 250000
63
  WILDCARD_FTS_SCAN_MIN_CANDIDATES = 5000
 
64
  PREVIEW_CACHE_MAX_ENTRIES = 64
65
  PREVIEW_CACHE_MAX_ENTRY_BYTES = 2 * 1024 * 1024
66
  api_response_cache: dict[tuple, tuple[float, object]] = {}
67
  api_response_cache_lock = threading.Lock()
68
  search_response_cache: dict[tuple, tuple[float, object]] = {}
69
  search_response_cache_lock = threading.Lock()
 
 
70
  preview_text_cache: dict[str, str] = {}
71
  preview_text_cache_lock = threading.Lock()
72
  cache_key_locks: dict[tuple, threading.Lock] = {}
@@ -247,6 +250,8 @@ class FulltextDatabases:
247
  self.file_signatures[source] = signature
248
  self.generation += 1
249
  self.match_cache.clear()
 
 
250
  if old_connection is not None:
251
  if self.connection_readers.get(old_connection, 0):
252
  self.retired_connections.add(old_connection)
@@ -287,6 +292,8 @@ class FulltextDatabases:
287
  with self.lock:
288
  self.closed = True
289
  self.match_cache.clear()
 
 
290
  for event in self.match_inflight.values():
291
  event.set()
292
  self.match_inflight.clear()
@@ -778,6 +785,8 @@ def load_json_gz(path: Path):
778
 
779
  def build_indexes() -> None:
780
  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
 
 
781
  word_index = {}
782
  latin_all_index = {}
783
  latin_file_index = {}
@@ -1041,7 +1050,7 @@ def metadata_prefilter(terms: list[str], search_paths: bool) -> set[int] | None:
1041
  break
1042
  return candidates
1043
 
1044
- def metadata_matches(q: str, exact: bool, search_paths: bool) -> set[int]:
1045
  field = "_search_text" if search_paths else "_file_search_text"
1046
  if exact:
1047
  terms = query_terms(q)
@@ -1077,6 +1086,20 @@ def metadata_matches(q: str, exact: bool, search_paths: bool) -> set[int]:
1077
  if all(term in records[idx][field] for term in terms)
1078
  }
1079
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1080
  def search(q="", sources_filter=None, folders=None, min_size=None, max_size=None, page=1, page_size=100, sort="relevance", exact=False, search_paths=True, timings=None):
1081
  started = time.perf_counter()
1082
  q = q.strip()
 
61
  FULLTEXT_MATCH_CACHE_MAX_ENTRIES = 16
62
  FULLTEXT_MATCH_CACHE_MAX_TOTAL_IDS = 250000
63
  WILDCARD_FTS_SCAN_MIN_CANDIDATES = 5000
64
+ METADATA_MATCH_CACHE_MAX_ENTRIES = 128
65
  PREVIEW_CACHE_MAX_ENTRIES = 64
66
  PREVIEW_CACHE_MAX_ENTRY_BYTES = 2 * 1024 * 1024
67
  api_response_cache: dict[tuple, tuple[float, object]] = {}
68
  api_response_cache_lock = threading.Lock()
69
  search_response_cache: dict[tuple, tuple[float, object]] = {}
70
  search_response_cache_lock = threading.Lock()
71
+ metadata_match_cache: dict[tuple, frozenset[int]] = {}
72
+ metadata_match_cache_lock = threading.Lock()
73
  preview_text_cache: dict[str, str] = {}
74
  preview_text_cache_lock = threading.Lock()
75
  cache_key_locks: dict[tuple, threading.Lock] = {}
 
250
  self.file_signatures[source] = signature
251
  self.generation += 1
252
  self.match_cache.clear()
253
+ with metadata_match_cache_lock:
254
+ metadata_match_cache.clear()
255
  if old_connection is not None:
256
  if self.connection_readers.get(old_connection, 0):
257
  self.retired_connections.add(old_connection)
 
292
  with self.lock:
293
  self.closed = True
294
  self.match_cache.clear()
295
+ with metadata_match_cache_lock:
296
+ metadata_match_cache.clear()
297
  for event in self.match_inflight.values():
298
  event.set()
299
  self.match_inflight.clear()
 
785
 
786
  def build_indexes() -> None:
787
  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
788
+ with metadata_match_cache_lock:
789
+ metadata_match_cache.clear()
790
  word_index = {}
791
  latin_all_index = {}
792
  latin_file_index = {}
 
1050
  break
1051
  return candidates
1052
 
1053
+ def _metadata_matches_uncached(q: str, exact: bool, search_paths: bool) -> set[int]:
1054
  field = "_search_text" if search_paths else "_file_search_text"
1055
  if exact:
1056
  terms = query_terms(q)
 
1086
  if all(term in records[idx][field] for term in terms)
1087
  }
1088
 
1089
+
1090
+ def metadata_matches(q: str, exact: bool, search_paths: bool) -> set[int]:
1091
+ key = (q, exact, search_paths)
1092
+ with metadata_match_cache_lock:
1093
+ cached = metadata_match_cache.get(key)
1094
+ if cached is not None:
1095
+ return set(cached)
1096
+ result = _metadata_matches_uncached(q, exact, search_paths)
1097
+ with metadata_match_cache_lock:
1098
+ metadata_match_cache[key] = frozenset(result)
1099
+ while len(metadata_match_cache) > METADATA_MATCH_CACHE_MAX_ENTRIES:
1100
+ metadata_match_cache.pop(next(iter(metadata_match_cache)), None)
1101
+ return set(result)
1102
+
1103
  def search(q="", sources_filter=None, folders=None, min_size=None, max_size=None, page=1, page_size=100, sort="relevance", exact=False, search_paths=True, timings=None):
1104
  started = time.perf_counter()
1105
  q = q.strip()