From ea6a841aeee63801b8e3fdb200d1cf6984c09238 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Mon, 25 Sep 2023 01:44:45 +0200 Subject: [PATCH] Search with search_vector field. Use OR instead of AND --- .../commands/set_search_vector_field.py | 42 +++++++++-- lemarche/siaes/models.py | 22 ++++-- lemarche/templates/siaes/search_results.html | 71 +++++++++++++++---- lemarche/www/siaes/forms.py | 23 ++++-- 4 files changed, 127 insertions(+), 31 deletions(-) diff --git a/lemarche/siaes/management/commands/set_search_vector_field.py b/lemarche/siaes/management/commands/set_search_vector_field.py index 9291067af..1691048ce 100644 --- a/lemarche/siaes/management/commands/set_search_vector_field.py +++ b/lemarche/siaes/management/commands/set_search_vector_field.py @@ -1,4 +1,6 @@ from django.contrib.postgres.search import SearchVector +from django.db import models +from django.db.models import Value from lemarche.siaes.models import Siae from lemarche.utils.commands import BaseCommand @@ -13,22 +15,48 @@ class Command(BaseCommand): def handle(self, *args, **options): self.stdout_info("-" * 80) self.stdout_info("Reseting search_vector field...") - for siae in Siae.objects.all(): + progress = 0 + for siae in Siae.objects.prefetch_related("offers", "labels").all(): siae_search_vector = ( SearchVector( - "offers__name", + Value(siae.name, output_field=models.CharField()), # weight="A", - config="french", + # config="french", ) + SearchVector( - "description", + Value(siae.brand, output_field=models.CharField()), # weight="A", - config="french", + # config="french", + ) + + SearchVector( + Value(siae.kind, output_field=models.CharField()), + # weight="A", + # config="french", ) + SearchVector( - "labels__name", + Value(siae.description, output_field=models.CharField()), # weight="A", config="french", ) ) - Siae.objects.filter(id=siae.id).update(search_vector=siae_search_vector) + if siae.offers: + siae_search_vector += SearchVector( + Value( + " ".join(str(offer.name) for offer in siae.offers.all()), + ), + # weight="A", + config="french", + ) + if siae.labels: + siae_search_vector += SearchVector( + Value( + " ".join(str(label.name) for label in siae.labels.all()), + ), + # weight="A", + config="french", + ) + siae.search_vector = siae_search_vector + siae.save(update_fields=["search_vector"]) + progress += 1 + if (progress % 500) == 0: + print(f"{progress}...") diff --git a/lemarche/siaes/models.py b/lemarche/siaes/models.py index 7429a7def..7dbf79cef 100644 --- a/lemarche/siaes/models.py +++ b/lemarche/siaes/models.py @@ -7,8 +7,7 @@ from django.contrib.gis.measure import D from django.contrib.postgres.aggregates import ArrayAgg from django.contrib.postgres.indexes import GinIndex -from django.contrib.postgres.search import TrigramSimilarity # SearchVector -from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector, SearchVectorField +from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector, SearchVectorField, TrigramSimilarity from django.db import IntegrityError, models, transaction from django.db.models import BooleanField, Case, CharField, Count, F, IntegerField, PositiveIntegerField, Q, Sum, When from django.db.models.functions import Greatest, Round @@ -194,12 +193,25 @@ def filter_on_siret_or_name_or_brand(self, search_string): def filter_full_text(self, search_string): search_vector = ( - SearchVector("offers__name", config="french") + SearchVector("name") + + SearchVector("brand") + SearchVector("description", config="french") + + SearchVector("offers__name", config="french") + SearchVector("labels__name", config="french") ) - search_query = SearchQuery(search_string) - return self.annotate(rank=SearchRank(search_vector, search_query)).filter(rank__gte=0.3) + search_query = SearchQuery(search_string, config="french") + + return self.annotate(rank=SearchRank(search_vector, search_query)).filter(rank__gte=0.01) + + def filter_full_text_on_search_vector_field(self, search_string): + # SearchQuery uses 'AND' by default. Change to 'OR'. + search_string_list = search_string.split(" ") + filters = SearchQuery(search_string_list[0], config="french") + if len(search_string_list) > 1: + for search_term in search_string_list[1:]: + filters |= SearchQuery(search_term, config="french") + + return self.filter(search_vector=filters).annotate(rank=SearchRank(F("search_vector"), filters)) def filter_sectors(self, sectors): return self.filter(sectors__in=sectors) diff --git a/lemarche/templates/siaes/search_results.html b/lemarche/templates/siaes/search_results.html index ac5c61cba..ba397c3b9 100644 --- a/lemarche/templates/siaes/search_results.html +++ b/lemarche/templates/siaes/search_results.html @@ -55,13 +55,25 @@ + @@ -204,9 +216,37 @@
+ +
+
+ aria-labelledby="search-full-text-2-tab">
-
{% bootstrap_field form.search %}
+
{% bootstrap_field form.search_2 %}
@@ -420,9 +460,13 @@