1 # -*- coding: utf-8 -*-
3 from django.conf import settings
4 from django.shortcuts import render_to_response, get_object_or_404
5 from django.template import RequestContext
6 from django.contrib.auth.decorators import login_required
7 from django.views.decorators import cache
8 from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponsePermanentRedirect
9 from django.utils.translation import ugettext as _
11 from catalogue.utils import split_tags
12 from catalogue.models import Book, Tag, Fragment
13 from catalogue.views import JSONResponse
14 from search import Search, JVM, SearchResult
15 from lucene import StringReader
16 from suggest.forms import PublishingSuggestForm
17 from time import sleep
21 dictionary = enchant.Dict('pl_PL')
24 def match_word_re(word):
25 if 'sqlite' in settings.DATABASES['default']['ENGINE']:
26 return r"\b%s\b" % word
27 elif 'mysql' in settings.DATABASES['default']['ENGINE']:
28 return "[[:<:]]%s[[:>:]]" % word
31 def did_you_mean(query, tokens):
34 authors = Tag.objects.filter(category='author', name__iregex=match_word_re(t))
38 if not dictionary.check(t):
40 change_to = dictionary.suggest(t)[0].lower()
41 if change_to != t.lower():
49 for frm, to in change.items():
50 query = query.replace(frm, to)
55 JVM.attachCurrentThread()
62 while _search is False:
72 prefix = request.GET.get('term', '')
74 return JSONResponse([])
75 JVM.attachCurrentThread()
80 tags = request.GET.get('tags', '')
81 hint.tags(Tag.get_tag_list(tags))
85 # tagi beda ograniczac tutaj
86 # ale tagi moga byc na ksiazce i na fragmentach
87 # jezeli tagi dot tylko ksiazki, to wazne zeby te nowe byly w tej samej ksiazce
88 # jesli zas dotycza themes, to wazne, zeby byly w tym samym fragmencie.
90 tags = search.hint_tags(prefix, pdcounter=True)
91 books = search.hint_books(prefix)
94 if c.startswith('pd_'):
100 'category': category_name(t.category),
102 'url': t.get_absolute_url()}
105 'category': _('book'),
107 'url': b.get_absolute_url()}
113 JVM.attachCurrentThread() # where to put this?
119 query = request.GET.get('q','')
120 # book_id = request.GET.get('book', None)
122 # if book_id is not None:
123 # book = get_object_or_404(Book, id=book_id)
125 # hint = search.hint()
127 # tag_list = Tag.get_tag_list(tags)
132 return render_to_response('catalogue/search_too_short.html', {'prefix': query},
133 context_instance=RequestContext(request))
135 search = get_search()
136 # hint.tags(tag_list)
139 tags = search.hint_tags(query, pdcounter=True, prefix=False, fuzzy=fuzzy)
140 tags = split_tags(tags)
142 toks = StringReader(query)
145 author_results = search.search_phrase(toks, 'authors', fuzzy=fuzzy, tokens_cache=tokens_cache)
146 title_results = search.search_phrase(toks, 'title', fuzzy=fuzzy, tokens_cache=tokens_cache)
148 # Boost main author/title results with mixed search, and save some of its results for end of list.
149 # boost author, title results
150 author_title_mixed = search.search_some(toks, ['authors', 'title', 'tags'], fuzzy=fuzzy, tokens_cache=tokens_cache)
151 author_title_rest = []
152 for b in author_title_mixed:
153 bks = filter(lambda ba: ba.book_id == b.book_id, author_results + title_results)
157 author_title_rest.append(b)
159 # Do a phrase search but a term search as well - this can give us better snippets then search_everywhere,
160 # Because the query is using only one field.
161 text_phrase = SearchResult.aggregate(
162 search.search_phrase(toks, 'content', fuzzy=fuzzy, tokens_cache=tokens_cache, snippets=True, book=False, slop=4),
163 search.search_some(toks, ['content'], tokens_cache=tokens_cache, snippets=True, book=False))
165 everywhere = search.search_everywhere(toks, fuzzy=fuzzy, tokens_cache=tokens_cache)
167 def already_found(results):
170 if e.book_id == r.book_id:
176 f = already_found(author_results + title_results + text_phrase)
177 everywhere = filter(lambda x: not f(x), everywhere)
179 author_results = SearchResult.aggregate(author_results)
180 title_results = SearchResult.aggregate(title_results)
182 everywhere = SearchResult.aggregate(everywhere, author_title_rest)
184 for res in [author_results, title_results, text_phrase, everywhere]:
185 res.sort(reverse=True)
188 h['snippets'] = map(lambda s:
189 re.subn(r"(^[ \t\n]+|[ \t\n]+$)", u"",
190 re.subn(r"[ \t\n]*\n[ \t\n]*", u"\n", s)[0])[0], h['snippets'])
192 suggestion = did_you_mean(query, search.get_tokens(toks, field="SIMPLE"))
194 def ensure_exists(r):
197 except Book.DoesNotExist:
200 author_results = filter(ensure_exists, author_results)
201 title_results = filter(ensure_exists, title_results)
202 text_phrase = filter(ensure_exists, text_phrase)
203 everywhere = filter(ensure_exists, everywhere)
205 results = author_results + title_results + text_phrase + everywhere
206 # ensure books do exists & sort them
207 results.sort(reverse=True)
209 if len(results) == 1:
210 fragment_hits = filter(lambda h: 'fragment' in h, results[0].hits)
211 if len(fragment_hits) == 1:
212 #anchor = fragment_hits[0]['fragment']
213 #frag = Fragment.objects.get(anchor=anchor)
214 return HttpResponseRedirect(fragment_hits[0]['fragment'].get_absolute_url())
215 return HttpResponseRedirect(results[0].book.get_absolute_url())
216 elif len(results) == 0:
217 form = PublishingSuggestForm(initial={"books": query + ", "})
218 return render_to_response('catalogue/search_no_hits.html',
222 'did_you_mean': suggestion},
223 context_instance=RequestContext(request))
225 return render_to_response('catalogue/search_multiple_hits.html',
228 'results': { 'author': author_results,
229 'title': title_results,
230 'content': text_phrase,
231 'other': everywhere},
232 'did_you_mean': suggestion},
233 context_instance=RequestContext(request))