Preserve cross-field search matching
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
## Не выпущено
|
||||
|
||||
- Backend обновлён до `0.10.3`: запрос о налоге на прибыль поднимает действующий
|
||||
Налоговый кодекс; релевантность текста и названия оценивается раздельно.
|
||||
Налоговый кодекс; точное совпадение фразы дополнительно усиливает результат.
|
||||
- Backend обновлён до `0.10.2`: действующие документы ранжируются выше, а
|
||||
утратившие силу — после остальных; из лаборатории удалён пустой блок фрагмента.
|
||||
- Backend обновлён до `0.10.1`: поисковая выдача по регистрации больше не
|
||||
|
||||
@@ -100,17 +100,22 @@ def tax_profit_clauses(language: str, query: str) -> list[dict]:
|
||||
def build_search_query(language: str, query: str) -> dict:
|
||||
registration_clauses = company_registration_clauses(language, query)
|
||||
intent_clauses = [*registration_clauses, *tax_profit_clauses(language, query)]
|
||||
operator = "OR" if registration_clauses else "AND"
|
||||
full_text = [
|
||||
clause
|
||||
{
|
||||
"multi_match": {
|
||||
"query": variant,
|
||||
"fields": [f"document_name_{language}^4", f"text_{language}"],
|
||||
"type": "cross_fields",
|
||||
"operator": "OR" if registration_clauses else "AND",
|
||||
}
|
||||
}
|
||||
for variant in query_variants(language, query)
|
||||
for clause in (
|
||||
{"match": {f"text_{language}": {"query": variant, "operator": operator}}},
|
||||
{"match": {f"document_name_{language}": {"query": variant, "operator": operator, "boost": 4}}},
|
||||
{"match_phrase": {f"text_{language}": {"query": variant, "boost": 3}}},
|
||||
)
|
||||
]
|
||||
planned = {"should": [*full_text, *intent_clauses], "minimum_should_match": 1}
|
||||
phrase_matches = [
|
||||
{"match_phrase": {f"text_{language}": {"query": variant, "boost": 3}}}
|
||||
for variant in query_variants(language, query)
|
||||
]
|
||||
planned = {"should": [*full_text, *phrase_matches, *intent_clauses], "minimum_should_match": 1}
|
||||
return {"bool": planned}
|
||||
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class SearchApiTest(unittest.TestCase):
|
||||
self.assertEqual(planned["minimum_should_match"], 1)
|
||||
self.assertNotIn("filter", planned)
|
||||
self.assertTrue(any("constant_score" in clause for clause in planned["should"]))
|
||||
self.assertTrue(any("общество с ограниченной ответственностью" in clause.get("match", {}).get("text_ru", {}).get("query", "") for clause in planned["should"]))
|
||||
self.assertTrue(any("общество с ограниченной ответственностью" in clause.get("multi_match", {}).get("query", "") for clause in planned["should"]))
|
||||
|
||||
def test_production_api_boosts_tax_code_for_profit_tax_query(self):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
|
||||
@@ -38,7 +38,9 @@ class SearchRelevanceTest(unittest.TestCase):
|
||||
self.assertFalse(body["track_total_hits"])
|
||||
self.assertEqual(body["collapse"], {"field": "document_code"})
|
||||
self.assertIn({"term": {"is_current_edition": True}}, body["query"]["bool"]["filter"])
|
||||
lexical_query = body["query"]["bool"]["must"]["bool"]["should"][0]["match"]["text_ru"]
|
||||
lexical_query = body["query"]["bool"]["must"]["bool"]["should"][0]["multi_match"]
|
||||
self.assertEqual(lexical_query["type"], "cross_fields")
|
||||
self.assertEqual(lexical_query["fields"], ["document_name_ru^4", "text_ru"])
|
||||
self.assertEqual(lexical_query["operator"], "AND")
|
||||
self.assertTrue(any("match_phrase" in clause for clause in body["query"]["bool"]["must"]["bool"]["should"]))
|
||||
|
||||
@@ -56,8 +58,8 @@ class SearchRelevanceTest(unittest.TestCase):
|
||||
search_query = body["query"]["bool"]["must"]["bool"]
|
||||
self.assertEqual(search_query["minimum_should_match"], 1)
|
||||
self.assertNotIn("filter", search_query)
|
||||
lexical = [clause["match"] for clause in search_query["should"] if "match" in clause]
|
||||
self.assertTrue(all(next(iter(clause.values()))["operator"] == "OR" for clause in lexical))
|
||||
lexical = [clause["multi_match"] for clause in search_query["should"] if "multi_match" in clause]
|
||||
self.assertTrue(all(clause["type"] == "cross_fields" and clause["operator"] == "OR" for clause in lexical))
|
||||
boosts = [clause["constant_score"] for clause in search_query["should"] if "constant_score" in clause]
|
||||
self.assertEqual([item["boost"] for item in boosts], [boost for _, boost in COMPANY_REGISTRATION_DOCUMENTS])
|
||||
self.assertEqual(
|
||||
|
||||
Reference in New Issue
Block a user