Djapian: solução de search engine para seu projeto

Postado por Rafael Sierra em 25/08/2007

Voltando a ser "on-topic" dessa vez vou falar de um projeto que desenvolvi junto com os outros integrantes desse blog: Djapian

Esse projeto é um aplicativo que você pode incorporar à sua própria solução afim de permitir buscas nos textos, ele é essencial em aplicativos como: Wiki, Blog, CMS e todo tipo de projeto que envolva colaboração de usuários em informação.

Bom, vamos ao que interessa, que é como usar o Djapian.

Antes de mais nada instale o Xapian, suas bindings e o Djapian, um bom tutorial de como fazer isso pode ser encontrado aqui.

Não esqueça que você precisa do Django instalado também, aqui uso a versão 0.96.

Criaremos um projeto simples, só para exemplificar, com apenas um aplicativo e um modelo:


$ django-admin.py start app teste
$ cd teste
$ python manage.py startapp app

Agora edite o arquivo settings.py para configurar sua base de dados e colocar o aplicativo "teste.app" e o "djapian" na lista dos INSTALLED_APPS, no meu caso vou usar o sqlite mesmo pra não perder tempo no postgresql

Edite o arquivo teste/app/models.py e deixe-o da seguinte forma:
[python]
# -*- encoding: utf-8 -*-
'''
Esse arquivo é auto-explicativo com varios comentarios para facilitar o
entendimento de como funciona e o que significa cada parte do código

Algumas informações sobre o Xapian não explicitas aqui (como o que são prefixos)
podem ser encontrados em:

http://blog.stiod.com.br/?p=5
http://blog.stiod.com.br/?p=6

'''
from django.db import models

#
# O Change é o objeto que você deve criar sempre que ocorrer uma mudança no seu
# próprio objeto
#
from djapian.models import Change

#
# XapianIndexer é o objeto que usamos para fazer buscas e indexações
#
from djapian.backend.backends import XapianIndexer

#
# Esse é o modelo que vamos indexar
#
class Modelo(models.Model):
titulo = models.CharField(maxlength=100)
corpo = models.TextField()
#
# Esse modulo é usado pelo Change pra saber qual é a instancia do
# XapianIndexer que está sendo usada por esse modulo, talvez isso no futuro
# seja substituido por algo mais digno, como GenericRelation ou objeto
# estatico, veremos :)
#
index_model = 'teste.app.models.Modelo_index'

#
# Precisamos sobrescrever o metodo save pra que sempre que o objeto for
# gravado (seja um novo, ou apenas alterado) seja criado uma alteração na
# fila do Change
#
def save(self):
# Primeiro nós salvamos o objeto pra evitar perda de informação
super(Modelo, self).save()
#
# Depois criamos o objeto e informamos qual o modelo e ID e em seguida
# salvamos o objeto, isso tudo poderia ser uma linha só, como foi feito
# na função delete() logo abaixo
#
new_change = Change()
new_change.model = self.index_model
new_change.did = self.id
new_change.save()

#
# Da mesma forma que informamos que um objeto foi criado ou alterado,
# precisamos informar que um objeto foi removido, afinal, não queremos
# resultados "fantasmas"
#
def delete(self):
# Essa é a versão resumida do código usado na função save, com a
# resalva que no save não usamos o "is_deleted"
Change(did=self.id, model=self.index_model, is_deleted=True).save()
# Repare que agora nós deletamos *depois* de criar o Change, isso pra
# evitar perder o id deste objeto (ainda não testei deletar antes e ver
# o que acontece)
super(Test, self).delete()

#
# Aqui é a parte mais importante da indexação, onde definimos o que e onde
# iremos indexar
#
Modelo_index = XapianIndexer(
#
# Esse primeiro argumento define onde a base de dados do
# XAPIAN deve ser criada ou usada se já existir, NUNCA
# use o diretório /tmp sem a presença de um adulto isso
# pode (e irá) trazer graves consequencias ao seu
# projeto
#
'/tmp/db_modelo/',

#
# O segundo argumento especifica qual modelo deve ser
# indexado, isso permite que você tenha varias
# instancias do XapianIndexer, uma para cada modelo do
# seu aplicativo que precise ser indexado
#
Modelo,

#
# No terceiro argumento informamos quais serão os campos
# a serem indexados SEM prefixo
#
['Modelo.titulo', 'Modelo.corpo'],

#
# Por ultimo, mas, não menos importante vem os campos a
# serem indexados COM prefixo, o prefixo ser a chave do
# dicionário
#
{
'titulo':'Modelo.titulo',
}
)

[/python]

Isso é tudo que você precisa fazer para configurar seu projeto para rodar com o Djapian, depois disso basta rodar o aplicativo "run_djapian.py" que foi instalado durante a instalação do Djapian, mas note que você precisará exportar a variavel DJANGO_SETTINGS_MODULE para "teste.settings", bem como ter o diretório do projeto no seu PYTHONPATH.

Como o foco deste post é mostar o backend da busca, eu não vou fazer nenhuma view, vou apenas usar o proprio shell do python, considero também que você já rodou o `syncdb`, para esse teste eu também exportei a variável de ambiente XAPIAN_FLUSH_THRESHOLD[1] para 10:

[python]
from teste.app.models import Modelo
for x in xrange(100):
Modelo(titulo='titulo numero %d'%x, corpo = 'corpo numero %d'%x).save()

from teste.app.models import Modelo_index
resultados = Modelo_index.search('titulo')
len(resultados)
resultados = Modelo_index.search('titulo:10')
len(resultados)
for resultado in resultados:
print resultado.get_object()
[/python]

Bom, isso é só um exemplo do básico, existem mais funcionalidades (como um módulo de tratamento de texto e remoção de acentos) junto do Djapian, mas eu preciso de ajuda pra documentar e deixar o projeto com cara de "projeto", se você acha que pode ajudar, please, let me know, toda ajuda é bem vinda, assim como se você acha que pode melhorar alguma coisa ou mesmo já fez um patch pro Djapian me envie que eu posso te adicionar como contribuidor do projeto e aplicarei o patch no fonte.

[1] - A variável XAPIAN_FLUSH_THRESHOLD é usada pelo core do Xapian para saber de quantos em quantos documentos ele deve fazer o flush das informações para a base de dados, se ela não for exportada o padrão é 10000, mas use-a com moderação :P

3 Comentário para “Djapian: solução de search engine para seu projeto”

  1. joze fontes disse em 25/08/2007 as 15:20

    como faço um engine de busca em dw cara?
    nao to soluciunando nada!
    qem me da uma maozinha?

  2. Rafael "SDM" Sierra disse em 25/08/2007 as 15:37

    Joze, desculpe cara, eu não entendi sua pergunta, o que é esse “dw” na sua pergunta? O que exatamente você ta tentando fazer?

  3. Gadonski disse em 25/08/2007 as 11:59

    Como faz a busca em textos que contenham caracteres especiais?!

Trackback URI | RSS dos comentários

Deixe um comentário

Av. Conselheiro Nébias, 368A, Cj. 413
Vila Mathias - Santos - SP
Telefone: (13) 3345-4580

© 2008 - 2009 Stiod. Todos os direitos reservados.