update search

This commit is contained in:
Ross
2026-07-11 11:01:57 +01:00
parent 9f70f3994c
commit 6642181ce1
3 changed files with 732 additions and 378 deletions
+147 -107
View File
@@ -249,11 +249,33 @@ def match_author(authors: List[Dict[str, Any]], q: str) -> bool:
return False
def run_search(root: str, qkey: str, qval: str, mode: str = 'exact', targets: List[str] = None) -> List[Dict[str, Any]]:
def run_search(root: str, qkey: str, qval: str, mode: str = 'exact', targets: List[str] = None, or_queries: List[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
out = []
# Helper to test if a string/list/dict matches under the chosen mode
def value_matches(query: str, target_val: Any) -> bool:
# Normalize queries list
if not or_queries:
or_queries = [{
'qkey': qkey,
'qval': qval,
'mode': mode,
'targets': targets
}]
normalized_specs = []
for spec in or_queries:
qk = spec.get('qkey') or 'global'
qv = spec.get('qval') or ''
m = spec.get('mode') or 'exact'
t = spec.get('targets')
normalized_specs.append({
'qkey': qk,
'qval': qv,
'mode': m,
'targets': t
})
# Helper to test if a string/list/dict matches under a specific mode
def value_matches(query: str, target_val: Any, mode_val: str) -> bool:
if target_val is None:
return False
@@ -261,15 +283,15 @@ def run_search(root: str, qkey: str, qval: str, mode: str = 'exact', targets: Li
for item in target_val:
if isinstance(item, dict):
for k, v in item.items():
if value_matches(query, v):
if value_matches(query, v, mode_val):
return True
else:
if value_matches(query, item):
if value_matches(query, item, mode_val):
return True
return False
elif isinstance(target_val, dict):
for k, v in target_val.items():
if value_matches(query, v):
if value_matches(query, v, mode_val):
return True
return False
@@ -277,9 +299,9 @@ def run_search(root: str, qkey: str, qval: str, mode: str = 'exact', targets: Li
if not s_val:
return False
if mode == 'stemming':
if mode_val == 'stemming':
return match_stemming(query, s_val)
elif mode == 'fuzzy':
elif mode_val == 'fuzzy':
return match_fuzzy(query, s_val)
else:
# Exact substring or wildcard match
@@ -303,108 +325,126 @@ def run_search(root: str, qkey: str, qval: str, mode: str = 'exact', targets: Li
reasons = []
snippet = ""
# Normalise query key. If none or global/all/empty, search all
k_lower = (qkey or '').strip().lower()
if not k_lower or k_lower in ('global', 'all', 'any'):
# Determine which targets to test
if targets:
target_set = {t.lower() for t in targets}
else:
target_set = {'title', 'docid', 'breadcrumbs', 'authors', 'keywords', 'category', 'type', 'content'}
for spec in normalized_specs:
qk = spec['qkey']
qv = spec['qval']
m = spec['mode']
t = spec['targets']
# Single search box mode / global search:
# 1. Title
if 'title' in target_set:
for f in ['title', 'enhancedTitle', 'pageTitle']:
if value_matches(qval, fm.get(f)):
matched = True
reasons.append('Title')
break
# 2. DocID
if 'docid' in target_set:
if value_matches(qval, fm.get('docid')):
matched = True
reasons.append('DocID')
# 3. Breadcrumbs
if 'breadcrumbs' in target_set:
bcs = fm.get('breadcrumbs') or []
if isinstance(bcs, list) and bcs and isinstance(bcs[0], dict):
bcs_list = [d.get('name') or d.get('slug') or '' for d in bcs]
if not qv:
continue # skip empty queries
spec_matched = False
spec_reasons = []
spec_snippet = ""
k_lower = (qk or '').strip().lower()
if not k_lower or k_lower in ('global', 'all', 'any'):
# Determine which targets to test
if t:
target_set = {x.lower() for x in t}
else:
bcs_list = bcs
if '>' in qval:
query_parts = [p.strip() for p in qval.split('>') if p.strip()]
if match_breadcrumbs(bcs_list, query_parts):
matched = True
reasons.append('Breadcrumbs')
else:
if value_matches(qval, bcs_list):
matched = True
reasons.append('Breadcrumbs')
# 4. Authors
if 'authors' in target_set:
if value_matches(qval, fm.get('authors')):
matched = True
reasons.append('Authors')
# 5. PageKeywords
if 'keywords' in target_set or 'pagekeywords' in target_set:
if value_matches(qval, fm.get('pageKeywords')):
matched = True
reasons.append('Keywords')
# 6. Category
if 'category' in target_set:
if value_matches(qval, fm.get('category')):
matched = True
reasons.append('Category')
# 7. Type
if 'type' in target_set:
if value_matches(qval, fm.get('type')):
matched = True
reasons.append('Type')
# 8. Content
if 'content' in target_set:
if value_matches(qval, content):
matched = True
reasons.append('Content')
snippet = get_content_snippet(content, qval)
else:
# Specific key search
if k_lower == 'breadcrumbs':
bcs = fm.get('breadcrumbs') or []
if bcs and isinstance(bcs, list) and bcs and isinstance(bcs[0], dict):
bcs_list = [d.get('name') or d.get('slug') or '' for d in bcs]
else:
bcs_list = bcs
if '>' in qval:
query_parts = [p.strip() for p in qval.split('>') if p.strip()]
matched = match_breadcrumbs(bcs_list, query_parts)
else:
matched = value_matches(qval, bcs_list)
if matched:
reasons.append('Breadcrumbs')
elif k_lower == 'authors':
matched = value_matches(qval, fm.get('authors'))
if matched:
reasons.append('Authors')
elif k_lower == 'pagekeywords':
matched = value_matches(qval, fm.get('pageKeywords'))
if matched:
reasons.append('Keywords')
elif k_lower == 'content':
matched = value_matches(qval, content)
if matched:
reasons.append('Content')
snippet = get_content_snippet(content, qval)
elif k_lower in ('title', 'enhancedtitle', 'pagetitle'):
for f in ['title', 'enhancedTitle', 'pageTitle']:
if value_matches(qval, fm.get(f)):
matched = True
reasons.append('Title')
break
target_set = {'title', 'docid', 'breadcrumbs', 'authors', 'keywords', 'category', 'type', 'content'}
# 1. Title
if 'title' in target_set:
for f in ['title', 'enhancedTitle', 'pageTitle']:
if value_matches(qv, fm.get(f), m):
spec_matched = True
spec_reasons.append('Title')
break
# 2. DocID
if 'docid' in target_set:
if value_matches(qv, fm.get('docid'), m):
spec_matched = True
spec_reasons.append('DocID')
# 3. Breadcrumbs
if 'breadcrumbs' in target_set:
bcs = fm.get('breadcrumbs') or []
if isinstance(bcs, list) and bcs and isinstance(bcs[0], dict):
bcs_list = [d.get('name') or d.get('slug') or '' for d in bcs]
else:
bcs_list = bcs
if '>' in qv:
query_parts = [p.strip() for p in qv.split('>') if p.strip()]
if match_breadcrumbs(bcs_list, query_parts):
spec_matched = True
spec_reasons.append('Breadcrumbs')
else:
if value_matches(qv, bcs_list, m):
spec_matched = True
spec_reasons.append('Breadcrumbs')
# 4. Authors
if 'authors' in target_set:
if value_matches(qv, fm.get('authors'), m):
spec_matched = True
spec_reasons.append('Authors')
# 5. PageKeywords
if 'keywords' in target_set or 'pagekeywords' in target_set:
if value_matches(qv, fm.get('pageKeywords'), m):
spec_matched = True
spec_reasons.append('Keywords')
# 6. Category
if 'category' in target_set:
if value_matches(qv, fm.get('category'), m):
spec_matched = True
spec_reasons.append('Category')
# 7. Type
if 'type' in target_set:
if value_matches(qv, fm.get('type'), m):
spec_matched = True
spec_reasons.append('Type')
# 8. Content
if 'content' in target_set:
if value_matches(qv, content, m):
spec_matched = True
spec_reasons.append('Content')
spec_snippet = get_content_snippet(content, qv)
else:
matched = value_matches(qval, fm.get(qkey))
if matched:
reasons.append(qkey.capitalize())
# Specific key search
if k_lower == 'breadcrumbs':
bcs = fm.get('breadcrumbs') or []
if bcs and isinstance(bcs, list) and bcs and isinstance(bcs[0], dict):
bcs_list = [d.get('name') or d.get('slug') or '' for d in bcs]
else:
bcs_list = bcs
if '>' in qv:
query_parts = [p.strip() for p in qv.split('>') if p.strip()]
spec_matched = match_breadcrumbs(bcs_list, query_parts)
else:
spec_matched = value_matches(qv, bcs_list, m)
if spec_matched:
spec_reasons.append('Breadcrumbs')
elif k_lower == 'authors':
spec_matched = value_matches(qv, fm.get('authors'), m)
if spec_matched:
spec_reasons.append('Authors')
elif k_lower == 'pagekeywords':
spec_matched = value_matches(qv, fm.get('pageKeywords'), m)
if spec_matched:
spec_reasons.append('Keywords')
elif k_lower == 'content':
spec_matched = value_matches(qv, content, m)
if spec_matched:
spec_reasons.append('Content')
spec_snippet = get_content_snippet(content, qv)
elif k_lower in ('title', 'enhancedtitle', 'pagetitle'):
for f in ['title', 'enhancedTitle', 'pageTitle']:
if value_matches(qv, fm.get(f), m):
spec_matched = True
spec_reasons.append('Title')
break
else:
spec_matched = value_matches(qv, fm.get(qk), m)
if spec_matched:
spec_reasons.append(qk.capitalize())
if spec_matched:
matched = True
spec_reasons_clean = [str(x) for x in spec_reasons]
reasons.extend(spec_reasons_clean)
if spec_snippet and not snippet:
snippet = spec_snippet
if matched:
out.append({