evaluation
This commit is contained in:
parent
0a3d898b2c
commit
e4e5c77afb
File diff suppressed because it is too large
Load Diff
11916
evaluation/questions_before_ambiguity_cleanup.json
Normal file
11916
evaluation/questions_before_ambiguity_cleanup.json
Normal file
File diff suppressed because it is too large
Load Diff
12094
evaluation/questions_before_validation.json
Normal file
12094
evaluation/questions_before_validation.json
Normal file
File diff suppressed because it is too large
Load Diff
1060
evaluation/results/retrieval_results_dev.csv
Normal file
1060
evaluation/results/retrieval_results_dev.csv
Normal file
File diff suppressed because it is too large
Load Diff
35537
evaluation/results/retrieval_results_dev.json
Normal file
35537
evaluation/results/retrieval_results_dev.json
Normal file
File diff suppressed because it is too large
Load Diff
1105
evaluation/results/retrieval_results_dev_baseline.csv
Normal file
1105
evaluation/results/retrieval_results_dev_baseline.csv
Normal file
File diff suppressed because it is too large
Load Diff
37022
evaluation/results/retrieval_results_dev_baseline.json
Normal file
37022
evaluation/results/retrieval_results_dev_baseline.json
Normal file
File diff suppressed because it is too large
Load Diff
1060
evaluation/results/retrieval_results_dev_final.csv
Normal file
1060
evaluation/results/retrieval_results_dev_final.csv
Normal file
File diff suppressed because it is too large
Load Diff
35537
evaluation/results/retrieval_results_dev_final.json
Normal file
35537
evaluation/results/retrieval_results_dev_final.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,11 @@ WORD_RE = re.compile(
|
|||||||
re.UNICODE,
|
re.UNICODE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
QUOTED_PHRASE_RE = re.compile(
|
||||||
|
r'[„“”"]([^„“”"]+)[„“”"]',
|
||||||
|
re.UNICODE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
BM25_WEIGHTS = (
|
BM25_WEIGHTS = (
|
||||||
0.0,
|
0.0,
|
||||||
@ -45,6 +50,13 @@ FTS_RRF_WEIGHT = 1.0
|
|||||||
VECTOR_RRF_WEIGHT = 1.5
|
VECTOR_RRF_WEIGHT = 1.5
|
||||||
ANY_TERM_RRF_WEIGHT = 0.25
|
ANY_TERM_RRF_WEIGHT = 0.25
|
||||||
|
|
||||||
|
# Ak FTS kandidát obsahuje veľmi silný
|
||||||
|
# lexikálny signál, napríklad meno osoby
|
||||||
|
# alebo presný názov práce, nesmie byť
|
||||||
|
# potlačený iba embeddingovým výsledkom.
|
||||||
|
LEXICAL_ANCHOR_MIN_BONUS = 4.5
|
||||||
|
LEXICAL_ANCHOR_RRF_WEIGHT = 2.0
|
||||||
|
|
||||||
|
|
||||||
STRATEGY_PRIORITY = {
|
STRATEGY_PRIORITY = {
|
||||||
"all_terms": 3,
|
"all_terms": 3,
|
||||||
@ -104,6 +116,42 @@ def query_tokens(
|
|||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
|
def quoted_query_phrases(
|
||||||
|
query: str,
|
||||||
|
) -> list[str]:
|
||||||
|
phrases: list[str] = []
|
||||||
|
seen: set[str] = set()
|
||||||
|
|
||||||
|
for match in QUOTED_PHRASE_RE.finditer(
|
||||||
|
query
|
||||||
|
):
|
||||||
|
phrase = normalize_for_compare(
|
||||||
|
match.group(1)
|
||||||
|
)
|
||||||
|
|
||||||
|
if not phrase:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Jednoslovné výrazy ako "RAG"
|
||||||
|
# alebo "chatbot" sú príliš široké
|
||||||
|
# na silný lexikálny anchor.
|
||||||
|
if len(phrase.split()) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if phrase in seen:
|
||||||
|
continue
|
||||||
|
|
||||||
|
phrases.append(
|
||||||
|
phrase
|
||||||
|
)
|
||||||
|
|
||||||
|
seen.add(
|
||||||
|
phrase
|
||||||
|
)
|
||||||
|
|
||||||
|
return phrases
|
||||||
|
|
||||||
|
|
||||||
def quote_fts_token(
|
def quote_fts_token(
|
||||||
token: str,
|
token: str,
|
||||||
*,
|
*,
|
||||||
@ -633,6 +681,25 @@ def exact_match_bonus(
|
|||||||
|
|
||||||
bonus = 0.0
|
bonus = 0.0
|
||||||
|
|
||||||
|
# Pri otázkach typu:
|
||||||
|
#
|
||||||
|
# Kto sa venuje práci s názvom
|
||||||
|
# „Systém získavania informácií
|
||||||
|
# v slovenskom jazyku“?
|
||||||
|
#
|
||||||
|
# je celý názov práce veľmi silný
|
||||||
|
# lexikálny signál, aj keď title
|
||||||
|
# dokumentu je meno študenta.
|
||||||
|
for phrase in quoted_query_phrases(
|
||||||
|
query
|
||||||
|
):
|
||||||
|
if (
|
||||||
|
phrase in title
|
||||||
|
or phrase in text
|
||||||
|
):
|
||||||
|
bonus += 6.0
|
||||||
|
break
|
||||||
|
|
||||||
if title == normalized_query:
|
if title == normalized_query:
|
||||||
bonus += 6.0
|
bonus += 6.0
|
||||||
|
|
||||||
@ -781,9 +848,8 @@ def add_fts_metadata(
|
|||||||
-bm25_score,
|
-bm25_score,
|
||||||
)
|
)
|
||||||
|
|
||||||
score = (
|
match_bonus = (
|
||||||
base_score
|
exact_match_bonus(
|
||||||
+ exact_match_bonus(
|
|
||||||
query,
|
query,
|
||||||
item,
|
item,
|
||||||
tags,
|
tags,
|
||||||
@ -791,6 +857,11 @@ def add_fts_metadata(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
score = (
|
||||||
|
base_score
|
||||||
|
+ match_bonus
|
||||||
|
)
|
||||||
|
|
||||||
heading_paths = (
|
heading_paths = (
|
||||||
parse_heading_paths(
|
parse_heading_paths(
|
||||||
item
|
item
|
||||||
@ -943,6 +1014,49 @@ def add_vector_metadata(
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def lexical_bonus_from_fts_result(
|
||||||
|
item: dict[str, Any],
|
||||||
|
) -> float:
|
||||||
|
fts_score = item.get(
|
||||||
|
"score"
|
||||||
|
)
|
||||||
|
|
||||||
|
bm25_score = item.get(
|
||||||
|
"bm25_score"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
fts_score is None
|
||||||
|
or bm25_score is None
|
||||||
|
):
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
try:
|
||||||
|
score_value = float(
|
||||||
|
fts_score
|
||||||
|
)
|
||||||
|
|
||||||
|
bm25_value = float(
|
||||||
|
bm25_score
|
||||||
|
)
|
||||||
|
|
||||||
|
except (
|
||||||
|
TypeError,
|
||||||
|
ValueError,
|
||||||
|
):
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
base_score = max(
|
||||||
|
0.0,
|
||||||
|
-bm25_value,
|
||||||
|
)
|
||||||
|
|
||||||
|
return max(
|
||||||
|
0.0,
|
||||||
|
score_value - base_score,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def fuse_hybrid_results(
|
def fuse_hybrid_results(
|
||||||
fts_results: list[
|
fts_results: list[
|
||||||
dict[str, Any]
|
dict[str, Any]
|
||||||
@ -1002,6 +1116,33 @@ def fuse_hybrid_results(
|
|||||||
else FTS_RRF_WEIGHT
|
else FTS_RRF_WEIGHT
|
||||||
)
|
)
|
||||||
|
|
||||||
|
lexical_bonus = (
|
||||||
|
lexical_bonus_from_fts_result(
|
||||||
|
item
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Silný lexikálny anchor má prednosť
|
||||||
|
# pred čisto sémantickou podobnosťou.
|
||||||
|
#
|
||||||
|
# Typické prípady:
|
||||||
|
# - meno osoby je priamo title dokumentu,
|
||||||
|
# - názov práce je uvedený v úvodzovkách,
|
||||||
|
# - query obsahuje celý názov dokumentu.
|
||||||
|
#
|
||||||
|
# Toto rieši najmä situáciu, keď
|
||||||
|
# any_term FTS nájde správneho Bogdana
|
||||||
|
# na 1. mieste, ale pôvodná váha 0.25
|
||||||
|
# ho po RRF vytlačila mimo Top 5.
|
||||||
|
if (
|
||||||
|
lexical_bonus
|
||||||
|
>= LEXICAL_ANCHOR_MIN_BONUS
|
||||||
|
):
|
||||||
|
fts_weight = max(
|
||||||
|
fts_weight,
|
||||||
|
LEXICAL_ANCHOR_RRF_WEIGHT,
|
||||||
|
)
|
||||||
|
|
||||||
scores[
|
scores[
|
||||||
chunk_id
|
chunk_id
|
||||||
] += (
|
] += (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user