1212import whoosh .qparser
1313import whoosh .qparser .plugins
1414import whoosh .qparser .syntax
15+ import whoosh .qparser .taggers
1516import whoosh .query
1617
1718
@@ -55,10 +56,17 @@ def build_field(clause):
5556 yield clause .text
5657
5758
58- @handler (whoosh .query .And , whoosh .query .Or , whoosh .query .Not )
59+ @handler (whoosh .query .And , whoosh .query .Or , whoosh .query .Not ,
60+ whoosh .query .AndMaybe )
5961def build_grouper (clause ):
6062 yield "("
61- yield clause .__class__ .__name__ .lower ()
63+ # CloudSearch only supports 'and' and 'or' clauses; neither really fit
64+ # with the concept of "AndMaybe", which tries to "boost" results that
65+ # include the "Maybe" portion of the clause.
66+ if isinstance (clause , whoosh .query .AndMaybe ):
67+ yield "and"
68+ else :
69+ yield clause .__class__ .__name__ .lower ()
6270 for child_clause in clause .children ():
6371 yield " "
6472 for piece in walk_clause (child_clause ):
@@ -154,40 +162,46 @@ def modify_node(self, fieldname, node):
154162 return node
155163
156164
157- class PlusMinusPlugin (whoosh .qparser .plugins .PlusMinusPlugin ):
158- '''The default PlusMinus plugin doesn't respect the parser's
159- default grouping, instead blindly using "OR" groupings. This modified
160- version takes the parser's desired grouping into account
165+ class MinusPlugin (whoosh .qparser .plugins .Plugin ):
166+ '''This differs from whoosh's PlusMinusPlugin. The concept of "AndMaybe"
167+ isn't one that applies to CloudSearch, so "+" actions aren't needed.
168+ Additionally, the logic is simplified from the whoosh version to just
169+ swap out the nodes
161170 '''
162- def do_plusminus (self , parser , group ):
171+ class Minus (whoosh .qparser .syntax .MarkerNode ):
172+ pass
173+
174+ def __init__ (self , minusexpr = "-" ):
175+ self .minusexpr = minusexpr
176+
177+ def taggers (self , parser ):
178+ minus_tagger = whoosh .qparser .taggers .FnTagger (self .minusexpr ,
179+ self .Minus ,
180+ "minus" )
181+ return [(minus_tagger , 0 )]
182+
183+ def filters (self , parser ):
184+ return [(self .do_minus , 505 )]
185+
186+ def do_minus (self , parser , group ):
163187 '''This filter sorts nodes in a flat group into "required", "default",
164188 and "banned" subgroups based on the presence of plus and minus nodes.
165189 '''
166- required = whoosh .qparser .syntax .AndGroup ()
167- banned = whoosh .qparser .syntax .OrGroup ()
168- default = parser .group ()
169-
170- # Which group to put the next node we see into
171- next_ = default
190+ grouper = group .__class__ ()
191+
192+ next_not = None
172193 for node in group :
173- if isinstance (node , self .Plus ):
174- # +: put the next node in the required group
175- next_ = required
176- elif isinstance (node , self .Minus ):
177- # -: put the next node in the banned group
178- next_ = banned
194+ if isinstance (node , self .Minus ):
195+ # -: Replace with a NOT node
196+ next_not = whoosh .qparser .syntax .NotGroup ()
197+ grouper .append (next_not )
198+ elif next_not is not None :
199+ next_not .append (node )
200+ next_not = None
179201 else :
180- # Anything else: put it in the appropriate group
181- next_ .append (node )
182- # Reset to putting things in the optional group by default
183- next_ = default
184-
185- group = default
186- if required :
187- group = whoosh .qparser .syntax .AndMaybeGroup ([required , group ])
188- if banned :
189- group = whoosh .qparser .syntax .AndNotGroup ([group , banned ])
190- return group
202+ grouper .append (node )
203+
204+ return grouper
191205
192206
193207DEFAULT_PLUGINS = (
@@ -200,7 +214,7 @@ def do_plusminus(self, parser, group):
200214 whoosh .qparser .plugins .OperatorsPlugin (AndMaybe = None ,
201215 Require = None ),
202216 whoosh .qparser .plugins .EveryPlugin (),
203- PlusMinusPlugin (),
217+ MinusPlugin (),
204218 )
205219
206220
0 commit comments