search.py
113 lines
| 4.5 KiB
| text/x-python
|
PythonLexer
r406 | #!/usr/bin/env python | |||
# encoding: utf-8 | ||||
# search controller for pylons | ||||
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> | ||||
# | ||||
# This program is free software; you can redistribute it and/or | ||||
# modify it under the terms of the GNU General Public License | ||||
# as published by the Free Software Foundation; version 2 | ||||
# of the License or (at your opinion) any later version of the license. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU General Public License | ||||
# along with this program; if not, write to the Free Software | ||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||||
# MA 02110-1301, USA. | ||||
""" | ||||
Created on Aug 7, 2010 | ||||
search controller for pylons | ||||
@author: marcink | ||||
""" | ||||
from pylons import request, response, session, tmpl_context as c, url | ||||
from pylons.controllers.util import abort, redirect | ||||
from pylons_app.lib.auth import LoginRequired | ||||
from pylons_app.lib.base import BaseController, render | ||||
r410 | from pylons_app.lib.indexers import ANALYZER, IDX_LOCATION, SCHEMA, IDX_NAME | |||
r406 | from webhelpers.html.builder import escape | |||
from whoosh.highlight import highlight, SimpleFragmenter, HtmlFormatter, \ | ||||
ContextFragmenter | ||||
r410 | from pylons.i18n.translation import _ | |||
r406 | from whoosh.index import open_dir, EmptyIndexError | |||
from whoosh.qparser import QueryParser, QueryParserError | ||||
from whoosh.query import Phrase | ||||
import logging | ||||
import traceback | ||||
log = logging.getLogger(__name__) | ||||
class SearchController(BaseController): | ||||
@LoginRequired() | ||||
def __before__(self): | ||||
super(SearchController, self).__before__() | ||||
def index(self): | ||||
c.formated_results = [] | ||||
c.runtime = '' | ||||
search_items = set() | ||||
c.cur_query = request.GET.get('q', None) | ||||
if c.cur_query: | ||||
cur_query = c.cur_query.lower() | ||||
if c.cur_query: | ||||
try: | ||||
r410 | idx = open_dir(IDX_LOCATION, indexname=IDX_NAME) | |||
r406 | searcher = idx.searcher() | |||
qp = QueryParser("content", schema=SCHEMA) | ||||
try: | ||||
query = qp.parse(unicode(cur_query)) | ||||
if isinstance(query, Phrase): | ||||
search_items.update(query.words) | ||||
else: | ||||
for i in query.all_terms(): | ||||
search_items.add(i[1]) | ||||
log.debug(query) | ||||
log.debug(search_items) | ||||
results = searcher.search(query) | ||||
c.runtime = '%s results (%.3f seconds)' \ | ||||
% (len(results), results.runtime) | ||||
analyzer = ANALYZER | ||||
formatter = HtmlFormatter('span', | ||||
between='\n<span class="break">...</span>\n') | ||||
#how the parts are splitted within the same text part | ||||
fragmenter = SimpleFragmenter(200) | ||||
#fragmenter = ContextFragmenter(search_items) | ||||
for res in results: | ||||
d = {} | ||||
d.update(res) | ||||
hl = highlight(escape(res['content']), search_items, | ||||
analyzer=analyzer, | ||||
fragmenter=fragmenter, | ||||
formatter=formatter, | ||||
top=5) | ||||
f_path = res['path'][res['path'].find(res['repository']) \ | ||||
+ len(res['repository']):].lstrip('/') | ||||
d.update({'content_short':hl, | ||||
'f_path':f_path}) | ||||
#del d['content'] | ||||
c.formated_results.append(d) | ||||
except QueryParserError: | ||||
r410 | c.runtime = _('Invalid search query. Try quoting it.') | |||
r406 | ||||
except (EmptyIndexError, IOError): | ||||
log.error(traceback.format_exc()) | ||||
log.error('Empty Index data') | ||||
r410 | c.runtime = _('There is no index to search in. Please run whoosh indexer') | |||
r406 | ||||
# Return a rendered template | ||||
return render('/search/search.html') | ||||