1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.elasticsearch.impl;
23
24 import static org.opencastproject.elasticsearch.impl.IndexSchema.TEXT;
25 import static org.opencastproject.elasticsearch.impl.IndexSchema.TEXT_FUZZY;
26
27 import org.opencastproject.elasticsearch.api.SearchQuery;
28 import org.opencastproject.util.DateTimeSupport;
29
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.lucene.search.Query;
32 import org.elasticsearch.common.io.stream.StreamOutput;
33 import org.elasticsearch.common.xcontent.XContentBuilder;
34 import org.elasticsearch.index.query.BoolQueryBuilder;
35 import org.elasticsearch.index.query.MatchAllQueryBuilder;
36 import org.elasticsearch.index.query.MoreLikeThisQueryBuilder;
37 import org.elasticsearch.index.query.QueryBuilder;
38 import org.elasticsearch.index.query.QueryBuilders;
39 import org.elasticsearch.index.query.QueryRewriteContext;
40 import org.elasticsearch.index.query.QueryShardContext;
41 import org.elasticsearch.index.query.QueryStringQueryBuilder;
42 import org.elasticsearch.index.query.RangeQueryBuilder;
43 import org.elasticsearch.index.query.TermsQueryBuilder;
44
45 import java.io.IOException;
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.Date;
49 import java.util.HashMap;
50 import java.util.HashSet;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.Set;
54 import java.util.stream.Collectors;
55
56
57
58
59 public abstract class AbstractElasticsearchQueryBuilder<T extends SearchQuery> implements QueryBuilder {
60
61
62 private Map<String, Set<Object>> searchTerms = null;
63
64
65 protected List<ValueGroup> groups = null;
66
67
68 private Set<DateRange> dateRanges = null;
69
70
71 protected String filter = null;
72
73
74 protected String text = null;
75
76
77 protected String fuzzyText = null;
78
79
80 private T query;
81
82
83 private QueryBuilder queryBuilder = null;
84
85
86
87
88
89
90
91 public AbstractElasticsearchQueryBuilder(T query) {
92 this.query = query;
93 buildQuery(query);
94 createQuery();
95 }
96
97
98
99
100
101
102 public T getQuery() {
103 return query;
104 }
105
106 public abstract void buildQuery(T query);
107
108
109
110
111
112 private void createQuery() {
113
114 queryBuilder = new MatchAllQueryBuilder();
115
116
117 BoolQueryBuilder booleanQuery = new BoolQueryBuilder();
118
119
120 if (searchTerms != null) {
121 for (Map.Entry<String, Set<Object>> entry : searchTerms.entrySet()) {
122 booleanQuery.must(new TermsQueryBuilder(entry.getKey(), entry.getValue().toArray(new Object[0])));
123 }
124 this.queryBuilder = booleanQuery;
125 }
126
127
128 if (dateRanges != null) {
129 for (DateRange dr : dateRanges) {
130 booleanQuery.must(dr.getQueryBuilder());
131 }
132 this.queryBuilder = booleanQuery;
133 }
134
135
136 if (text != null) {
137 QueryStringQueryBuilder queryBuilder = QueryBuilders.queryStringQuery(text).field(TEXT);
138 booleanQuery.must(queryBuilder);
139 this.queryBuilder = booleanQuery;
140 }
141
142
143 if (fuzzyText != null) {
144 MoreLikeThisQueryBuilder moreLikeThisQueryBuilder = QueryBuilders.moreLikeThisQuery(
145 new String[] {TEXT_FUZZY},
146 new String[] {fuzzyText},
147 null);
148 booleanQuery.must(moreLikeThisQueryBuilder);
149 this.queryBuilder = booleanQuery;
150 }
151
152 List<QueryBuilder> filters = new ArrayList<>();
153
154
155 if (groups != null) {
156 for (ValueGroup group : groups) {
157 filters.addAll(group.getFilterBuilders());
158 }
159 }
160
161
162 if (filter != null) {
163 filters.add(QueryBuilders.termQuery(IndexSchema.TEXT, filter));
164 }
165
166
167 if (!filters.isEmpty()) {
168 for (QueryBuilder filter : filters) {
169 booleanQuery.filter(filter);
170 }
171 this.queryBuilder = booleanQuery;
172 }
173
174 }
175
176
177
178
179
180
181
182
183
184 protected void and(String fieldName, Object... fieldValues) {
185
186
187 if (searchTerms == null) {
188 searchTerms = new HashMap<>();
189 }
190
191
192 fieldName = StringUtils.trim(fieldName);
193
194
195 searchTerms.computeIfAbsent(fieldName, k -> new HashSet<>())
196 .addAll(Arrays.asList(fieldValues));
197 }
198
199
200
201
202
203
204
205
206
207
208
209 protected void and(String fieldName, Date startDate, Date endDate) {
210
211
212 fieldName = StringUtils.trim(fieldName);
213
214
215 if (dateRanges == null) {
216 dateRanges = new HashSet<>();
217 }
218
219
220 dateRanges.add(new DateRange(fieldName, startDate, endDate));
221 }
222
223 @Override
224 public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
225 return queryBuilder.toXContent(builder, params);
226 }
227
228 @Override
229 public Query toQuery(QueryShardContext context) throws IOException {
230 return queryBuilder.toQuery(context);
231 }
232
233 @Override
234 public QueryBuilder queryName(String queryName) {
235 return queryBuilder.queryName(queryName);
236 }
237
238 @Override
239 public String queryName() {
240 return queryBuilder.queryName();
241 }
242
243 @Override
244 public float boost() {
245 return queryBuilder.boost();
246 }
247
248 @Override
249 public QueryBuilder boost(float boost) {
250 return queryBuilder.boost(boost);
251 }
252
253 @Override
254 public String getName() {
255 return queryBuilder.getName();
256 }
257
258 @Override
259 public String getWriteableName() {
260 return queryBuilder.getWriteableName();
261 }
262
263 @Override
264 public void writeTo(StreamOutput out) throws IOException {
265 queryBuilder.writeTo(out);
266 }
267
268 @Override
269 public QueryBuilder rewrite(QueryRewriteContext queryShardContext) throws IOException {
270 return queryBuilder.rewrite(queryShardContext);
271 }
272
273 @Override
274 public boolean isFragment() {
275 return queryBuilder.isFragment();
276 }
277
278
279
280
281 public static final class DateRange {
282
283
284 private String field;
285
286
287 private Date startDate;
288
289
290 private Date endDate;
291
292
293
294
295
296
297
298
299
300
301
302
303 DateRange(String field, Date start, Date end) {
304 this.field = field;
305 this.startDate = start;
306 this.endDate = end;
307 }
308
309
310
311
312
313
314 QueryBuilder getQueryBuilder() {
315 RangeQueryBuilder rqb = new RangeQueryBuilder(field);
316 if (startDate != null) {
317 rqb.from(DateTimeSupport.toUTC(startDate.getTime()));
318 }
319 if (endDate != null) {
320 rqb.to(DateTimeSupport.toUTC(endDate.getTime()));
321 }
322 return rqb;
323 }
324
325 @Override
326 public boolean equals(Object obj) {
327 return obj instanceof DateRange
328 && ((DateRange) obj).field.equals(field);
329 }
330
331 @Override
332 public int hashCode() {
333 return field.hashCode();
334 }
335
336 }
337
338
339
340
341 public static final class ValueGroup {
342
343
344 private String field;
345
346
347 private Object[] values;
348
349
350
351
352
353
354
355
356
357 public ValueGroup(String field, Object... values) {
358 this.field = field;
359 this.values = values;
360 }
361
362
363
364
365
366
367 List<QueryBuilder> getFilterBuilders() {
368 return Arrays.stream(values)
369 .map((v) -> QueryBuilders.termQuery(field, v.toString()))
370 .collect(Collectors.toList());
371 }
372
373 @Override
374 public boolean equals(Object obj) {
375 return obj instanceof ValueGroup
376 && ((ValueGroup) obj).field.equals(field);
377 }
378
379 @Override
380 public int hashCode() {
381 return field.hashCode();
382 }
383
384 }
385
386 }