/*
* 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.helper;
import static org.codelibs.core.stream.StreamUtil.stream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.Stream;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.util.BytesRef;
import org.codelibs.core.lang.StringUtil;
import org.codelibs.fess.Constants;
import org.codelibs.fess.entity.FacetInfo;
import org.codelibs.fess.entity.GeoInfo;
import org.codelibs.fess.entity.QueryContext;
import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType;
import org.codelibs.fess.exception.InvalidQueryException;
import org.codelibs.fess.mylasta.direction.FessConfig;
import org.codelibs.fess.util.ComponentUtil;
import org.dbflute.optional.OptionalThing;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder.FilterFunctionBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.lastaflute.core.message.UserMessages;
import org.lastaflute.web.util.LaRequestUtil;
public class QueryHelper {
private static final String ES_SCORE_FIELD = "_score";
protected static final String SCORE_SORT_VALUE = "score";
protected static final String SCORE_FIELD = "score";
protected static final String INURL_FIELD = "inurl";
@Resource
protected FessConfig fessConfig;
@Resource
protected RoleQueryHelper roleQueryHelper;
@Resource
protected SystemHelper systemHelper;
@Resource
protected KeyMatchHelper keyMatchHelper;
protected Set<String> apiResponseFieldSet;
protected Set<String> highlightFieldSet = new HashSet<>();
protected Set<String> notAnalyzedFieldSet;
protected String[] responseFields;
protected String[] cacheResponseFields;
protected String[] highlightedFields;
protected String[] searchFields;
protected String[] facetFields;
protected String sortPrefix = "sort:";
protected String[] sortFields;
protected String additionalQuery;
protected boolean lowercaseWildcard = true;
protected long timeAllowed = -1;
protected SortBuilder[] defaultSortBuilders;
protected String highlightPrefix = "hl_";
protected FacetInfo defaultFacetInfo;
protected GeoInfo defaultGeoInfo;
protected Map<String, String> fieldBoostMap = new HashMap<>();
@PostConstruct
public void init() {
if (responseFields == null) {
responseFields = fessConfig.getQueryAdditionalResponseFields(//
SCORE_FIELD, //
fessConfig.getIndexFieldId(), //
fessConfig.getIndexFieldDocId(), //
fessConfig.getIndexFieldBoost(), //
fessConfig.getIndexFieldContentLength(), //
fessConfig.getIndexFieldHost(), //
fessConfig.getIndexFieldSite(), //
fessConfig.getIndexFieldLastModified(), //
fessConfig.getIndexFieldTimestamp(), //
fessConfig.getIndexFieldMimetype(), //
fessConfig.getIndexFieldFiletype(), //
fessConfig.getIndexFieldFilename(), //
fessConfig.getIndexFieldCreated(), //
fessConfig.getIndexFieldTitle(), //
fessConfig.getIndexFieldDigest(), //
fessConfig.getIndexFieldUrl(), //
fessConfig.getIndexFieldClickCount(), //
fessConfig.getIndexFieldFavoriteCount(), //
fessConfig.getIndexFieldConfigId(), //
fessConfig.getIndexFieldLang(), //
fessConfig.getIndexFieldHasCache());
}
if (cacheResponseFields == null) {
cacheResponseFields = fessConfig.getQueryAdditionalCacheResponseFields(//
SCORE_FIELD, //
fessConfig.getIndexFieldId(), //
fessConfig.getIndexFieldDocId(), //
fessConfig.getIndexFieldBoost(), //
fessConfig.getIndexFieldContentLength(), //
fessConfig.getIndexFieldHost(), //
fessConfig.getIndexFieldSite(), //
fessConfig.getIndexFieldLastModified(), //
fessConfig.getIndexFieldTimestamp(), //
fessConfig.getIndexFieldMimetype(), //
fessConfig.getIndexFieldFiletype(), //
fessConfig.getIndexFieldFilename(), //
fessConfig.getIndexFieldCreated(), //
fessConfig.getIndexFieldTitle(), //
fessConfig.getIndexFieldDigest(), //
fessConfig.getIndexFieldUrl(), //
fessConfig.getIndexFieldClickCount(), //
fessConfig.getIndexFieldFavoriteCount(), //
fessConfig.getIndexFieldConfigId(), //
fessConfig.getIndexFieldLang(), //
fessConfig.getIndexFieldCache());
}
if (highlightedFields == null) {
highlightedFields = fessConfig.getQueryAdditionalHighlightedFields(fessConfig.getIndexFieldContent());
}
if (searchFields == null) {
searchFields = fessConfig.getQueryAdditionalSearchFields(//
INURL_FIELD, //
fessConfig.getIndexFieldUrl(), //
fessConfig.getIndexFieldDocId(), //
fessConfig.getIndexFieldHost(), //
fessConfig.getIndexFieldTitle(), //
fessConfig.getIndexFieldContent(), //
fessConfig.getIndexFieldContentLength(), //
fessConfig.getIndexFieldLastModified(), //
fessConfig.getIndexFieldTimestamp(), //
fessConfig.getIndexFieldMimetype(), //
fessConfig.getIndexFieldFiletype(), //
fessConfig.getIndexFieldFilename(), //
fessConfig.getIndexFieldLabel(), //
fessConfig.getIndexFieldSegment(), //
fessConfig.getIndexFieldClickCount(), //
fessConfig.getIndexFieldFavoriteCount(), //
fessConfig.getIndexFieldLang());
}
if (facetFields == null) {
facetFields = fessConfig.getQueryAdditionalFacetFields(//
fessConfig.getIndexFieldUrl(), //
fessConfig.getIndexFieldHost(), //
fessConfig.getIndexFieldTitle(), //
fessConfig.getIndexFieldContent(), //
fessConfig.getIndexFieldContentLength(), //
fessConfig.getIndexFieldLastModified(), //
fessConfig.getIndexFieldTimestamp(), //
fessConfig.getIndexFieldMimetype(), //
fessConfig.getIndexFieldFiletype(), //
fessConfig.getIndexFieldLabel(), //
fessConfig.getIndexFieldSegment());
}
if (sortFields == null) {
sortFields = fessConfig.getQueryAdditionalSortFields(//
SCORE_SORT_VALUE, //
fessConfig.getIndexFieldFilename(), //
fessConfig.getIndexFieldCreated(), //
fessConfig.getIndexFieldContentLength(), //
fessConfig.getIndexFieldLastModified(), //
fessConfig.getIndexFieldTimestamp(), //
fessConfig.getIndexFieldClickCount(), //
fessConfig.getIndexFieldFavoriteCount());
}
if (apiResponseFieldSet == null) {
setApiResponseFields(fessConfig.getQueryAdditionalApiResponseFields(//
fessConfig.getResponseFieldContentDescription(), //
fessConfig.getResponseFieldContentTitle(), //
fessConfig.getResponseFieldSitePath(), //
fessConfig.getResponseFieldUrlLink(), //
fessConfig.getIndexFieldId(), //
fessConfig.getIndexFieldDocId(), //
fessConfig.getIndexFieldBoost(), //
fessConfig.getIndexFieldContentLength(), //
fessConfig.getIndexFieldHost(), //
fessConfig.getIndexFieldSite(), //
fessConfig.getIndexFieldLastModified(), //
fessConfig.getIndexFieldTimestamp(), //
fessConfig.getIndexFieldMimetype(), //
fessConfig.getIndexFieldFiletype(), //
fessConfig.getIndexFieldFilename(), //
fessConfig.getIndexFieldCreated(), //
fessConfig.getIndexFieldTitle(), //
fessConfig.getIndexFieldDigest(), //
fessConfig.getIndexFieldUrl()));
}
if (notAnalyzedFieldSet == null) {
setNotAnalyzedFields(fessConfig.getQueryAdditionalNotAnalyzedFields(//
fessConfig.getIndexFieldAnchor(), //
fessConfig.getIndexFieldBoost(), //
fessConfig.getIndexFieldClickCount(), //
fessConfig.getIndexFieldConfigId(), //
fessConfig.getIndexFieldContentLength(), //
fessConfig.getIndexFieldCreated(), //
fessConfig.getIndexFieldDocId(), //
fessConfig.getIndexFieldExpires(), //
fessConfig.getIndexFieldFavoriteCount(), //
fessConfig.getIndexFieldFiletype(), //
fessConfig.getIndexFieldFilename(), //
fessConfig.getIndexFieldHasCache(), //
fessConfig.getIndexFieldHost(), //
fessConfig.getIndexFieldId(), //
fessConfig.getIndexFieldLabel(), //
fessConfig.getIndexFieldLang(), //
fessConfig.getIndexFieldLastModified(), //
fessConfig.getIndexFieldMimetype(), //
fessConfig.getIndexFieldParentId(), //
fessConfig.getIndexFieldRole(), //
fessConfig.getIndexFieldSegment(), //
fessConfig.getIndexFieldSite(), //
fessConfig.getIndexFieldTimestamp(), //
fessConfig.getIndexFieldUrl(), //
fessConfig.getIndexFieldVersion()));
}
}
public QueryContext build(final SearchRequestType searchRequestType, final String query, final Consumer<QueryContext> context) {
String q;
if (additionalQuery != null && StringUtil.isNotBlank(query)) {
q = query + " " + additionalQuery;
} else {
q = query;
}
final QueryContext queryContext = new QueryContext(q, true);
buildBaseQuery(queryContext, context);
buildBoostQuery(queryContext);
buildRoleQuery(queryContext, searchRequestType);
if (!queryContext.hasSorts() && defaultSortBuilders != null) {
queryContext.addSorts(defaultSortBuilders);
}
return queryContext;
}
protected void buildRoleQuery(final QueryContext queryContext, final SearchRequestType searchRequestType) {
if (roleQueryHelper != null && queryContext.roleQueryEnabled()) {
final Set<String> roleSet = roleQueryHelper.build(searchRequestType);
if (!roleSet.isEmpty()) {
queryContext.addQuery(boolQuery -> {
final BoolQueryBuilder roleQuery = QueryBuilders.boolQuery();
roleSet.stream().forEach(name -> {
roleQuery.should(QueryBuilders.termQuery(fessConfig.getIndexFieldRole(), name));
});
boolQuery.filter(roleQuery);
});
}
}
}
protected void buildBoostQuery(final QueryContext queryContext) {
queryContext.addFunctionScore(list -> {
list.add(new FilterFunctionBuilder(ScoreFunctionBuilders.fieldValueFactorFunction(fessConfig.getIndexFieldBoost())));
if (keyMatchHelper != null) {
keyMatchHelper.buildQuery(queryContext.getDefaultKeyword(), list);
}
});
}
public void buildBaseQuery(final QueryContext queryContext, final Consumer<QueryContext> context) {
try {
final Query query = getQueryParser().parse(queryContext.getQueryString());
final QueryBuilder queryBuilder = convertQuery(queryContext, query, 1.0f);
if (queryBuilder != null) {
queryContext.setQueryBuilder(queryBuilder);
} else {
queryContext.setQueryBuilder(QueryBuilders.matchAllQuery());
}
// TODO options query
context.accept(queryContext);
} catch (final ParseException e) {
throw new InvalidQueryException(messages -> messages.addErrorsInvalidQueryParseError(UserMessages.GLOBAL_PROPERTY_KEY),
"Invalid query: " + queryContext.getQueryString(), e);
}
}
protected QueryParser getQueryParser() {
return ComponentUtil.getQueryParser();
}
protected QueryBuilder convertQuery(final QueryContext context, final Query query, final float boost) {
if (query instanceof TermQuery) {
return convertTermQuery(context, (TermQuery) query, boost);
} else if (query instanceof TermRangeQuery) {
return convertTermRangeQuery(context, (TermRangeQuery) query, boost);
} else if (query instanceof PhraseQuery) {
return convertPhraseQuery(context, (PhraseQuery) query, boost);
} else if (query instanceof FuzzyQuery) {
return convertFuzzyQuery(context, (FuzzyQuery) query, boost);
} else if (query instanceof PrefixQuery) {
return convertPrefixQuery(context, (PrefixQuery) query, boost);
} else if (query instanceof WildcardQuery) {
return convertWildcardQuery(context, (WildcardQuery) query, boost);
} else if (query instanceof BooleanQuery) {
final BooleanQuery booleanQuery = (BooleanQuery) query;
return convertBooleanQuery(context, booleanQuery, boost);
} else if (query instanceof MatchAllDocsQuery) {
return QueryBuilders.matchAllQuery();
} else if (query instanceof BoostQuery) {
final BoostQuery boostQuery = (BoostQuery) query;
return convertQuery(context, boostQuery.getQuery(), boostQuery.getBoost());
}
throw new InvalidQueryException(messages -> messages.addErrorsInvalidQueryUnknown(UserMessages.GLOBAL_PROPERTY_KEY), "Unknown q: "
+ query.getClass() + " => " + query);
}
protected QueryBuilder convertBooleanQuery(final QueryContext context, final BooleanQuery booleanQuery, final float boost) {
final BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
for (final BooleanClause clause : booleanQuery.clauses()) {
final QueryBuilder queryBuilder = convertQuery(context, clause.getQuery(), boost);
if (queryBuilder != null) {
switch (clause.getOccur()) {
case MUST:
boolQuery.must(queryBuilder);
break;
case SHOULD:
boolQuery.should(queryBuilder);
break;
case MUST_NOT:
boolQuery.mustNot(queryBuilder);
break;
default:
break;
}
}
}
return boolQuery;
}
protected String toLowercaseWildcard(final String value) {
if (lowercaseWildcard) {
return value.toLowerCase(Locale.ROOT);
}
return value;
}
protected QueryBuilder convertWildcardQuery(final QueryContext context, final WildcardQuery wildcardQuery, final float boost) {
final String field = wildcardQuery.getField();
if (Constants.DEFAULT_FIELD.equals(field)) {
context.addFieldLog(field, wildcardQuery.getTerm().text());
return buildDefaultQueryBuilder((f, b) -> QueryBuilders.wildcardQuery(f, toLowercaseWildcard(wildcardQuery.getTerm().text()))
.boost(b * boost));
} else if (isSearchField(field)) {
context.addFieldLog(field, wildcardQuery.getTerm().text());
return QueryBuilders.wildcardQuery(field, toLowercaseWildcard(wildcardQuery.getTerm().text())).boost(boost);
} else {
final String query = wildcardQuery.getTerm().toString();
final String origQuery = toLowercaseWildcard(query);
context.addFieldLog(Constants.DEFAULT_FIELD, query);
context.addHighlightedQuery(origQuery);
return buildDefaultQueryBuilder((f, b) -> QueryBuilders.wildcardQuery(f, origQuery).boost(b * boost));
}
}
protected QueryBuilder convertPrefixQuery(final QueryContext context, final PrefixQuery prefixQuery, final float boost) {
final String field = prefixQuery.getField();
if (Constants.DEFAULT_FIELD.equals(field)) {
context.addFieldLog(field, prefixQuery.getPrefix().text());
return buildDefaultQueryBuilder((f, b) -> QueryBuilders.prefixQuery(f, toLowercaseWildcard(prefixQuery.getPrefix().text()))
.boost(b * boost));
} else if (isSearchField(field)) {
context.addFieldLog(field, prefixQuery.getPrefix().text());
return QueryBuilders.prefixQuery(field, toLowercaseWildcard(prefixQuery.getPrefix().text())).boost(boost);
} else {
final String query = prefixQuery.getPrefix().toString();
final String origQuery = toLowercaseWildcard(query);
context.addFieldLog(Constants.DEFAULT_FIELD, query);
context.addHighlightedQuery(origQuery);
return buildDefaultQueryBuilder((f, b) -> QueryBuilders.prefixQuery(f, origQuery).boost(b * boost));
}
}
protected QueryBuilder convertFuzzyQuery(final QueryContext context, final FuzzyQuery fuzzyQuery, final float boost) {
final Term term = fuzzyQuery.getTerm();
final String field = term.field();
// TODO fuzzy value
if (Constants.DEFAULT_FIELD.equals(field)) {
context.addFieldLog(field, term.text());
return buildDefaultQueryBuilder((f, b) -> QueryBuilders.fuzzyQuery(f, term.text())
.fuzziness(Fuzziness.fromEdits(fuzzyQuery.getMaxEdits())).boost(b * boost));
} else if (isSearchField(field)) {
context.addFieldLog(field, term.text());
return QueryBuilders.fuzzyQuery(field, term.text()).boost(boost).fuzziness(Fuzziness.fromEdits(fuzzyQuery.getMaxEdits()));
} else {
final String origQuery = fuzzyQuery.toString();
context.addFieldLog(Constants.DEFAULT_FIELD, origQuery);
context.addHighlightedQuery(origQuery);
return buildDefaultQueryBuilder((f, b) -> QueryBuilders.fuzzyQuery(f, origQuery)
.fuzziness(Fuzziness.fromEdits(fuzzyQuery.getMaxEdits())).boost(b * boost));
}
}
protected QueryBuilder convertTermRangeQuery(final QueryContext context, final TermRangeQuery termRangeQuery, final float boost) {
final String field = termRangeQuery.getField();
if (isSearchField(field)) {
context.addFieldLog(field, termRangeQuery.toString(field));
final RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(field);
final BytesRef min = termRangeQuery.getLowerTerm();
if (min != null) {
if (termRangeQuery.includesLower()) {
rangeQuery.gte(min.utf8ToString());
} else {
rangeQuery.gt(min.utf8ToString());
}
}
final BytesRef max = termRangeQuery.getUpperTerm();
if (max != null) {
if (termRangeQuery.includesUpper()) {
rangeQuery.lte(max.utf8ToString());
} else {
rangeQuery.lt(max.utf8ToString());
}
}
rangeQuery.boost(boost);
return rangeQuery;
} else {
final String origQuery = termRangeQuery.toString();
context.addFieldLog(Constants.DEFAULT_FIELD, origQuery);
context.addHighlightedQuery(origQuery);
return buildDefaultQueryBuilder((f, b) -> QueryBuilders.matchPhraseQuery(f, origQuery).boost(b));
}
}
protected QueryBuilder convertTermQuery(final QueryContext context, final TermQuery termQuery, final float boost) {
final String field = termQuery.getTerm().field();
final String text = termQuery.getTerm().text();
if (fessConfig.getQueryReplaceTermWithPrefixQueryAsBoolean() && text.length() > 1 && text.endsWith("*")) {
return convertPrefixQuery(context, new PrefixQuery(new Term(field, text.substring(0, text.length() - 1))), boost);
} else if (Constants.DEFAULT_FIELD.equals(field)) {
context.addFieldLog(field, text);
context.addHighlightedQuery(text);
return buildDefaultQueryBuilder((f, b) -> QueryBuilders.matchPhraseQuery(f, text).boost(b * boost));
} else if ("sort".equals(field)) {
final String[] values = text.split("\\.");
if (values.length > 2) {
throw new InvalidQueryException(
messages -> messages.addErrorsInvalidQuerySortValue(UserMessages.GLOBAL_PROPERTY_KEY, text), "Invalid sort field: "
+ termQuery);
}
final String sortField = values[0];
if (!isSortField(sortField)) {
throw new InvalidQueryException(messages -> messages.addErrorsInvalidQueryUnsupportedSortField(
UserMessages.GLOBAL_PROPERTY_KEY, sortField), "Unsupported sort field: " + termQuery);
}
SortOrder sortOrder;
if (values.length == 2) {
sortOrder = SortOrder.DESC.toString().equalsIgnoreCase(values[1]) ? SortOrder.DESC : SortOrder.ASC;
if (sortOrder == null) {
throw new InvalidQueryException(messages -> messages.addErrorsInvalidQueryUnsupportedSortOrder(
UserMessages.GLOBAL_PROPERTY_KEY, values[1]), "Invalid sort order: " + termQuery);
}
} else {
sortOrder = SortOrder.ASC;
}
context.addSorts(createFieldSortBuilder(sortField, sortOrder));
return null;
} else if (INURL_FIELD.equals(field)) {
return QueryBuilders.wildcardQuery(fessConfig.getIndexFieldUrl(), "*" + text + "*").boost(boost);
} else if (isSearchField(field)) {
context.addFieldLog(field, text);
context.addHighlightedQuery(text);
if (notAnalyzedFieldSet.contains(field)) {
return QueryBuilders.termQuery(field, text).boost(boost);
} else {
return QueryBuilders.matchPhraseQuery(field, text).boost(boost);
}
} else {
final String origQuery = termQuery.toString();
context.addFieldLog(Constants.DEFAULT_FIELD, origQuery);
context.addHighlightedQuery(origQuery);
return buildDefaultQueryBuilder((f, b) -> QueryBuilders.matchPhraseQuery(f, origQuery).boost(b * boost));
}
}
private QueryBuilder convertPhraseQuery(final QueryContext context, final PhraseQuery query, final float boost) {
final Term[] terms = query.getTerms();
if (terms.length == 0) {
throw new InvalidQueryException(messages -> messages.addErrorsInvalidQueryUnknown(UserMessages.GLOBAL_PROPERTY_KEY),
"Unknown phrase query: " + query);
}
final String field = terms[0].field();
final String[] texts = stream(terms).get(stream -> stream.map(term -> term.text()).toArray(n -> new String[n]));
final String text = String.join(" ", texts);
context.addFieldLog(field, text);
stream(texts).of(stream -> stream.forEach(t -> context.addHighlightedQuery(t)));
return buildDefaultQueryBuilder((f, b) -> QueryBuilders.matchPhraseQuery(f, text).boost(b * boost));
}
private boolean isSearchField(final String field) {
for (final String searchField : searchFields) {
if (searchField.equals(field)) {
return true;
}
}
return false;
}
private QueryBuilder buildDefaultQueryBuilder(final DefaultQueryBuilderFunction builder) {
final BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
final QueryBuilder titleQuery =
builder.apply(fessConfig.getIndexFieldTitle(), fessConfig.getQueryBoostTitleAsDecimal().floatValue());
boolQuery.should(titleQuery);
final QueryBuilder contentQuery =
builder.apply(fessConfig.getIndexFieldContent(), fessConfig.getQueryBoostContentAsDecimal().floatValue());
boolQuery.should(contentQuery);
getQueryLanguages().ifPresent(
langs -> {
stream(langs).of(
stream -> stream.forEach(lang -> {
final QueryBuilder titleLangQuery =
builder.apply(fessConfig.getIndexFieldTitle() + "_" + lang, fessConfig
.getQueryBoostTitleLangAsDecimal().floatValue());
boolQuery.should(titleLangQuery);
final QueryBuilder contentLangQuery =
builder.apply(fessConfig.getIndexFieldContent() + "_" + lang, fessConfig
.getQueryBoostContentLangAsDecimal().floatValue());
boolQuery.should(contentLangQuery);
}));
});
return boolQuery;
}
interface DefaultQueryBuilderFunction {
QueryBuilder apply(String field, float boost);
}
protected OptionalThing<String[]> getQueryLanguages() {
return LaRequestUtil.getOptionalRequest()
.map(request -> fessConfig.getQueryLanguages(request.getLocales(),
(String[]) request.getAttribute(Constants.REQUEST_LANGUAGES)));
}
private boolean isSortField(final String field) {
for (final String f : sortFields) {
if (f.equals(field)) {
return true;
}
}
return false;
}
public boolean isFacetField(final String field) {
if (StringUtil.isBlank(field)) {
return false;
}
boolean flag = false;
for (final String f : facetFields) {
if (field.equals(f)) {
flag = true;
}
}
return flag;
}
public boolean isFacetSortValue(final String sort) {
return "count".equals(sort) || "index".equals(sort);
}
public void setApiResponseFields(final String[] fields) {
apiResponseFieldSet = new HashSet<>();
for (final String field : fields) {
apiResponseFieldSet.add(field);
}
}
public void setNotAnalyzedFields(final String[] fields) {
notAnalyzedFieldSet = new HashSet<>();
for (final String field : fields) {
notAnalyzedFieldSet.add(field);
}
}
public boolean isApiResponseField(final String field) {
return apiResponseFieldSet.contains(field);
}
/**
* @return the responseFields
*/
public String[] getResponseFields() {
return responseFields;
}
/**
* @param responseFields the responseFields to set
*/
public void setResponseFields(final String[] responseFields) {
this.responseFields = responseFields;
}
public String[] getCacheResponseFields() {
return cacheResponseFields;
}
public void setCacheResponseFields(final String[] cacheResponseFields) {
this.cacheResponseFields = cacheResponseFields;
}
/**
* @return the highlightedFields
*/
public String[] getHighlightedFields() {
return highlightedFields;
}
/**
* @param highlightedFields the highlightedFields to set
*/
public void setHighlightedFields(final String[] highlightedFields) {
this.highlightedFields = highlightedFields;
}
public void highlightedFields(final Consumer<Stream<String>> stream) {
stream(highlightedFields).of(stream);
}
/**
* @return the supportedFields
*/
public String[] getSearchFields() {
return searchFields;
}
/**
* @param supportedFields the supportedFields to set
*/
public void setSearchFields(final String[] supportedFields) {
searchFields = supportedFields;
}
/**
* @return the facetFields
*/
public String[] getFacetFields() {
return facetFields;
}
/**
* @param facetFields the facetFields to set
*/
public void setFacetFields(final String[] facetFields) {
this.facetFields = facetFields;
}
/**
* @return the sortPrefix
*/
public String getSortPrefix() {
return sortPrefix;
}
/**
* @param sortPrefix the sortPrefix to set
*/
public void setSortPrefix(final String sortPrefix) {
this.sortPrefix = sortPrefix;
}
/**
* @return the sortFields
*/
public String[] getSortFields() {
return sortFields;
}
/**
* @param sortFields the sortFields to set
*/
public void setSortFields(final String[] sortFields) {
this.sortFields = sortFields;
}
public void addHighlightField(final String field) {
highlightFieldSet.add(field);
}
/**
* @return the additionalQuery
*/
public String getAdditionalQuery() {
return additionalQuery;
}
/**
* @param additionalQuery the additionalQuery to set
*/
public void setAdditionalQuery(final String additionalQuery) {
this.additionalQuery = additionalQuery;
}
/**
* @return the timeAllowed
*/
public long getTimeAllowed() {
return timeAllowed;
}
/**
* @param timeAllowed the timeAllowed to set
*/
public void setTimeAllowed(final long timeAllowed) {
this.timeAllowed = timeAllowed;
}
public void addDefaultSort(final String fieldName, final String order) {
final List<SortBuilder> list = new ArrayList<>();
if (defaultSortBuilders != null) {
stream(defaultSortBuilders).of(stream -> stream.forEach(builder -> list.add(builder)));
}
list.add(createFieldSortBuilder(fieldName, SortOrder.DESC.toString().equalsIgnoreCase(order) ? SortOrder.DESC : SortOrder.ASC));
defaultSortBuilders = list.toArray(new SortBuilder[list.size()]);
}
protected FieldSortBuilder createFieldSortBuilder(final String field, final SortOrder order) {
final String fieldName = SCORE_FIELD.equals(field) ? ES_SCORE_FIELD : field;
final FieldSortBuilder builder = SortBuilders.fieldSort(fieldName);
if (ES_SCORE_FIELD.equals(fieldName)) {
builder.unmappedType("float");
}
return builder.order(order);
}
public void setHighlightPrefix(final String highlightPrefix) {
this.highlightPrefix = highlightPrefix;
}
public String getHighlightPrefix() {
return highlightPrefix;
}
public FacetInfo getDefaultFacetInfo() {
return defaultFacetInfo;
}
public void setDefaultFacetInfo(final FacetInfo defaultFacetInfo) {
this.defaultFacetInfo = defaultFacetInfo;
}
public GeoInfo getDefaultGeoInfo() {
return defaultGeoInfo;
}
public void setDefaultGeoInfo(final GeoInfo defaultGeoInfo) {
this.defaultGeoInfo = defaultGeoInfo;
}
public String generateId() {
return UUID.randomUUID().toString().replace("-", StringUtil.EMPTY);
}
public void setLowercaseWildcard(final boolean lowercaseWildcard) {
this.lowercaseWildcard = lowercaseWildcard;
}
}