Author: peter
Date: Wed Mar 13 09:14:01 2013
New Revision: 1455845
URL: http://svn.apache.org/r1455845
Log:
#421 - search metakeywords $me and $my
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/query_parser.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/templates/bhsearch.html
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/query_parser.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py?rev=1455845&r1=1455844&r2=1455845&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py Wed Mar 13
09:14:01 2013
@@ -186,7 +186,7 @@ class IQueryParser(Interface):
"""Extension point for Bloodhound Search query parser.
"""
- def parse(query_string):
+ def parse(query_string, context):
"""Parse query from string"""
def parse_filters(filters):
@@ -219,7 +219,7 @@ class IQueryPreprocessor(Interface):
class IMetaKeywordParser(Interface):
"""Extension point for custom meta keywords."""
- def match(text):
+ def match(text, context):
"""If text matches the keyword, return its transformed value."""
@@ -255,7 +255,8 @@ class BloodhoundSearchApi(Component):
pagenum = 1,
pagelen = 20,
highlight = False,
- highlight_fields = None):
+ highlight_fields = None,
+ context = None):
"""Return query result from an underlying search backend.
Arguments:
@@ -271,12 +272,13 @@ class BloodhoundSearchApi(Component):
:param pagelen: paging support
:param highlight: highlight matched terms in fields
:param highlight_fields: list of fields to highlight
+ :param context: request context
:return: result QueryResult
"""
self.env.log.debug("Receive query request: %s", locals())
- parsed_query = self.parser.parse(query)
+ parsed_query = self.parser.parse(query, context)
parsed_filters = self.parser.parse_filters(filter)
# TODO: add query parsers and meta keywords post-parsing
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/query_parser.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/query_parser.py?rev=1455845&r1=1455844&r2=1455845&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/query_parser.py
(original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/query_parser.py Wed
Mar 13 09:14:01 2013
@@ -39,9 +39,10 @@ class MetaKeywordPlugin(qparser.TaggingP
expr = r"[$](?P<text>[^ \t\r\n]+)(?= |$|\))"
nodetype = qparser.syntax.WordNode
- def __init__(self, meta_keyword_parsers=()):
+ def __init__(self, meta_keyword_parsers=(), context=None):
super(MetaKeywordPlugin, self).__init__()
self.meta_keyword_parsers = meta_keyword_parsers
+ self.context = context
def match(self, parser, text, pos):
match = qparser.TaggingPlugin.match(self, parser, text, pos)
@@ -50,7 +51,8 @@ class MetaKeywordPlugin(qparser.TaggingP
candidate = match.text
for meta_keyword_parser in self.meta_keyword_parsers:
- expanded_meta_keyword = meta_keyword_parser.match(candidate)
+ expanded_meta_keyword = meta_keyword_parser.match(candidate,
+ self.context)
if expanded_meta_keyword is not None:
node = MetaKeywordNode(parser.tag(expanded_meta_keyword))
return node.set_range(match.startchar, match.endchar)
@@ -91,28 +93,13 @@ class DefaultQueryParser(Component):
meta_keyword_parsers = ExtensionPoint(IMetaKeywordParser)
- def __init__(self):
- super(DefaultQueryParser, self).__init__()
- self.parser = MultifieldParser(
- self.field_boosts.keys(),
- WhooshBackend.SCHEMA,
- fieldboosts=self.field_boosts
- )
- self.parser.add_plugin(
- MetaKeywordPlugin(meta_keyword_parsers=self.meta_keyword_parsers)
- )
-
- def parse(self, query_string):
+ def parse(self, query_string, context=None):
+ parser = self._create_parser(context)
query_string = query_string.strip()
-
if query_string == "" or query_string == "*" or query_string == "*:*":
return query.Every()
-
query_string = unicode(query_string)
- parsed_query = self.parser.parse(query_string)
-
- #todo: impalement pluggable mechanism for query post processing
- #e.g. meta keyword replacement etc.
+ parsed_query = parser.parse(query_string)
return parsed_query
def parse_filters(self, filters):
@@ -125,13 +112,25 @@ class DefaultQueryParser(Component):
def _parse_filter(self, filter):
return self.parse(unicode(filter))
+ def _create_parser(self, context):
+ parser = MultifieldParser(
+ self.field_boosts.keys(),
+ WhooshBackend.SCHEMA,
+ fieldboosts=self.field_boosts
+ )
+ parser.add_plugin(
+ MetaKeywordPlugin(meta_keyword_parsers=self.meta_keyword_parsers,
+ context=context)
+ )
+ return parser
+
class DocTypeMetaKeywordParser(Component):
implements(IMetaKeywordParser)
search_participants = ExtensionPoint(ISearchParticipant)
- def match(self, text):
+ def match(self, text, context):
documents = [p.get_participant_type()
for p in self.search_participants]
if text in documents:
@@ -141,7 +140,7 @@ class DocTypeMetaKeywordParser(Component
class ResolvedMetaKeywordParser(Component):
implements(IMetaKeywordParser)
- def match(self, text):
+ def match(self, text, context):
if text == u'resolved':
return u'status:(resolved OR closed)'
@@ -149,7 +148,23 @@ class ResolvedMetaKeywordParser(Componen
class UnResolvedMetaKeywordParser(Component):
implements(IMetaKeywordParser)
- def match(self, text):
+ def match(self, text, context):
if text == u'unresolved':
return u'NOT $resolved'
+
+class MeMetaKeywordParser(Component):
+ implements(IMetaKeywordParser)
+
+ def match(self, text, context):
+ if text == u'me':
+ username = unicode(context.req.authname)
+ return username
+
+
+class MyMetaKeywordParser(Component):
+ implements(IMetaKeywordParser)
+
+ def match(self, text, context):
+ if text == u'my':
+ return u'owner:$me'
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py?rev=1455845&r1=1455844&r2=1455845&view=diff
==============================================================================
---
incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py
(original)
+++
incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py
Wed Mar 13 09:14:01 2013
@@ -39,6 +39,7 @@ class TicketFields(IndexFields):
KEYWORDS = "keywords"
RESOLUTION = "resolution"
CHANGES = 'changes'
+ OWNER = 'owner'
class TicketIndexer(BaseIndexer):
implements(ITicketChangeListener, IIndexParticipant)
@@ -52,6 +53,7 @@ class TicketIndexer(BaseIndexer):
'status': TicketFields.STATUS,
'resolution': TicketFields.RESOLUTION,
'reporter': TicketFields.AUTHOR,
+ 'owner': TicketFields.OWNER,
}
def __init__(self):
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/templates/bhsearch.html
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/templates/bhsearch.html?rev=1455845&r1=1455844&r2=1455845&view=diff
==============================================================================
---
incubator/bloodhound/trunk/bloodhound_search/bhsearch/templates/bhsearch.html
(original)
+++
incubator/bloodhound/trunk/bloodhound_search/bhsearch/templates/bhsearch.html
Wed Mar 13 09:14:01 2013
@@ -182,7 +182,6 @@
</div>
</div>
-
<div class="span12"
py:if="query and not (results or quickjump)">
<p id="notfound" class="alert">
@@ -190,6 +189,12 @@
</p>
</div>
+ <div py:if="debug.enabled" class="span12">
+ <p>DEBUG INFO:
+ <pre>${pprint(debug)}</pre>
+ </p>
+ </div>
+
<div id="help" class="help-block pull-right" i18n:msg="">
<strong>Note:</strong> See <a
href="${href.wiki('BloodhoundSearch')}">BloodhoundSearch</a>
for help on searching.
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py?rev=1455845&r1=1455844&r2=1455845&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py
(original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py Wed
Mar 13 09:14:01 2013
@@ -29,6 +29,7 @@ def suite():
test_suite.addTest(whoosh_backend.suite())
test_suite.addTest(web_ui.suite())
test_suite.addTest(api.suite())
+ test_suite.addTest(query_parser.suite())
test_suite.addTest(ticket_search.suite())
test_suite.addTest(wiki_search.suite())
test_suite.addTest(milestone_search.suite())
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/query_parser.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/query_parser.py?rev=1455845&r1=1455844&r2=1455845&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/query_parser.py
(original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/query_parser.py
Wed Mar 13 09:14:01 2013
@@ -69,6 +69,26 @@ class MetaKeywordsParsingTestCase(BaseBl
)
]))
+ def test_can_parse_keyword_me(self):
+ context = self._mock_context_with_username('username')
+
+ parsed_query = self.parser.parse("author:$me", context)
+
+ self.assertEqual(parsed_query, terms.Term('author', 'username'))
+
+ def test_can_parse_keyword_my(self):
+ context = self._mock_context_with_username('username')
+
+ parsed_query = self.parser.parse("$my", context)
+
+ self.assertEqual(parsed_query, terms.Term('owner', 'username'))
+
+ def _mock_context_with_username(self, username):
+ class context:
+ class req:
+ authname = username
+ return context
+
def suite():
test_suite = unittest.TestSuite()
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py?rev=1455845&r1=1455844&r2=1455845&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py
(original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py Wed
Mar 13 09:14:01 2013
@@ -140,8 +140,8 @@ class WebUiTestCaseWithWhoosh(BaseBloodh
#act
data = self.process_request()
#assert
- active_type = data["active_type"]
- self.assertEquals("ticket", active_type)
+ extra_search_options = dict(data["extra_search_fields"])
+ self.assertEquals("ticket", extra_search_options['type'])
resource_types = data["types"]
@@ -513,7 +513,8 @@ class WebUiTestCaseWithWhoosh(BaseBloodh
self.req.args[RequestParameters.VIEW] = "grid"
data = self.process_request()
#assert
- self.assertEqual("grid", data["active_view"])
+ extra_search_options = dict(data["extra_search_fields"])
+ self.assertEqual("grid", extra_search_options["view"])
def test_can_apply_sorting(self):
#arrange
@@ -585,9 +586,9 @@ class WebUiTestCaseWithWhoosh(BaseBloodh
data = self.process_request()
#assert
- active_sort = data["active_sort"]
- self.assertEquals("id, time desc", active_sort["expression"])
- self.assertNotIn("sort=", active_sort["href"])
+ extra_search_options = dict(data["extra_search_fields"])
+ self.assertEquals("id, time desc", extra_search_options["sort"])
+ #self.assertNotIn("sort=", active_sort["href"])
def test_that_document_summary_contains_highlighted_search_terms(self):
term = "searchterm"
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py?rev=1455845&r1=1455844&r2=1455845&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py Wed Mar 13
09:14:01 2013
@@ -60,6 +60,7 @@ class RequestParameters(object):
FILTER_QUERY = "fq"
VIEW = "view"
SORT = "sort"
+ DEBUG = "debug"
def __init__(self, req):
self.req = req
@@ -85,6 +86,7 @@ class RequestParameters(object):
DEFAULT_RESULTS_PER_PAGE))
self.page = int(req.args.getfirst(self.PAGE, '1'))
self.type = req.args.getfirst(self.TYPE)
+ self.debug = int(req.args.getfirst(self.DEBUG, '0'))
self.params = {
RequestParameters.FILTER_QUERY: []
@@ -106,6 +108,8 @@ class RequestParameters(object):
self.params[RequestParameters.FILTER_QUERY] = self.filter_queries
if self.sort_string:
self.params[RequestParameters.SORT] = self.sort_string
+ if self.debug:
+ self.params[RequestParameters.DEBUG] = self.debug
def _parse_sort(self, sort_string):
if not sort_string:
@@ -284,6 +288,7 @@ class BloodhoundSearchModule(Component):
facets=request_context.facets,
filter=request_context.query_filter,
highlight=True,
+ context=request_context,
)
request_context.process_results(query_result)
@@ -649,6 +654,9 @@ class RequestContext(object):
self._prepare_result_facet_counts(query_result.facets)
self._prepare_breadcrumbs_template()
self.data[self.DATA_DEBUG] = query_result.debug
+ if self.parameters.debug:
+ self.data[self.DATA_DEBUG]['enabled'] = True
+ self.data[self.DATA_SEARCH_EXTRAS].append(('debug', '1'))
self.data[self.DATA_PAGE_HREF] = self.parameters.create_href()
def _prepare_result_facet_counts(self, result_facets):
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py?rev=1455845&r1=1455844&r2=1455845&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py
(original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py Wed
Mar 13 09:14:01 2013
@@ -69,7 +69,9 @@ class WhooshBackend(Component):
content=TEXT(stored=True,
analyzer=analysis.StandardAnalyzer(stoplist=None)),
changes=TEXT(analyzer=analysis.StandardAnalyzer(stoplist=None)),
- )
+ owner=TEXT(stored=True,
+ analyzer=analysis.SimpleAnalyzer()),
+ )
max_fragment_size = IntOption('bhsearch', 'max_fragment_size', 240,
'The maximum number of characters allowed in a '
@@ -224,6 +226,11 @@ class WhooshBackend(Component):
fields,
highlight_fields,
query_parameters)
+ try:
+ results.debug['actual_query'] =
unicode(query.simplify(searcher))
+ except TypeError:
+ # Simplify has a bug that causes it to fail sometimes.
+ pass
return results
def _workaround_join_query_and_filter(