2016-06-16 14 views
7

Lavoriamo con la ricerca in django 1.10 e abbiamo bisogno di una ricerca con classificazione utente con ricerca trigramma.Combina il trigramma con la ricerca classificata in django 1.10

Il nostro codice è questo:

def get_queryset(self): 
     search = self.request.GET.get('text', '') 
     vector = SearchVector('name',weight='A', 
      config=settings.SEARCH_LANGS[ 
       settings.LANGUAGE 
      ], 
      ) + SearchVector(
      'content', 
      weight='B', 
      config=settings.SEARCH_LANGS[ 
       settings.LANGUAGE 
      ], 
      ) 
     query = SearchQuery(search) 
     return Article.objects.annotate(
      rank=SearchRank(
       vector, 
       query 
       ), 
      similarity=TrigramSimilarity(
       'name', search 
       ) + TrigramSimilarity(
       'content', search 
       ), 
      ).filter(
      rank__gte=0.3 
      ).filter(
      similarity__gt=0.3 
      ).order_by(
      '-similarity' 
      )[:20] 

Ma questo codice non restituisce qualsiasi richiesta, senza l'uso trigram problemi che abbiamo Haven, ma, in combinazione tra loro non possiamo ottenere una query.

Come possiamo combinare il trigramma e la ricerca classificata in django 1.10?

risposta

10

Abbiamo studiato in modo più approfondito il modo in cui la ricerca funziona con i pesi.

Secondo documents è possibile assegnare pesi in base ai campi e possono anche essere assegnati pesi, e allo stesso modo si può usare trigrams per filtrare per similarità o distanza.

Tuttavia, non specificare un esempio di utilizzo dei due e di indagare ulteriormente, né tanto meno come funzionano i pesi.

Un po 'di logica ci dice che se cerchiamo una parola comune in tutti noi tutti i gradi 0, la somiglianza varia molto di più degli intervalli, tuttavia tende a valori più bassi che variano.

Ora, la ricerca di testo, per quanto ne sappiamo, viene eseguita in base al testo contenuto nei campi che si desidera filtrare ancor più che nella lingua che viene inserita nella configurazione. L'esempio è che mettendo i titoli, il modello usato aveva un campo titolo e un campo contenuto, le cui parole più comuni erano how change, rivedendo parole ponderate (gli intervalli funzionano come query, quindi possiamo usare values o values_list per rivedere i ranghi e le somiglianze, che sono valori numerici, possiamo vedere le parole ponderate che guardano oggetto vettoriale), abbiamo visto che se i pesi venivano assegnati, ma le combinazioni di parole suddivise: trovato 'perfil' e 'cambi', tuttavia non abbiamo trovato 'cambiar' o 'como' ; tuttavia, tutti i modelli contenevano lo stesso testo di "lorem ipsun ..." e tutte le parole di quella frase se erano complete e con i pesi B; Concludiamo dicendo che le ricerche vengono eseguite in base al contenuto dei campi per filtrare più della lingua con cui configuriamo le ricerche.

Detto questo, qui vi presentiamo il codice che usiamo per tutto.

In primo luogo, abbiamo bisogno di usare trigrammi nella misura necessaria per abilitare il database: operazioni

from __future__ import unicode_literals 

from django.db import migrations, models 
import django.db.models.deletion 
from django.contrib.postgres.operations import UnaccentExtension 
from django.contrib.postgres.operations import TrigramExtension 

class Migration(migrations.Migration): 

    initial = True 

    dependencies = [ 
    ] 

    operations = [ 
     ... 
     TrigramExtension(), 
     UnaccentExtension(), 

    ] 

Importa per la migrazione da postgres pacchetti ed eseguire la migrazione da qualsiasi file.

Il passo successivo è quello di modificare il codice della questione in modo che il filtro restituisce uno dei querys se il secondo fallisce:

def get_queryset(self): 
     search_query = SearchQuery(self.request.GET.get('q', '')) 

     vector = SearchVector(
      'name', 
      weight='A', 
      config=settings.SEARCH_LANGS[settings.LANGUAGE_CODE], 
     ) + SearchVector(
      'content', 
      weight='B', 
      config=settings.SEARCH_LANGS[settings.LANGUAGE_CODE], 
     ) 

     if self.request.user.is_authenticated: 
      queryset = Article.actives.all() 
     else: 
      queryset = Article.publics.all() 

     return queryset.annotate(
      rank=SearchRank(vector, search_query) 
      similarity=TrigramSimilarity(
       'name', search 
      ) + TrigramSimilarity(
       'content', search 
      ), 
     ).filter(Q(rank__gte=0.3) | Q(similarity__gt=0.3)).order_by('-rank')[:20] 

Il problema con il codice di cui sopra filtrava una query dopo l'altro, e se la parola scelta non appare in nessuna delle due ricerche il problema è maggiore. Utilizziamo un oggetto Q per filtrare utilizzando un connettore OR in modo che se uno dei due non restituisce un valore desiderato, inviare l'altro sul posto.

Con questo è sufficiente, tuttavia sono graditi chiarimenti approfonditi su come funzionano questi pesi e trigrammi, per sfruttare al meglio questo nuovo vantaggio offerto dall'ultima versione di Django.

+0

Grazie per aver condiviso la soluzione trovata. – Private

Problemi correlati