sql >> Base de Datos >  >> RDS >> PostgreSQL

Combine trigram con búsqueda clasificada en django 1.10

Investigamos más a fondo cómo funciona la búsqueda de pesos.

Según documentos se le pueden asignar pesos de acuerdo a los campos e incluso se les pueden asignar pesos, y de manera similar podemos usar trigramas para filtrar por similitud o distancia.

Sin embargo no especifica un ejemplo de uso de los dos e investigando más a fondo no entendió mucho como funcionan las pesas.

Un poco de lógica nos dice que si buscamos una palabra común en todos todos vamos a rangos 0, la similitud varía mucho más que los rangos, sin embargo tiende a bajar los valores de ese rango.

Ahora bien, la búsqueda de texto, según entendemos, se realiza en base al texto contenido en los campos que se quieren filtrar incluso más que en el idioma que se coloque en la configuración. Ejemplo es que poniendo títulos, el modelo utilizado tenía un campo de título y un campo de contenido, cuyas palabras más comunes eran how change , revisando palabras ponderadas (los rangos funcionan como consulta, por lo que podemos usar values o values_list para revisar los rangos y similitudes, que son valores numéricos, podemos ver palabras ponderadas viendo objeto vectorial), vimos que si se asignaron pesos, pero combinaciones de palabras divididas:encontramos 'perfil' y 'cambi', sin embargo no encontramos 'cambiar' o 'como'; sin embargo, todos los modelos habían contenido el mismo texto como 'lorem ipsun...', y todas las palabras de esa oración si estaban enteras y con pesos B; Concluimos con esto que las búsquedas se realizan en base al contenido de los campos para filtrar más allá del idioma con el que configuramos las búsquedas.

Dicho esto, aquí presentamos el código que usamos para todo.

Primero, necesitamos usar Trigrams en la medida necesaria para habilitar la base de datos:

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

class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

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

    ]

Operaciones de importación para la migración desde postgres paquetes y ejecutar desde cualquier archivo de migración.

El siguiente paso es cambiar el código de la pregunta para que el filtro devuelva una de las consultas si falla la segunda:

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_query
            ) + TrigramSimilarity(
              'content', search_query
            ),
        ).filter(Q(rank__gte=0.3) | Q(similarity__gt=0.3)).order_by('-rank')[:20]

El problema con el código anterior era filtrar una consulta tras otra, y si la palabra elegida no aparecía en ninguna de las dos búsquedas el problema es mayor. Usamos una Q objeto a filtrar usando un OR conector para que si uno de los dos no devuelve un valor deseado, envíe el otro en su lugar.

Con esto es suficiente, no obstante son bienvenidas aclaraciones en profundidad sobre cómo funcionan estos pesos y trigramas, para explitar al máximo esta nueva ventaja que ofrece la última versión de Django.