RkBlog

Hardware, programming and astronomy tutorials and reviews.

Django i Lupy

Wykorzystanie modułu lupy do implementacji prostej wyszukiwarki w aplikacjach Django. Lupy to moduł wzorowany na Lucene oferujący proste pełnotekstowe wyszukiwanie, obecnie już nie rozwijany

Lupy to pełnotekstowa wyszukiwarka napisana w Pythonie wzorowana na Lucene - pełnotekstowej wyszukiwarce napisanej w Javie. Obecnie projekt ten nie jest już rozwijany. Opis znajdziemy na starej stronie projektu, a pobrać możemy z mirrora Gentoo. Domyślnym zastosowaniem jest indeksowanie plików tekstowych, lecz równie łatwo można wykorzystać ją do indeksowania danych znajdujących się w bazie danych.

Tworzenie indeksu

Umieść poniższy kod w jakimś widoku:
# import
from lupy.indexer import Index
# tworzymy indeks "foobar", create True = nadpisuje
index = Index('foobar', create=True)

# pobieramy dane z bazy
pages = Page.objects.all()
for p in pages:
	#indeksujemy po kolei strony
	index.index(text=p.text, __title=p.title, _slug=p.slug)
index.optimize()
Dla modelu:
class Page(models.Model):
	title = models.CharField(maxlength=255) # page real title (for title tag and h1 in templates)
	slug = models.SlugField(maxlength=255, unique=True) # the wiki URL "title"
	description = models.CharField(maxlength=255) # short description (meta description, some link generation)
	text = models.TextField() # the page text
	changes = models.CharField(maxlength=255) # description of changes, no blanks!
	creation_date = models.DateTimeField(auto_now_add = True)
	modification_date = models.DateTimeField(auto_now = True)
	modification_user = models.CharField(maxlength=30)
	modification_ip = models.CharField(maxlength=20, blank=True)

Proste Wyszukiwanie

from lupy.indexer import Index
index = Index('foobar', create=False)
# fraza - python
hits = index.find('python')
for h in hits:
	# slug to nazwa podanego przy indeksowaniu pola
	print 'Znalezione w ', h.get('slug')


Prawdziwe wykorzystanie

Dla widoku dodawania stron wiki dodałem kod indeksujący dodawaną stronę. Kod indeksujący wstawiłem zaraz po zapisie danych w bazie danych (tj. wszystko zwalidowane):
if settings.WIKI_SEARCH_WITH_LUPY:
	from lupy.indexer import Index
	from os.path import isdir
	if isdir('diamandaSearchCache'):
		index = Index('diamandaSearchCache', create=False)
	else:
		index = Index('diamandaSearchCache', create=True)
	index.index(text=page_data['text'].decode("utf-8"), __title=page_data['title'].decode("utf-8"), __description=page_data['description'].decode("utf-8"), _slug=page_data['slug'])
	index.optimize()
Gdzie diamandaSearchCache to nazwa kesza Lupy dla wiki. Dodatkowo sprawdzam czy już istnieje czy nie sprawdzając obecność folderu o tej samej nazwie. "WIKI_SEARCH_WITH_LUPY" to zmienna w settings.py przyjmująca wartość True/False określająca czy używam Lupy czy nie.

Wyszukiwanie wyników jest nieco bardziej złożone - stosuję logiczne wyszukiwanie LUB dla każdego podanego we frazie wyrazu.
if data.has_key('lupy'):
	from lupy.index.term import Term
	from lupy.search.indexsearcher import IndexSearcher
	from lupy.search.term import TermQuery
	from lupy.search.boolean import BooleanQuery
	
	index =  IndexSearcher('diamandaSearchCache')
	query = data['string'].split(' ')
	q = BooleanQuery()
	if len(query) > 1:
		for a in query:
			t = Term('text', a.decode("utf-8"))
			tq = TermQuery(t)
			q.add(tq, False, False)
	else:
		t = Term('text', query[0].decode("utf-8"))
		tq = TermQuery(t)
		q.add(tq, True, False)
	hits = index.search(q)
	pages = []
	for h in hits:
		pages.append({'title': h.get('title'),'description': h.get('description'),'slug': h.get('slug')})
	pages.reverse()
	return render_to_response('wiki/' + settings.ENGINE + '/search.html', {'pages': pages, 'lupy': lupy, 'string': data['string'], 'google': google, 'lupyuse': True, 'theme': settings.THEME, 'engine': settings.ENGINE})
W formularzu wyszukiwania istnieje pole o nazwie lupy:
<input type="submit" value="{% trans "boolean OR search" %}" name="lupy" />
Po którym powyższy kod widoku orientuje się, który z trzech obecnie dostępnych sposobów wyszukiwania został użyty. Wyświetlanie wyników jest standardowe:
{% if lupyuse %}
	{% for page in pages %}
	<img src="/site_media/wiki/img/2.png" alt="" /> <a href="/wiki/page/{{ page.slug }}/">{{ page.title }}</a> - {{ page.description }}<br />
	{% endfor %}
{% endif %}
RkBlog

Django, 14 July 2008,

Comment article