Author: peter
Date: Tue Mar 5 13:25:37 2013
New Revision: 1452789
URL: http://svn.apache.org/r1452789
Log:
#421 Add meta keywords support for searching ($resolve, $notresolved, $ticket,
$wiki, $milestone)
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/query_parser.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.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=1452789&r1=1452788&r2=1452789&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py Tue Mar 5
13:25:37 2013
@@ -208,6 +208,14 @@ class IQueryPreprocessor(Interface):
def query_pre_process(query_parameters):
"""Process query parameters"""
+
+class IMetaKeywordParser(Interface):
+ """Extension point for custom meta keywords."""
+
+ def match(text):
+ """If text matches the keyword, return its transformed value."""
+
+
class BloodhoundSearchApi(Component):
"""Implements core indexing functionality, provides methods for
searching, adding and deleting documents from index.
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=1452789&r1=1452788&r2=1452789&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/query_parser.py
(original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/query_parser.py Tue
Mar 5 13:25:37 2013
@@ -20,12 +20,57 @@
r"""Provides Bloodhound Search query parsing functionality"""
-from bhsearch.api import IQueryParser
+from bhsearch.api import IQueryParser, IMetaKeywordParser, ISearchParticipant
from bhsearch.whoosh_backend import WhooshBackend
+from trac.config import ExtensionPoint
from trac.core import Component, implements
-from whoosh import query
+from whoosh import query, qparser
from whoosh.qparser import MultifieldParser
+
+class MetaKeywordNode(qparser.GroupNode):
+ def __init__(self, group_node=None, **kwargs):
+ nodes = group_node.nodes if group_node else []
+ super(MetaKeywordNode, self).__init__(nodes, kwargs=kwargs)
+
+
+class MetaKeywordPlugin(qparser.TaggingPlugin):
+ priority = 0
+ expr = r"[$](?P<text>[^ \t\r\n]+)(?= |$|\))"
+ nodetype = qparser.syntax.WordNode
+
+ def __init__(self, meta_keyword_parsers=()):
+ super(MetaKeywordPlugin, self).__init__()
+ self.meta_keyword_parsers = meta_keyword_parsers
+
+ def match(self, parser, text, pos):
+ match = qparser.TaggingPlugin.match(self, parser, text, pos)
+ if match is None:
+ return
+
+ candidate = match.text
+ for meta_keyword_parser in self.meta_keyword_parsers:
+ expanded_meta_keyword = meta_keyword_parser.match(candidate)
+ if expanded_meta_keyword is not None:
+ node = MetaKeywordNode(parser.tag(expanded_meta_keyword))
+ return node.set_range(match.startchar, match.endchar)
+
+ def filters(self, parser):
+ # must execute before GroupPlugin with priority 0
+ return [(self.unroll_meta_keyword_nodes, -100)]
+
+ def unroll_meta_keyword_nodes(self, parser, group):
+ newgroup = group.empty_copy()
+ for node in group:
+ if isinstance(node, MetaKeywordNode):
+ newgroup.extend(self.unroll_meta_keyword_nodes(parser, node))
+ elif isinstance(node, qparser.GroupNode):
+ newgroup.append(self.unroll_meta_keyword_nodes(parser, node))
+ else:
+ newgroup.append(node)
+ return newgroup
+
+
class DefaultQueryParser(Component):
implements(IQueryParser)
@@ -43,11 +88,19 @@ class DefaultQueryParser(Component):
content = 1,
changes = 1,
)
- parser = MultifieldParser(
- field_boosts.keys(),
- WhooshBackend.SCHEMA,
- fieldboosts=field_boosts
- )
+
+ 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):
query_string = query_string.strip()
@@ -70,4 +123,33 @@ class DefaultQueryParser(Component):
return query.And(parsed_filters).normalize()
def _parse_filter(self, filter):
- return self.parse(unicode(filter))
\ No newline at end of file
+ return self.parse(unicode(filter))
+
+
+class DocTypeMetaKeywordParser(Component):
+ implements(IMetaKeywordParser)
+
+ search_participants = ExtensionPoint(ISearchParticipant)
+
+ def match(self, text):
+ documents = [p.get_participant_type()
+ for p in self.search_participants]
+ if text in documents:
+ return u'type:%s' % text
+
+
+class ResolvedMetaKeywordParser(Component):
+ implements(IMetaKeywordParser)
+
+ def match(self, text):
+ if text == u'resolved':
+ return u'status:(resolved OR closed)'
+
+
+class UnResolvedMetaKeywordParser(Component):
+ implements(IMetaKeywordParser)
+
+ def match(self, text):
+ if text == u'unresolved':
+ return u'NOT $resolved'
+
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=1452789&r1=1452788&r2=1452789&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py
(original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py Tue
Mar 5 13:25:37 2013
@@ -19,7 +19,7 @@
# under the License.
import unittest
from bhsearch.tests import (whoosh_backend, index_with_whoosh, web_ui,
- api)
+ api, query_parser)
from bhsearch.tests.search_resources import (ticket_search, wiki_search,
milestone_search, base)