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.fields import dumps
14 from catalogue.views import JSONResponse
15 from search import Search, JVM, SearchResult
16 from lucene import StringReader
17 from suggest.forms import PublishingSuggestForm
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)
54 JVM.attachCurrentThread()
59 prefix = request.GET.get('term', '')
61 return JSONResponse([])
62 JVM.attachCurrentThread()
66 tags = request.GET.get('tags', '')
67 hint.tags(Tag.get_tag_list(tags))
71 # tagi beda ograniczac tutaj
72 # ale tagi moga byc na ksiazce i na fragmentach
73 # jezeli tagi dot tylko ksiazki, to wazne zeby te nowe byly w tej samej ksiazce
74 # jesli zas dotycza themes, to wazne, zeby byly w tym samym fragmencie.
76 tags = search.hint_tags(prefix, pdcounter=True)
77 books = search.hint_books(prefix)
80 if c.startswith('pd_'):
86 'category': category_name(t.category),
88 'url': t.get_absolute_url()}
91 'category': _('book'),
93 'url': b.get_absolute_url()}
99 JVM.attachCurrentThread() # where to put this?
105 query = request.GET.get('q','')
106 # book_id = request.GET.get('book', None)
108 # if book_id is not None:
109 # book = get_object_or_404(Book, id=book_id)
111 # hint = search.hint()
113 # tag_list = Tag.get_tag_list(tags)
118 return render_to_response('catalogue/search_too_short.html', {'prefix': query},
119 context_instance=RequestContext(request))
121 # hint.tags(tag_list)
124 tags = search.hint_tags(query, pdcounter=True, prefix=False, fuzzy=fuzzy)
125 tags = split_tags(tags)
127 toks = StringReader(query)
130 author_results = search.search_phrase(toks, 'authors', fuzzy=fuzzy, tokens_cache=tokens_cache)
131 title_results = search.search_phrase(toks, 'title', fuzzy=fuzzy, tokens_cache=tokens_cache)
133 # Boost main author/title results with mixed search, and save some of its results for end of list.
134 # boost author, title results
135 author_title_mixed = search.search_some(toks, ['authors', 'title', 'tags'], fuzzy=fuzzy, tokens_cache=tokens_cache)
136 author_title_rest = []
137 for b in author_title_mixed:
138 bks = filter(lambda ba: ba.book_id == b.book_id, author_results + title_results)
142 author_title_rest.append(b)
144 # Do a phrase search but a term search as well - this can give us better snippets then search_everywhere,
145 # Because the query is using only one field.
146 text_phrase = SearchResult.aggregate(
147 search.search_phrase(toks, 'content', fuzzy=fuzzy, tokens_cache=tokens_cache, snippets=True, book=False, slop=4),
148 search.search_some(toks, ['content'], tokens_cache=tokens_cache, snippets=True, book=False))
150 everywhere = search.search_everywhere(toks, fuzzy=fuzzy, tokens_cache=tokens_cache)
152 def already_found(results):
155 if e.book_id == r.book_id:
161 f = already_found(author_results + title_results + text_phrase)
162 everywhere = filter(lambda x: not f(x), everywhere)
164 author_results = SearchResult.aggregate(author_results)
165 title_results = SearchResult.aggregate(title_results)
167 everywhere = SearchResult.aggregate(everywhere, author_title_rest)
169 for res in [author_results, title_results, text_phrase, everywhere]:
170 res.sort(reverse=True)
173 h['snippets'] = map(lambda s:
174 re.subn(r"(^[ \t\n]+|[ \t\n]+$)", u"",
175 re.subn(r"[ \t\n]*\n[ \t\n]*", u"\n", s)[0])[0], h['snippets'])
177 suggestion = did_you_mean(query, search.get_tokens(toks, field="SIMPLE"))
179 def ensure_exists(r):
182 except Book.DoesNotExist:
185 author_results = filter(ensure_exists, author_results)
186 title_results = filter(ensure_exists, title_results)
187 text_phrase = filter(ensure_exists, text_phrase)
188 everywhere = filter(ensure_exists, everywhere)
190 results = author_results + title_results + text_phrase + everywhere
191 # ensure books do exists & sort them
192 results.sort(reverse=True)
194 if len(results) == 1:
195 fragment_hits = filter(lambda h: 'fragment' in h, results[0].hits)
196 if len(fragment_hits) == 1:
197 #anchor = fragment_hits[0]['fragment']
198 #frag = Fragment.objects.get(anchor=anchor)
199 return HttpResponseRedirect(fragment_hits[0]['fragment'].get_absolute_url())
200 return HttpResponseRedirect(results[0].book.get_absolute_url())
201 elif len(results) == 0:
202 form = PublishingSuggestForm(initial={"books": query + ", "})
203 return render_to_response('catalogue/search_no_hits.html',
207 'did_you_mean': suggestion},
208 context_instance=RequestContext(request))
210 return render_to_response('catalogue/search_multiple_hits.html',
213 'results': { 'author': author_results,
214 'title': title_results,
215 'content': text_phrase,
216 'other': everywhere},
217 'did_you_mean': suggestion},
218 context_instance=RequestContext(request))