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 pdcounter.models import Author as PDCounterAuthor, BookStub as PDCounterBook
14 from catalogue.views import JSONResponse
15 from search import Search, JVM, SearchResult
16 from lucene import StringReader
17 from suggest.forms import PublishingSuggestForm
18 from time import sleep
23 dictionary = enchant.Dict('pl_PL')
26 def match_word_re(word):
27 if 'sqlite' in settings.DATABASES['default']['ENGINE']:
28 return r"\b%s\b" % word
29 elif 'mysql' in settings.DATABASES['default']['ENGINE']:
30 return "[[:<:]]%s[[:>:]]" % word
33 def did_you_mean(query, tokens):
36 authors = Tag.objects.filter(category='author', name__iregex=match_word_re(t))
40 if not dictionary.check(t):
42 change_to = dictionary.suggest(t)[0].lower()
43 if change_to != t.lower():
51 for frm, to in change.items():
52 query = query.replace(frm, to)
57 JVM.attachCurrentThread()
64 while _search is False:
74 prefix = request.GET.get('term', '')
76 return JSONResponse([])
77 JVM.attachCurrentThread()
82 tags = request.GET.get('tags', '')
83 hint.tags(Tag.get_tag_list(tags))
87 # tagi beda ograniczac tutaj
88 # ale tagi moga byc na ksiazce i na fragmentach
89 # jezeli tagi dot tylko ksiazki, to wazne zeby te nowe byly w tej samej ksiazce
90 # jesli zas dotycza themes, to wazne, zeby byly w tym samym fragmencie.
92 tags = search.hint_tags(prefix, pdcounter=True)
93 books = search.hint_books(prefix)
97 if isinstance(tag, PDCounterAuthor):
98 if filter(lambda t: t.slug == tag.slug and t != tag, tags):
100 elif isinstance(tag, PDCounterBook):
101 if filter(lambda b: b.slug == tag.slug, tags):
105 tags = filter(lambda t: not is_dupe(t), tags)
107 def category_name(c):
108 if c.startswith('pd_'):
112 callback = request.GET.get('callback', None)
113 data = [{'label': t.name,
114 'category': category_name(t.category),
116 'url': t.get_absolute_url()}
119 'category': _('book'),
121 'url': b.get_absolute_url()}
124 return HttpResponse("%s(%s);" % (callback, json.dumps(data)),
125 content_type="application/json; charset=utf-8")
127 return JSONResponse(data)
133 JVM.attachCurrentThread() # where to put this?
139 query = request.GET.get('q','')
140 # book_id = request.GET.get('book', None)
142 # if book_id is not None:
143 # book = get_object_or_404(Book, id=book_id)
145 # hint = search.hint()
147 # tag_list = Tag.get_tag_list(tags)
152 return render_to_response('catalogue/search_too_short.html', {'prefix': query},
153 context_instance=RequestContext(request))
155 search = get_search()
156 # hint.tags(tag_list)
159 tags = search.hint_tags(query, pdcounter=True, prefix=False, fuzzy=fuzzy)
160 tags = split_tags(tags)
162 toks = StringReader(query)
165 author_results = search.search_phrase(toks, 'authors', fuzzy=fuzzy, tokens_cache=tokens_cache)
166 title_results = search.search_phrase(toks, 'title', fuzzy=fuzzy, tokens_cache=tokens_cache)
168 # Boost main author/title results with mixed search, and save some of its results for end of list.
169 # boost author, title results
170 author_title_mixed = search.search_some(toks, ['authors', 'title', 'tags'], fuzzy=fuzzy, tokens_cache=tokens_cache)
171 author_title_rest = []
172 for b in author_title_mixed:
173 bks = filter(lambda ba: ba.book_id == b.book_id, author_results + title_results)
177 author_title_rest.append(b)
179 # Do a phrase search but a term search as well - this can give us better snippets then search_everywhere,
180 # Because the query is using only one field.
181 text_phrase = SearchResult.aggregate(
182 search.search_phrase(toks, 'content', fuzzy=fuzzy, tokens_cache=tokens_cache, snippets=True, book=False, slop=4),
183 search.search_some(toks, ['content'], tokens_cache=tokens_cache, snippets=True, book=False))
185 everywhere = search.search_everywhere(toks, fuzzy=fuzzy, tokens_cache=tokens_cache)
187 def already_found(results):
190 if e.book_id == r.book_id:
196 f = already_found(author_results + title_results + text_phrase)
197 everywhere = filter(lambda x: not f(x), everywhere)
199 author_results = SearchResult.aggregate(author_results)
200 title_results = SearchResult.aggregate(title_results)
202 everywhere = SearchResult.aggregate(everywhere, author_title_rest)
204 for res in [author_results, title_results, text_phrase, everywhere]:
205 res.sort(reverse=True)
208 h['snippets'] = map(lambda s:
209 re.subn(r"(^[ \t\n]+|[ \t\n]+$)", u"",
210 re.subn(r"[ \t\n]*\n[ \t\n]*", u"\n", s)[0])[0], h['snippets'])
212 suggestion = did_you_mean(query, search.get_tokens(toks, field="SIMPLE"))
214 def ensure_exists(r):
217 except Book.DoesNotExist:
220 author_results = filter(ensure_exists, author_results)
221 title_results = filter(ensure_exists, title_results)
222 text_phrase = filter(ensure_exists, text_phrase)
223 everywhere = filter(ensure_exists, everywhere)
225 results = author_results + title_results + text_phrase + everywhere
226 # ensure books do exists & sort them
227 results.sort(reverse=True)
229 if len(results) == 1:
230 fragment_hits = filter(lambda h: 'fragment' in h, results[0].hits)
231 if len(fragment_hits) == 1:
232 #anchor = fragment_hits[0]['fragment']
233 #frag = Fragment.objects.get(anchor=anchor)
234 return HttpResponseRedirect(fragment_hits[0]['fragment'].get_absolute_url())
235 return HttpResponseRedirect(results[0].book.get_absolute_url())
236 elif len(results) == 0:
237 form = PublishingSuggestForm(initial={"books": query + ", "})
238 return render_to_response('catalogue/search_no_hits.html',
242 'did_you_mean': suggestion},
243 context_instance=RequestContext(request))
245 return render_to_response('catalogue/search_multiple_hits.html',
248 'results': { 'author': author_results,
249 'title': title_results,
250 'content': text_phrase,
251 'other': everywhere},
252 'did_you_mean': suggestion},
253 context_instance=RequestContext(request))