@@ -65,17 +65,36 @@ def filter_reporttime(s, filter):
65
65
if not filter .get ('reporttime' ):
66
66
return s
67
67
68
- c = filter .pop ('reporttime' )
69
- if PYVERSION == 2 :
70
- if type (c ) == unicode :
71
- c = str (c )
68
+ high = 'now/m'
69
+ # if passed 'days' or 'hours', preferentially use that for ES filtering/caching
70
+ if filter .get ('days' ) or filter .get ('hours' ):
71
+ if filter .get ('hours' ):
72
+ lookback_amount = filter .pop ('hours' )
73
+ lookback_unit = 'h'
74
+ elif filter .get ('days' ):
75
+ lookback_amount = filter .pop ('days' )
76
+ lookback_unit = 'd'
77
+
78
+ try :
79
+ lookback_amount = int (lookback_amount )
80
+ except Exception as e :
81
+ raise InvalidSearch ('Lookback time filter {}{} is not a valid time' .format (lookback_amount , lookback_unit ))
82
+
83
+ # don't put spaces in relative date math operator query to make it easier to read. ES hates that and will error.
84
+ low = 'now/m-{}{}' .format (lookback_amount , lookback_unit )
85
+ # no relative 'days' or 'hours' params, so fallback to 'reporttime'
86
+ else :
87
+ c = filter .pop ('reporttime' )
88
+ if PYVERSION == 2 :
89
+ if type (c ) == unicode :
90
+ c = str (c )
72
91
73
- low , high = c , arrow .utcnow ()
74
- if isinstance (c , basestring ) and ',' in c :
75
- low , high = c .split (',' )
92
+ if isinstance (c , basestring ) and ',' in c :
93
+ low , high = c .split (',' )
94
+ else :
95
+ low = c
76
96
77
- low = arrow .get (low ).datetime
78
- high = arrow .get (high ).datetime
97
+ low = arrow .get (low ).datetime
79
98
80
99
s = s .filter ('range' , reporttime = {'gte' : low , 'lte' : high })
81
100
return s
@@ -114,7 +133,7 @@ def filter_indicator(s, q_filters):
114
133
115
134
def filter_terms (s , q_filters ):
116
135
for f in q_filters :
117
- if f in ['nolog' , 'days' , 'hours' , 'groups' , 'limit' , 'tags' ]:
136
+ if f in ['nolog' , 'days' , 'hours' , 'groups' , 'limit' , 'provider' , 'reporttime' , ' tags' ]:
118
137
continue
119
138
120
139
kwargs = {f : q_filters [f ]}
@@ -127,16 +146,70 @@ def filter_terms(s, q_filters):
127
146
128
147
129
148
def filter_tags (s , q_filters ):
130
- tags = q_filters ['tags' ]
149
+ if not q_filters .get ('tags' ):
150
+ return s
151
+
152
+ tags = q_filters .pop ('tags' )
131
153
132
154
if isinstance (tags , basestring ):
133
- tags = tags .split (',' )
155
+ tags = [ x . strip () for x in tags .split (',' )]
134
156
157
+ # each array element is implicitly ORed (aka, 'should') using a terms filter
158
+ #s = s.filter('terms', tags=tags)
135
159
tt = []
160
+ not_tt = []
136
161
for t in tags :
137
- tt .append (Q ('term' , tags = t ))
162
+ # used for tags exclusion/negation
163
+ if t .startswith ('!' ):
164
+ t = t [1 :]
165
+ not_tt .append (t )
166
+ else :
167
+ tt .append (t )
168
+
169
+ if len (not_tt ) > 0 :
170
+ if len (not_tt ) == 1 :
171
+ s = s .exclude ('term' , tags = not_tt [0 ])
172
+ else :
173
+ s = s .exclude ('terms' , tags = not_tt )
174
+
175
+ if len (tt ) > 0 :
176
+ if len (tt ) == 1 :
177
+ s = s .filter ('term' , tags = tt [0 ])
178
+ else :
179
+ s = s .filter ('terms' , tags = tt )
180
+
181
+ return s
182
+
183
+ def filter_provider (s , q_filters ):
184
+ if not q_filters .get ('provider' ):
185
+ return s
138
186
139
- s .query = Q ('bool' , must = s .query , should = tt , minimum_should_match = 1 )
187
+ provider = q_filters .pop ('provider' )
188
+
189
+ if isinstance (provider , basestring ):
190
+ provider = [x .strip () for x in provider .split (',' )]
191
+
192
+ pp = []
193
+ not_pp = []
194
+ for p in provider :
195
+ # used for provider exclusion/negation
196
+ if p .startswith ('!' ):
197
+ p = p [1 :]
198
+ not_pp .append (p )
199
+ else :
200
+ pp .append (p )
201
+
202
+ if len (not_pp ) > 0 :
203
+ if len (not_pp ) == 1 :
204
+ s = s .exclude ('term' , provider = not_pp [0 ])
205
+ else :
206
+ s = s .exclude ('terms' , provider = not_pp )
207
+
208
+ if len (pp ) > 0 :
209
+ if len (pp ) == 1 :
210
+ s = s .filter ('term' , provider = pp [0 ])
211
+ else :
212
+ s = s .filter ('terms' , provider = pp )
140
213
141
214
return s
142
215
@@ -145,16 +218,13 @@ def filter_groups(s, q_filters, token=None):
145
218
if token :
146
219
groups = token .get ('groups' , 'everyone' )
147
220
else :
148
- groups = q_filters [ 'groups' ]
221
+ groups = q_filters . pop ( 'groups' )
149
222
150
223
if isinstance (groups , basestring ):
151
224
groups = [groups ]
152
225
153
- gg = []
154
- for g in groups :
155
- gg .append (Q ('term' , group = g ))
156
-
157
- s .query = Q ('bool' , must = s .query , should = gg , minimum_should_match = 1 )
226
+ # each array element is implicitly ORed (aka, 'should') using a terms filter
227
+ s = s .filter ('terms' , group = groups )
158
228
159
229
return s
160
230
@@ -171,32 +241,34 @@ def filter_id(s, q_filters):
171
241
def filter_build (s , filters , token = None ):
172
242
limit = filters .get ('limit' )
173
243
if limit and int (limit ) > WINDOW_LIMIT :
174
- raise InvalidSearch ('request limit should be <= server threshold of {} but was set to {}' .format (WINDOW_LIMIT , limit ))
175
-
244
+ raise InvalidSearch ('Request limit should be <= server threshold of {} but was set to {}' .format (WINDOW_LIMIT , limit ))
245
+
176
246
q_filters = {}
177
247
for f in VALID_FILTERS :
178
248
if filters .get (f ):
179
249
q_filters [f ] = filters [f ]
180
250
181
- # treat indicator as special, transform into Search
182
- s = filter_indicator (s , q_filters )
251
+ s = filter_provider (s , q_filters )
252
+
253
+ s = filter_confidence (s , q_filters )
183
254
184
255
s = filter_id (s , q_filters )
185
256
186
- s = filter_confidence (s , q_filters )
257
+ # treat indicator as special, transform into Search
258
+ s = filter_indicator (s , q_filters )
187
259
188
260
s = filter_reporttime (s , q_filters )
189
261
190
262
# transform all other filters into term=
191
263
s = filter_terms (s , q_filters )
192
264
193
- if filters .get ('tags' ):
194
- s = filter_tags (s , filters )
195
-
196
- if filters .get ('groups' ):
197
- s = filter_groups (s , filters )
265
+ if q_filters .get ('groups' ):
266
+ s = filter_groups (s , q_filters )
198
267
else :
199
268
if token :
200
269
s = filter_groups (s , {}, token = token )
201
270
271
+ if q_filters .get ('tags' ):
272
+ s = filter_tags (s , q_filters )
273
+
202
274
return s
0 commit comments