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:
- Instale django haystack usando pip, por exemplo, pip install django-haystack
- Instale whoosh usando pip, por exemplo, pip install whoosh
- Adicione palheiro ao INSTALLED_APPS.
- 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_index
cron
./manage.py update_index
--age=<num_hours>
RealtimeSignalProcessor
update_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ê.