updated search v2 with full text search

This commit is contained in:
smilerz
2021-04-21 14:42:10 -05:00
parent 64d7f71d86
commit d625e07bd7
2 changed files with 78 additions and 30 deletions

View File

@ -1,16 +1,34 @@
from datetime import datetime, timedelta
from functools import reduce
from django.contrib.postgres.search import TrigramSimilarity
from django.db.models import Q, Case, When, Value
from django.forms import IntegerField
from cookbook.models import ViewLog
from cookbook.models import Recipe
from recipes import settings
from django.contrib.postgres.aggregates import StringAgg
from django.contrib.postgres.search import (
SearchQuery, SearchRank, SearchVector, TrigramSimilarity,
)
from django.db import models
from django.db.models import Q
from django.utils import translation
def search_recipes(request, queryset, params):
search_string = params.get('query', '')
DICTIONARY = {
# TODO find custom dictionaries - maybe from here https://www.postgresql.org/message-id/CAF4Au4x6X_wSXFwsQYE8q5o0aQZANrvYjZJ8uOnsiHDnOVPPEg%40mail.gmail.com
# 'hy': 'Armenian',
# 'ca': 'Catalan',
# 'cs': 'Czech',
'nl': 'dutch',
'en': 'english',
'fr': 'french',
'de': 'german',
'it': 'italian',
# 'lv': 'Latvian',
'es': 'spanish',
}
def search_recipes(queryset, params):
search_string = params.get('query', '').strip()
search_keywords = params.getlist('keywords', [])
search_foods = params.getlist('foods', [])
search_books = params.getlist('books', [])
@ -23,20 +41,26 @@ def search_recipes(request, queryset, params):
search_random = params.get('random', False)
search_last_viewed = int(params.get('last_viewed', 0))
if search_last_viewed > 0:
last_viewed_recipes = ViewLog.objects.filter(created_by=request.user, space=request.space,
created_at__gte=datetime.now() - timedelta(days=14)).order_by('pk').values_list('recipe__pk', flat=True).distinct()
return queryset.filter(pk__in=last_viewed_recipes[len(last_viewed_recipes) - min(len(last_viewed_recipes), search_last_viewed):])
queryset = queryset.annotate(
new_recipe=Case(When(created_at__gte=(datetime.now() - timedelta(days=7)), then=Value(100)),
default=Value(0), )).order_by('-new_recipe', 'name')
if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2',
'django.db.backends.postgresql']:
queryset = queryset.annotate(similarity=TrigramSimilarity('name', search_string), ).filter(
Q(similarity__gt=0.1) | Q(name__unaccent__icontains=search_string)).order_by('-similarity')
if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2', 'django.db.backends.postgresql'] and search_string != '':
# queryset = queryset.annotate(similarity=TrigramSimilarity('name', search_string), )
# .filter(Q(similarity__gt=0.1) | Q(name__unaccent__icontains=search_string)).order_by('-similarity')
language = DICTIONARY.get(translation.get_language(), 'simple')
search_query = SearchQuery(
search_string,
config=language,
search_type="websearch"
)
search_vectors = (
SearchVector('search_vector')
+ SearchVector(StringAgg('steps__ingredients__food__name', delimiter=' '), weight='B', config=language)
+ SearchVector(StringAgg('keywords__name', delimiter=' '), weight='B', config=language))
search_rank = SearchRank(search_vectors, search_query)
queryset = (
queryset.annotate(
search=search_vectors,
rank=search_rank,)
.filter(Q(search=search_query))
.order_by('-rank'))
else:
queryset = queryset.filter(name__icontains=search_string)

View File

@ -3,6 +3,7 @@ from django.contrib.postgres.search import (
SearchQuery, SearchRank, SearchVector, TrigramSimilarity,
)
from django.db import models
from django.db.models import Q
from django.utils import translation
DICTIONARY = {
@ -27,21 +28,44 @@ class RecipeSearchManager(models.Manager):
def search(self, search_text, space):
language = DICTIONARY.get(translation.get_language(), 'simple')
search_query = SearchQuery(
search_text, config=language
search_text,
config=language,
search_type="websearch"
)
search_vectors = (
SearchVector('search_vector')
+ SearchVector(StringAgg('steps__ingredients__food__name', delimiter=' '), weight='B', config=language)
+ SearchVector(StringAgg('keywords__name', delimiter=' '), weight='B', config=language))
search_rank = SearchRank(search_vectors, search_query)
# the results from trigram were really, really bad
# trigram = (
# TrigramSimilarity('name', search_text)
# USING TRIGRAM BREAKS WEB SEARCH
# ADDING MULTIPLE TRIGRAMS CREATES DUPLICATE RESULTS
# DISTINCT NOT COMPAITBLE WITH ANNOTATE
# trigram_name = (TrigramSimilarity('name', search_text))
# trigram_description = (TrigramSimilarity('description', search_text))
# trigram_food = (TrigramSimilarity('steps__ingredients__food__name', search_text))
# trigram_keyword = (TrigramSimilarity('keywords__name', search_text))
# adding additional trigrams created duplicates
# + TrigramSimilarity('description', search_text)
# + TrigramSimilarity('steps__ingredients__food__name', search_text)
# + TrigramSimilarity('keywords__name', search_text))
# + TrigramSimilarity('keywords__name', search_text)
return (
self.get_queryset()
.annotate(search=search_vectors, rank=search_rank)
.filter(search=search_query)
.annotate(
search=search_vectors,
rank=search_rank,
#trigram=trigram_name+trigram_description+trigram_food+trigram_keyword
# trigram_name=trigram_name,
# trigram_description=trigram_description,
# trigram_food=trigram_food,
# trigram_keyword=trigram_keyword
)
.filter(
Q(search=search_query)
# | Q(trigram_name__gt=0.1)
# | Q(name__icontains=search_text)
# | Q(trigram_name__gt=0.2)
# | Q(trigram_description__gt=0.2)
# | Q(trigram_food__gt=0.2)
# | Q(trigram_keyword__gt=0.2)
)
.order_by('-rank'))