Como adicionar pesquisa de texto completo no Django?

Introdução:

Adicionamos uma funcionalidade de texto completo em um de nossos produtos recentemente usando palheiro django. Usamos o whoosh como mecanismo de busca para testar coisas e pensei que poderia ser útil para outras pessoas. Haystack fornece pesquisa modular para Django. Ele apresenta uma API unificada e familiar que permite que você conecte diferentes back-ends de pesquisa (como Solr, Elasticsearch, Whoosh, Xapian, etc.) sem ter que modificar seu código.

Aqui estão as etapas para começar:

  1. Instale django haystack usando pip, por exemplo, pip install django-haystack
  2. Instale whoosh usando pip, por exemplo, pip install whoosh
  3. Adicione palheiro ao INSTALLED_APPS.
  4. Crie arquivos search_indexes.py para seus modelos.

Mais informações sobre configuração podem ser encontradas aqui em http://django-haystack.readthedocs.org/en/latest/tutorial.html#configuration

O search_index.py contém a classe de índice para o modelo de mensagem (no qual a pesquisa é necessária).

from haystack import indexes


class Message_forumIndex(indexes.SearchIndex, indexes.Indexable):
text
= indexes.EdgeNgramField(document=True, use_template=True)
message
= indexes.CharField(model_attr='message', null=True)
forum_id
= indexes.IntegerField(null=True)
status
= indexes.IntegerField(model_attr='status', null=True)
tags
= indexes.CharField(model_attr='tags', null=True)
message_date
= indexes.DateTimeField(null=True)
message_thread_id
= indexes.IntegerField(null=True)

def get_model(self):
return Message_forum

def index_queryset(self, using=None):
return self.get_model().objects.all()

def prepare_forum_id(self, obj):
return obj.forum.id

def prepare_status(self, obj):
return obj.status

def prepare_message_date(self, obj):
return obj.message.date

def prepare_tags(self, obj):
return [tag.tag for tag in obj.tags.all()]

def prepare_message_thread_id(self, obj):
if obj.message.thread is not None:
return obj.message.thread.id
else:
return -1

Haystack é compatível com pesquisa baseada em texto completo. Para isso, podemos definir um dos campos na classe de índice com document=true. Isso nos permite usar um modelo de dados para construir o documento que o mecanismo de pesquisa usará na pesquisa. Eu criei um modelo chamado ‘message forum text.txt’ com o conteúdo abaixo.

{{ object.forum.id }}
{{ object.tags.tag }}
{{ object.message.date }}
{{ object.message_thread_id }}

Como etapa final, precisamos construir dados de índice. Para um novo começo, pode-se executar o comando, ele irá construir novos dados de índice que seriam usados ​​posteriormente pelo palheiro para fins de pesquisa. Idealmente, devemos criar um trabalho em um intervalo específico (usando reduz o número de coisas para atualizar). Alternativamente, para aplicativos de baixo tráfego, pode ser usado o que tratará automaticamente as atualizações / exclusões para você. Eu tenho o comando cron para nosso aplicativo../manage.py rebuild_indexcron./manage.py update_index--age=<num_hours>RealtimeSignalProcessorupdate_index

Como fazer pesquisa?
Podemos definir os modelos de django de pesquisa onde podemos fazer a pesquisa. Mas, em nosso caso, nosso front-end está em uma pilha de tecnologia diferente, então precisei criar uma função separada que pesquisa e retorna dados fornecendo vários critérios de consulta. O pequeno snippet é fornecido abaixo:

#narrow down search to set of specific forums only..
results
= SearchQuerySet().filter(SQ(forum_id__in=['1','2'))

#filtering messages for selected status..
filts
= []
selected_status
= "completed, draft".split(",")

if len(selected_status) > 0:
status_cond
= SQ()

#appending status filters
if len(selected_status) > 0:
status_cond
|= SQ(status__in=selected_status)
filts
.append(status_cond)

#you can add more filters based on your need here

#applying filters
for filt in filts:
results
= results.filter(filt)

# Optionally you can add pagination support on results resultset object.

paginator
= Paginator(results, 10)
# Make sure page request is an int. If not, deliver first page.
try:
page
= int(page)
except ValueError:
page
= 1

try:
messages
= paginator.page(page)
except (EmptyPage, InvalidPage):
messages
= paginator.page(paginator.num_pages)

Espero que este seja você.