/* * Copyright 2012-2017 CodeLibs Project and the Others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.codelibs.fess.es.log.allcommon; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.TimeZone; import org.dbflute.cbean.ConditionBean; import org.dbflute.cbean.ConditionQuery; import org.dbflute.cbean.ckey.ConditionKey; import org.dbflute.cbean.coption.ConditionOption; import org.dbflute.cbean.coption.ParameterOption; import org.dbflute.cbean.cvalue.ConditionValue; import org.dbflute.cbean.sqlclause.SqlClause; import org.dbflute.dbmeta.info.ColumnInfo; import org.dbflute.dbmeta.name.ColumnRealName; import org.dbflute.dbmeta.name.ColumnSqlName; import org.dbflute.exception.InvalidQueryRegisteredException; import org.dbflute.util.Srl; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.CommonTermsQueryBuilder; import org.elasticsearch.index.query.ExistsQueryBuilder; import org.elasticsearch.index.query.IdsQueryBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.MatchPhrasePrefixQueryBuilder; import org.elasticsearch.index.query.MatchPhraseQueryBuilder; import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.index.query.MoreLikeThisQueryBuilder; import org.elasticsearch.index.query.PrefixQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryStringQueryBuilder; import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.index.query.RegexpQueryBuilder; import org.elasticsearch.index.query.SpanTermQueryBuilder; import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.index.query.TermsQueryBuilder; import org.elasticsearch.index.query.WildcardQueryBuilder; import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder; import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder.FilterFunctionBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder; import org.elasticsearch.search.sort.FieldSortBuilder; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; /** * @author ESFlute (using FreeGen) */ public abstract class EsAbstractConditionQuery implements ConditionQuery { protected static final String CQ_PROPERTY = "conditionQuery"; // =================================================================================== // Attribute // ========= protected List<QueryBuilder> queryBuilderList; protected List<FieldSortBuilder> fieldSortBuilderList; private DocMetaCQ docMetaCQ; // =================================================================================== // Control // ======= public DocMetaCQ docMeta() { if (docMetaCQ == null) { docMetaCQ = new DocMetaCQ(); } return docMetaCQ; } public List<FieldSortBuilder> getFieldSortBuilderList() { return fieldSortBuilderList == null ? Collections.emptyList() : fieldSortBuilderList; } public boolean hasQueries() { return queryBuilderList != null && !queryBuilderList.isEmpty(); } public QueryBuilder getQuery() { if (queryBuilderList == null) { return null; } else if (queryBuilderList.size() == 1) { return queryBuilderList.get(0); } BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); queryBuilderList.forEach(query -> { boolQuery.must(query); }); return boolQuery; } public List<QueryBuilder> getQueryBuilderList() { return queryBuilderList != null ? queryBuilderList : Collections.emptyList(); } // =================================================================================== // Query // ===== public void addQuery(QueryBuilder queryBuilder) { assertObjectNotNull("queryBuilder", queryBuilder); regQ(queryBuilder); } public void queryString(String queryString) { checkEsInvalidQuery("queryString", queryString); doQueryString(queryString, null); } public void queryString(String queryString, ConditionOptionCall<QueryStringQueryBuilder> opLambda) { checkEsInvalidQuery("queryString", queryString); assertObjectNotNull("opLambda", opLambda); doQueryString(queryString, opLambda); } protected void doQueryString(String queryString, ConditionOptionCall<QueryStringQueryBuilder> opLambda) { QueryStringQueryBuilder queryStringQuery = QueryBuilders.queryStringQuery(queryString); regQ(queryStringQuery); if (opLambda != null) { opLambda.callback(queryStringQuery); } } public void matchAll() { doMatchAll(null); } public void matchAll(ConditionOptionCall<MatchAllQueryBuilder> opLambda) { assertObjectNotNull("opLambda", opLambda); doMatchAll(opLambda); } protected void doMatchAll(ConditionOptionCall<MatchAllQueryBuilder> opLambda) { MatchAllQueryBuilder builder = QueryBuilders.matchAllQuery(); regQ(builder); if (opLambda != null) { opLambda.callback(builder); } } // =================================================================================== // Register // ======== protected FunctionScoreQueryBuilder regFunctionScoreQ(QueryBuilder queryBuilder, Collection<FilterFunctionBuilder> list) { FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(queryBuilder, list.toArray(new FilterFunctionBuilder[list.size()])); regQ(functionScoreQuery); return functionScoreQuery; } protected BoolQueryBuilder regBoolCQ(List<QueryBuilder> mustList, List<QueryBuilder> shouldList, List<QueryBuilder> mustNotList, List<QueryBuilder> filterList) { assertObjectNotNull("mustList", mustList); assertObjectNotNull("shouldList", shouldList); assertObjectNotNull("mustNotList", mustNotList); assertObjectNotNull("filterList", filterList); BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); mustList.forEach(query -> { boolQuery.must(query); }); shouldList.forEach(query -> { boolQuery.should(query); }); mustNotList.forEach(query -> { boolQuery.mustNot(query); }); filterList.forEach(query -> { boolQuery.filter(query); }); regQ(boolQuery); return boolQuery; } protected TermQueryBuilder regTermQ(String name, Object value) { checkEsInvalidQuery(name, value); TermQueryBuilder termQuery = QueryBuilders.termQuery(name, value); regQ(termQuery); return termQuery; } protected TermsQueryBuilder regTermsQ(String name, Collection<?> values) { checkEsInvalidQueryCollection(name, values); TermsQueryBuilder termsQuery = QueryBuilders.termsQuery(name, values); regQ(termsQuery); return termsQuery; } protected IdsQueryBuilder regIdsQ(Collection<String> values) { checkEsInvalidQueryCollection("_id", values); IdsQueryBuilder idsQuery = QueryBuilders.idsQuery(asTableDbName()).addIds(values.toArray(new String[values.size()])); regQ(idsQuery); return idsQuery; } protected MatchQueryBuilder regMatchQ(String name, Object value) { checkEsInvalidQuery(name, value); MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(name, value); regQ(matchQuery); return matchQuery; } protected MatchPhraseQueryBuilder regMatchPhraseQ(String name, Object value) { checkEsInvalidQuery(name, value); MatchPhraseQueryBuilder matchQuery = QueryBuilders.matchPhraseQuery(name, value); regQ(matchQuery); return matchQuery; } protected MatchPhrasePrefixQueryBuilder regMatchPhrasePrefixQ(String name, Object value) { checkEsInvalidQuery(name, value); MatchPhrasePrefixQueryBuilder matchQuery = QueryBuilders.matchPhrasePrefixQuery(name, value); regQ(matchQuery); return matchQuery; } protected MatchQueryBuilder regFuzzyQ(String name, Object value) { checkEsInvalidQuery(name, value); MatchQueryBuilder fuzzyQuery = QueryBuilders.matchQuery(name, value).fuzziness(Fuzziness.AUTO); regQ(fuzzyQuery); return fuzzyQuery; } protected PrefixQueryBuilder regPrefixQ(String name, String prefix) { checkEsInvalidQuery(name, prefix); PrefixQueryBuilder prefixQuery = QueryBuilders.prefixQuery(name, prefix); regQ(prefixQuery); return prefixQuery; } protected RangeQueryBuilder regRangeQ(String name, ConditionKey ck, Object value) { checkEsInvalidQuery(name, value); assertObjectNotNull("ck", ck); if (queryBuilderList != null) { for (QueryBuilder builder : queryBuilderList) { if (builder instanceof RangeQueryBuilder) { RangeQueryBuilder rangeQueryBuilder = (RangeQueryBuilder) builder; if (rangeQueryBuilder.toString().replaceAll("\\s", "").startsWith("{\"range\":{\"" + name + "\"")) { addRangeC(rangeQueryBuilder, ck, value); return rangeQueryBuilder; } } } } RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(name); addRangeC(rangeQueryBuilder, ck, value); regQ(rangeQueryBuilder); return rangeQueryBuilder; } protected void addRangeC(RangeQueryBuilder builder, ConditionKey ck, Object value) { assertObjectNotNull("ck", ck); if (ck.equals(ConditionKey.CK_GREATER_THAN)) { builder.gt(value); } else if (ck.equals(ConditionKey.CK_GREATER_EQUAL)) { builder.gte(value); } else if (ck.equals(ConditionKey.CK_LESS_THAN)) { builder.lt(value); } else if (ck.equals(ConditionKey.CK_LESS_EQUAL)) { builder.lte(value); } } protected ExistsQueryBuilder regExistsQ(String name) { ExistsQueryBuilder existsQuery = QueryBuilders.existsQuery(name); regQ(existsQuery); return existsQuery; } protected WildcardQueryBuilder regWildcardQ(String name, String wildcard) { checkEsInvalidQuery(name, wildcard); WildcardQueryBuilder wildcardQuery = QueryBuilders.wildcardQuery(name, wildcard); regQ(wildcardQuery); return wildcardQuery; } protected RegexpQueryBuilder regRegexpQ(String name, String regexp) { checkEsInvalidQuery(name, regexp); RegexpQueryBuilder regexpQuery = QueryBuilders.regexpQuery(name, regexp); regQ(regexpQuery); return regexpQuery; } protected CommonTermsQueryBuilder regCommonTermsQ(String name, Object text) { checkEsInvalidQuery(name, text); CommonTermsQueryBuilder commonTermsQuery = QueryBuilders.commonTermsQuery(name, text); regQ(commonTermsQuery); return commonTermsQuery; } protected MoreLikeThisQueryBuilder regMoreLikeThisQueryQ(String name, String[] likeTexts) { MoreLikeThisQueryBuilder moreLikeThisQuery = QueryBuilders.moreLikeThisQuery(new String[] { name }, likeTexts, null); regQ(moreLikeThisQuery); return moreLikeThisQuery; } protected SpanTermQueryBuilder regSpanTermQ(String name, String value) { checkEsInvalidQuery(name, value); SpanTermQueryBuilder spanTermQuery = QueryBuilders.spanTermQuery(name, value); regQ(spanTermQuery); return spanTermQuery; } protected void regQ(QueryBuilder builder) { assertObjectNotNull("builder", builder); if (queryBuilderList == null) { queryBuilderList = new ArrayList<>(); } queryBuilderList.add(builder); } protected void regOBA(String field) { registerOrderBy(field, true); } protected void regOBD(String field) { registerOrderBy(field, false); } protected void registerOrderBy(String field, boolean ascOrDesc) { assertObjectNotNull("field", field); if (fieldSortBuilderList == null) { fieldSortBuilderList = new ArrayList<>(); } fieldSortBuilderList.add(SortBuilders.fieldSort(field).order(ascOrDesc ? SortOrder.ASC : SortOrder.DESC)); } // =================================================================================== // Invalid Query // ============= protected void checkEsInvalidQuery(String name, Object value) { if (value == null || (value instanceof String && ((String) value).isEmpty())) { String msg = "Cannot register null or empty query: name=" + name + " value=" + value; throw new InvalidQueryRegisteredException(msg); } } protected void checkEsInvalidQueryCollection(String name, Collection<?> values) { if (values == null || values.isEmpty()) { String msg = "Cannot register null or empty query collection: name=" + name + " values=" + values; throw new InvalidQueryRegisteredException(msg); } } // =================================================================================== // DBFlute Implementation // ====================== @Override public ColumnRealName toColumnRealName(String columnDbName) { return ColumnRealName.create(xgetAliasName(), toColumnSqlName(columnDbName)); } @Override public ColumnRealName toColumnRealName(ColumnInfo columnInfo) { return ColumnRealName.create(xgetAliasName(), columnInfo.getColumnSqlName()); } @Override public ColumnSqlName toColumnSqlName(String columnDbName) { return new ColumnSqlName(columnDbName); } @Override public ConditionBean xgetBaseCB() { return null; } @Override public ConditionQuery xgetBaseQuery() { return null; } @Override public ConditionQuery xgetReferrerQuery() { return null; } @Override public SqlClause xgetSqlClause() { return null; } @Override public int xgetNestLevel() { return 0; } @Override public int xgetNextNestLevel() { return 0; } @Override public boolean isBaseQuery() { return false; } @Override public String xgetForeignPropertyName() { return null; } @Override public String xgetRelationPath() { return null; } @Override public String xgetLocationBase() { final StringBuilder sb = new StringBuilder(); ConditionQuery query = this; while (true) { if (query.isBaseQuery()) { sb.insert(0, CQ_PROPERTY + "."); break; } else { final String foreignPropertyName = query.xgetForeignPropertyName(); if (foreignPropertyName == null) { String msg = "The foreignPropertyName of the query should not be null:"; msg = msg + " query=" + query; throw new IllegalStateException(msg); } sb.insert(0, CQ_PROPERTY + Srl.initCap(foreignPropertyName) + "."); } query = query.xgetReferrerQuery(); } return sb.toString(); } @Override public ConditionValue invokeValue(String columnFlexibleName) { return null; } @Override public void invokeQuery(String columnFlexibleName, String conditionKeyName, Object conditionValue) { // nothing } @Override public void invokeQuery(String columnFlexibleName, String conditionKeyName, Object conditionValue, ConditionOption conditionOption) { // nothing } @Override public void invokeQueryEqual(String columnFlexibleName, Object conditionValue) { // nothing } @Override public void invokeQueryNotEqual(String columnFlexibleName, Object conditionValue) { // nothing } @Override public void invokeOrderBy(String columnFlexibleName, boolean isAsc) { // nothing } @Override public ConditionQuery invokeForeignCQ(String foreignPropertyName) { return null; } @Override public boolean invokeHasForeignCQ(String foreignPropertyName) { return false; } @Override public void xregisterParameterOption(ParameterOption option) { // nothing } // =================================================================================== // General Helper // ============== protected void assertObjectNotNull(String variableName, Object value) { if (variableName == null) { String msg = "The value should not be null: variableName=null value=" + value; throw new IllegalArgumentException(msg); } if (value == null) { String msg = "The value should not be null: variableName=" + variableName; throw new IllegalArgumentException(msg); } } protected String toRangeDateString(Date date, String format) { if (format.contains("epoch_millis")) { return Long.toString(date.getTime()); } else if (format.contains("date_optional_time")) { final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); return sdf.format(date); } else { return Long.toString(date.getTime()); } } protected String toRangeLocalDateTimeString(LocalDateTime date, String format) { if (format.contains("epoch_millis")) { return Long.toString(date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); } else if (format.contains("date_optional_time")) { return DateTimeFormatter.ISO_DATE_TIME.format(date); } else { return Long.toString(date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); } } // =================================================================================== // Assist Class // ============ public class DocMetaCQ { public void setId_Equal(String id) { regQ(QueryBuilders.idsQuery(asTableDbName()).addIds(id)); } } @FunctionalInterface public interface ConditionOptionCall<OP extends QueryBuilder> { /** * @param op The option of condition to be set up. (NotNull) */ void callback(OP op); } @FunctionalInterface public interface BoolCall<CQ extends EsAbstractConditionQuery> { void callback(CQ must, CQ should, CQ mustNot, CQ filter); } @FunctionalInterface public interface FilteredCall<CQ extends EsAbstractConditionQuery, CF extends EsAbstractConditionQuery> { void callback(CQ query, CF filter); } @FunctionalInterface public interface OperatorCall<CQ extends EsAbstractConditionQuery> { void callback(CQ query); } @FunctionalInterface public interface ScoreFunctionCall<CC extends ScoreFunctionCreator<?>> { void callback(CC creator); } @FunctionalInterface public interface ScoreFunctionCreator<T extends EsAbstractConditionQuery> { void filter(final OperatorCall<T> cqLambda, final ScoreFunctionBuilder scoreFunctionBuilder); } }