1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.opensearch.user.allcommon;
17
18 import java.text.SimpleDateFormat;
19 import java.time.LocalDateTime;
20 import java.time.ZoneId;
21 import java.time.format.DateTimeFormatter;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Date;
26 import java.util.List;
27 import java.util.TimeZone;
28
29 import org.dbflute.cbean.ConditionBean;
30 import org.dbflute.cbean.ConditionQuery;
31 import org.dbflute.cbean.ckey.ConditionKey;
32 import org.dbflute.cbean.coption.ConditionOption;
33 import org.dbflute.cbean.coption.ParameterOption;
34 import org.dbflute.cbean.cvalue.ConditionValue;
35 import org.dbflute.cbean.sqlclause.SqlClause;
36 import org.dbflute.dbmeta.info.ColumnInfo;
37 import org.dbflute.dbmeta.name.ColumnRealName;
38 import org.dbflute.dbmeta.name.ColumnSqlName;
39 import org.dbflute.exception.InvalidQueryRegisteredException;
40 import org.dbflute.util.Srl;
41 import org.opensearch.common.unit.Fuzziness;
42 import org.opensearch.index.query.BoolQueryBuilder;
43 import org.opensearch.index.query.CommonTermsQueryBuilder;
44 import org.opensearch.index.query.ExistsQueryBuilder;
45 import org.opensearch.index.query.IdsQueryBuilder;
46 import org.opensearch.index.query.MatchAllQueryBuilder;
47 import org.opensearch.index.query.MatchPhrasePrefixQueryBuilder;
48 import org.opensearch.index.query.MatchPhraseQueryBuilder;
49 import org.opensearch.index.query.MatchQueryBuilder;
50 import org.opensearch.index.query.MoreLikeThisQueryBuilder;
51 import org.opensearch.index.query.PrefixQueryBuilder;
52 import org.opensearch.index.query.QueryBuilder;
53 import org.opensearch.index.query.QueryBuilders;
54 import org.opensearch.index.query.QueryStringQueryBuilder;
55 import org.opensearch.index.query.RangeQueryBuilder;
56 import org.opensearch.index.query.RegexpQueryBuilder;
57 import org.opensearch.index.query.SpanTermQueryBuilder;
58 import org.opensearch.index.query.TermQueryBuilder;
59 import org.opensearch.index.query.TermsQueryBuilder;
60 import org.opensearch.index.query.WildcardQueryBuilder;
61 import org.opensearch.index.query.functionscore.FunctionScoreQueryBuilder;
62 import org.opensearch.index.query.functionscore.FunctionScoreQueryBuilder.FilterFunctionBuilder;
63 import org.opensearch.index.query.functionscore.ScoreFunctionBuilder;
64 import org.opensearch.search.sort.FieldSortBuilder;
65 import org.opensearch.search.sort.SortBuilders;
66 import org.opensearch.search.sort.SortOrder;
67
68
69
70
71 public abstract class EsAbstractConditionQuery implements ConditionQuery {
72
73 protected static final String CQ_PROPERTY = "conditionQuery";
74
75
76
77
78 protected List<QueryBuilder> queryBuilderList;
79 protected List<FieldSortBuilder> fieldSortBuilderList;
80 private DocMetaCQ docMetaCQ;
81
82
83
84
85 public DocMetaCQ docMeta() {
86 if (docMetaCQ == null) {
87 docMetaCQ = new DocMetaCQ();
88 }
89 return docMetaCQ;
90 }
91
92 public List<FieldSortBuilder> getFieldSortBuilderList() {
93 return fieldSortBuilderList == null ? Collections.emptyList() : fieldSortBuilderList;
94 }
95
96 public boolean hasQueries() {
97 return queryBuilderList != null && !queryBuilderList.isEmpty();
98 }
99
100 public QueryBuilder getQuery() {
101 if (queryBuilderList == null) {
102 return null;
103 } else if (queryBuilderList.size() == 1) {
104 return queryBuilderList.get(0);
105 }
106 BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
107 queryBuilderList.forEach(query -> {
108 boolQuery.must(query);
109 });
110 return boolQuery;
111 }
112
113 public List<QueryBuilder> getQueryBuilderList() {
114 return queryBuilderList != null ? queryBuilderList : Collections.emptyList();
115 }
116
117
118
119
120 public void addQuery(QueryBuilder queryBuilder) {
121 assertObjectNotNull("queryBuilder", queryBuilder);
122 regQ(queryBuilder);
123 }
124
125 public void queryString(String queryString) {
126 checkEsInvalidQuery("queryString", queryString);
127 doQueryString(queryString, null);
128 }
129
130 public void queryString(String queryString, ConditionOptionCall<QueryStringQueryBuilder> opLambda) {
131 checkEsInvalidQuery("queryString", queryString);
132 assertObjectNotNull("opLambda", opLambda);
133 doQueryString(queryString, opLambda);
134 }
135
136 protected void doQueryString(String queryString, ConditionOptionCall<QueryStringQueryBuilder> opLambda) {
137 QueryStringQueryBuilder queryStringQuery = QueryBuilders.queryStringQuery(queryString);
138 regQ(queryStringQuery);
139 if (opLambda != null) {
140 opLambda.callback(queryStringQuery);
141 }
142 }
143
144 public void matchAll() {
145 doMatchAll(null);
146 }
147
148 public void matchAll(ConditionOptionCall<MatchAllQueryBuilder> opLambda) {
149 assertObjectNotNull("opLambda", opLambda);
150 doMatchAll(opLambda);
151 }
152
153 protected void doMatchAll(ConditionOptionCall<MatchAllQueryBuilder> opLambda) {
154 MatchAllQueryBuilder builder = QueryBuilders.matchAllQuery();
155 regQ(builder);
156 if (opLambda != null) {
157 opLambda.callback(builder);
158 }
159 }
160
161
162
163
164
165 protected FunctionScoreQueryBuilder regFunctionScoreQ(QueryBuilder queryBuilder, Collection<FilterFunctionBuilder> list) {
166 FunctionScoreQueryBuilder functionScoreQuery =
167 QueryBuilders.functionScoreQuery(queryBuilder, list.toArray(new FilterFunctionBuilder[list.size()]));
168 regQ(functionScoreQuery);
169 return functionScoreQuery;
170 }
171
172 protected BoolQueryBuilder regBoolCQ(List<QueryBuilder> mustList, List<QueryBuilder> shouldList, List<QueryBuilder> mustNotList,
173 List<QueryBuilder> filterList) {
174 assertObjectNotNull("mustList", mustList);
175 assertObjectNotNull("shouldList", shouldList);
176 assertObjectNotNull("mustNotList", mustNotList);
177 assertObjectNotNull("filterList", filterList);
178 BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
179 mustList.forEach(query -> {
180 boolQuery.must(query);
181 });
182 shouldList.forEach(query -> {
183 boolQuery.should(query);
184 });
185 mustNotList.forEach(query -> {
186 boolQuery.mustNot(query);
187 });
188 filterList.forEach(query -> {
189 boolQuery.filter(query);
190 });
191 regQ(boolQuery);
192 return boolQuery;
193 }
194
195 protected TermQueryBuilder regTermQ(String name, Object value) {
196 checkEsInvalidQuery(name, value);
197 TermQueryBuilder termQuery = QueryBuilders.termQuery(name, value);
198 regQ(termQuery);
199 return termQuery;
200 }
201
202 protected TermsQueryBuilder regTermsQ(String name, Collection<?> values) {
203 checkEsInvalidQueryCollection(name, values);
204 TermsQueryBuilder termsQuery = QueryBuilders.termsQuery(name, values);
205 regQ(termsQuery);
206 return termsQuery;
207 }
208
209 protected IdsQueryBuilder regIdsQ(Collection<String> values) {
210 checkEsInvalidQueryCollection("_id", values);
211 IdsQueryBuilder idsQuery = QueryBuilders.idsQuery().addIds(values.toArray(new String[values.size()]));
212 regQ(idsQuery);
213 return idsQuery;
214 }
215
216 protected MatchQueryBuilder regMatchQ(String name, Object value) {
217 checkEsInvalidQuery(name, value);
218 MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(name, value);
219 regQ(matchQuery);
220 return matchQuery;
221 }
222
223 protected MatchPhraseQueryBuilder regMatchPhraseQ(String name, Object value) {
224 checkEsInvalidQuery(name, value);
225 MatchPhraseQueryBuilder matchQuery = QueryBuilders.matchPhraseQuery(name, value);
226 regQ(matchQuery);
227 return matchQuery;
228 }
229
230 protected MatchPhrasePrefixQueryBuilder regMatchPhrasePrefixQ(String name, Object value) {
231 checkEsInvalidQuery(name, value);
232 MatchPhrasePrefixQueryBuilder matchQuery = QueryBuilders.matchPhrasePrefixQuery(name, value);
233 regQ(matchQuery);
234 return matchQuery;
235 }
236
237 protected MatchQueryBuilder regFuzzyQ(String name, Object value) {
238 checkEsInvalidQuery(name, value);
239 MatchQueryBuilder fuzzyQuery = QueryBuilders.matchQuery(name, value).fuzziness(Fuzziness.AUTO);
240 regQ(fuzzyQuery);
241 return fuzzyQuery;
242 }
243
244 protected PrefixQueryBuilder regPrefixQ(String name, String prefix) {
245 checkEsInvalidQuery(name, prefix);
246 PrefixQueryBuilder prefixQuery = QueryBuilders.prefixQuery(name, prefix);
247 regQ(prefixQuery);
248 return prefixQuery;
249 }
250
251 protected RangeQueryBuilder regRangeQ(String name, ConditionKey ck, Object value) {
252 checkEsInvalidQuery(name, value);
253 assertObjectNotNull("ck", ck);
254 if (queryBuilderList != null) {
255 for (QueryBuilder builder : queryBuilderList) {
256 if (builder instanceof RangeQueryBuilder) {
257 RangeQueryBuilder rangeQueryBuilder = (RangeQueryBuilder) builder;
258 if (rangeQueryBuilder.toString().replaceAll("\\s", "").startsWith("{\"range\":{\"" + name + "\"")) {
259 addRangeC(rangeQueryBuilder, ck, value);
260 return rangeQueryBuilder;
261 }
262 }
263 }
264 }
265 RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(name);
266 addRangeC(rangeQueryBuilder, ck, value);
267 regQ(rangeQueryBuilder);
268 return rangeQueryBuilder;
269 }
270
271 protected void addRangeC(RangeQueryBuilder builder, ConditionKey ck, Object value) {
272 assertObjectNotNull("ck", ck);
273 if (ck.equals(ConditionKey.CK_GREATER_THAN)) {
274 builder.gt(value);
275 } else if (ck.equals(ConditionKey.CK_GREATER_EQUAL)) {
276 builder.gte(value);
277 } else if (ck.equals(ConditionKey.CK_LESS_THAN)) {
278 builder.lt(value);
279 } else if (ck.equals(ConditionKey.CK_LESS_EQUAL)) {
280 builder.lte(value);
281 }
282 }
283
284 protected ExistsQueryBuilder regExistsQ(String name) {
285 ExistsQueryBuilder existsQuery = QueryBuilders.existsQuery(name);
286 regQ(existsQuery);
287 return existsQuery;
288 }
289
290 protected WildcardQueryBuilder regWildcardQ(String name, String wildcard) {
291 checkEsInvalidQuery(name, wildcard);
292 WildcardQueryBuilder wildcardQuery = QueryBuilders.wildcardQuery(name, wildcard);
293 regQ(wildcardQuery);
294 return wildcardQuery;
295 }
296
297 protected RegexpQueryBuilder regRegexpQ(String name, String regexp) {
298 checkEsInvalidQuery(name, regexp);
299 RegexpQueryBuilder regexpQuery = QueryBuilders.regexpQuery(name, regexp);
300 regQ(regexpQuery);
301 return regexpQuery;
302 }
303
304 protected CommonTermsQueryBuilder regCommonTermsQ(String name, Object text) {
305 checkEsInvalidQuery(name, text);
306 CommonTermsQueryBuilder commonTermsQuery = QueryBuilders.commonTermsQuery(name, text);
307 regQ(commonTermsQuery);
308 return commonTermsQuery;
309 }
310
311 protected MoreLikeThisQueryBuilder regMoreLikeThisQueryQ(String name, String[] likeTexts) {
312 MoreLikeThisQueryBuilder moreLikeThisQuery = QueryBuilders.moreLikeThisQuery(new String[] { name }, likeTexts, null);
313 regQ(moreLikeThisQuery);
314 return moreLikeThisQuery;
315 }
316
317 protected SpanTermQueryBuilder regSpanTermQ(String name, String value) {
318 checkEsInvalidQuery(name, value);
319 SpanTermQueryBuilder spanTermQuery = QueryBuilders.spanTermQuery(name, value);
320 regQ(spanTermQuery);
321 return spanTermQuery;
322 }
323
324 protected void regQ(QueryBuilder builder) {
325 assertObjectNotNull("builder", builder);
326 if (queryBuilderList == null) {
327 queryBuilderList = new ArrayList<>();
328 }
329 queryBuilderList.add(builder);
330 }
331
332 protected void regOBA(String field) {
333 registerOrderBy(field, true);
334 }
335
336 protected void regOBD(String field) {
337 registerOrderBy(field, false);
338 }
339
340 protected void registerOrderBy(String field, boolean ascOrDesc) {
341 assertObjectNotNull("field", field);
342 if (fieldSortBuilderList == null) {
343 fieldSortBuilderList = new ArrayList<>();
344 }
345 fieldSortBuilderList.add(SortBuilders.fieldSort(field).order(ascOrDesc ? SortOrder.ASC : SortOrder.DESC));
346 }
347
348
349
350
351 protected void checkEsInvalidQuery(String name, Object value) {
352 if (value == null || (value instanceof String && ((String) value).isEmpty())) {
353 String msg = "Cannot register null or empty query: name=" + name + " value=" + value;
354 throw new InvalidQueryRegisteredException(msg);
355 }
356 }
357
358 protected void checkEsInvalidQueryCollection(String name, Collection<?> values) {
359 if (values == null || values.isEmpty()) {
360 String msg = "Cannot register null or empty query collection: name=" + name + " values=" + values;
361 throw new InvalidQueryRegisteredException(msg);
362 }
363 }
364
365
366
367
368 @Override
369 public ColumnRealName toColumnRealName(String columnDbName) {
370 return ColumnRealName.create(xgetAliasName(), toColumnSqlName(columnDbName));
371 }
372
373 @Override
374 public ColumnRealName toColumnRealName(ColumnInfo columnInfo) {
375 return ColumnRealName.create(xgetAliasName(), columnInfo.getColumnSqlName());
376 }
377
378 @Override
379 public ColumnSqlName toColumnSqlName(String columnDbName) {
380 return new ColumnSqlName(columnDbName);
381 }
382
383 @Override
384 public ConditionBean xgetBaseCB() {
385 return null;
386 }
387
388 @Override
389 public ConditionQuery xgetBaseQuery() {
390 return null;
391 }
392
393 @Override
394 public ConditionQuery xgetReferrerQuery() {
395 return null;
396 }
397
398 @Override
399 public SqlClause xgetSqlClause() {
400 return null;
401 }
402
403 @Override
404 public int xgetNestLevel() {
405 return 0;
406 }
407
408 @Override
409 public int xgetNextNestLevel() {
410 return 0;
411 }
412
413 @Override
414 public boolean isBaseQuery() {
415 return false;
416 }
417
418 @Override
419 public String xgetForeignPropertyName() {
420 return null;
421 }
422
423 @Override
424 public String xgetRelationPath() {
425 return null;
426 }
427
428 @Override
429 public String xgetLocationBase() {
430 final StringBuilder sb = new StringBuilder();
431 ConditionQuery query = this;
432 while (true) {
433 if (query.isBaseQuery()) {
434 sb.insert(0, CQ_PROPERTY + ".");
435 break;
436 } else {
437 final String foreignPropertyName = query.xgetForeignPropertyName();
438 if (foreignPropertyName == null) {
439 String msg = "The foreignPropertyName of the query should not be null:";
440 msg = msg + " query=" + query;
441 throw new IllegalStateException(msg);
442 }
443 sb.insert(0, CQ_PROPERTY + Srl.initCap(foreignPropertyName) + ".");
444 }
445 query = query.xgetReferrerQuery();
446 }
447 return sb.toString();
448 }
449
450 @Override
451 public ConditionValue invokeValue(String columnFlexibleName) {
452 return null;
453 }
454
455 @Override
456 public void invokeQuery(String columnFlexibleName, String conditionKeyName, Object conditionValue) {
457
458 }
459
460 @Override
461 public void invokeQuery(String columnFlexibleName, String conditionKeyName, Object conditionValue, ConditionOption conditionOption) {
462
463 }
464
465 @Override
466 public void invokeQueryEqual(String columnFlexibleName, Object conditionValue) {
467
468 }
469
470 @Override
471 public void invokeQueryNotEqual(String columnFlexibleName, Object conditionValue) {
472
473 }
474
475 @Override
476 public void invokeOrderBy(String columnFlexibleName, boolean isAsc) {
477
478 }
479
480 @Override
481 public ConditionQuery invokeForeignCQ(String foreignPropertyName) {
482 return null;
483 }
484
485 @Override
486 public boolean invokeHasForeignCQ(String foreignPropertyName) {
487 return false;
488 }
489
490 @Override
491 public void xregisterParameterOption(ParameterOption option) {
492
493 }
494
495
496
497
498 protected void assertObjectNotNull(String variableName, Object value) {
499 if (variableName == null) {
500 String msg = "The value should not be null: variableName=null value=" + value;
501 throw new IllegalArgumentException(msg);
502 }
503 if (value == null) {
504 String msg = "The value should not be null: variableName=" + variableName;
505 throw new IllegalArgumentException(msg);
506 }
507 }
508
509 protected String toRangeDateString(Date date, String format) {
510 if (format.contains("epoch_millis")) {
511 return Long.toString(date.getTime());
512 } else if (format.contains("date_optional_time")) {
513 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
514 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
515 return sdf.format(date);
516 } else {
517 return Long.toString(date.getTime());
518 }
519 }
520
521 protected String toRangeLocalDateTimeString(LocalDateTime date, String format) {
522 if (format.contains("epoch_millis")) {
523 return Long.toString(date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
524 } else if (format.contains("date_optional_time")) {
525 return DateTimeFormatter.ISO_DATE_TIME.format(date);
526 } else {
527 return Long.toString(date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
528 }
529 }
530
531
532
533
534 public class DocMetaCQ {
535
536 public void setId_Equal(String id) {
537 regQ(QueryBuilders.idsQuery().addIds(id));
538 }
539 }
540
541 @FunctionalInterface
542 public interface ConditionOptionCall<OP extends QueryBuilder> {
543
544
545
546
547 void callback(OP op);
548 }
549
550 @FunctionalInterface
551 public interface BoolCall<CQ extends EsAbstractConditionQuery> {
552
553 void callback(CQ must, CQ should, CQ mustNot, CQ filter);
554 }
555
556 @FunctionalInterface
557 public interface FilteredCall<CQ extends EsAbstractConditionQuery, CF extends EsAbstractConditionQuery> {
558
559 void callback(CQ query, CF filter);
560 }
561
562 @FunctionalInterface
563 public interface OperatorCall<CQ extends EsAbstractConditionQuery> {
564
565 void callback(CQ query);
566 }
567
568 @FunctionalInterface
569 public interface ScoreFunctionCall<CC extends ScoreFunctionCreator<?>> {
570
571 void callback(CC creator);
572 }
573
574 @FunctionalInterface
575 public interface ScoreFunctionCreator<T extends EsAbstractConditionQuery> {
576 void filter(final OperatorCall<T> cqLambda, final ScoreFunctionBuilder<?> scoreFunctionBuilder);
577 }
578 }