fix #2828 Add configurable DisMax query support for default field searches
This commit is contained in:
parent
4a010e703d
commit
64f7bf0332
8 changed files with 425 additions and 17 deletions
|
@ -1110,6 +1110,15 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
/** The key of the configuration. e.g. true */
|
||||
String QUERY_BOOST_FUZZY_CONTENT_TRANSPOSITIONS = "query.boost.fuzzy.content.transpositions";
|
||||
|
||||
/** The key of the configuration. e.g. bool */
|
||||
String QUERY_DEFAULT_query_type = "query.default.query_type";
|
||||
|
||||
/** The key of the configuration. e.g. 0.1 */
|
||||
String QUERY_DISMAX_tie_breaker = "query.dismax.tie_breaker";
|
||||
|
||||
/** The key of the configuration. e.g. */
|
||||
String QUERY_BOOL_minimum_should_match = "query.bool.minimum_should_match";
|
||||
|
||||
/** The key of the configuration. e.g. 50 */
|
||||
String QUERY_PREFIX_EXPANSIONS = "query.prefix.expansions";
|
||||
|
||||
|
@ -5244,6 +5253,43 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
*/
|
||||
boolean isQueryBoostFuzzyContentTranspositions();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'query.default.query_type'. <br>
|
||||
* The value is, e.g. bool <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getQueryDefaultQueryType();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'query.dismax.tie_breaker'. <br>
|
||||
* The value is, e.g. 0.1 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getQueryDismaxTieBreaker();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'query.dismax.tie_breaker' as {@link java.math.BigDecimal}. <br>
|
||||
* The value is, e.g. 0.1 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
* @throws NumberFormatException When the property is not decimal.
|
||||
*/
|
||||
java.math.BigDecimal getQueryDismaxTieBreakerAsDecimal();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'query.bool.minimum_should_match'. <br>
|
||||
* The value is, e.g. <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getQueryBoolMinimumShouldMatch();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'query.bool.minimum_should_match' as {@link Integer}. <br>
|
||||
* The value is, e.g. <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
* @throws NumberFormatException When the property is not integer.
|
||||
*/
|
||||
Integer getQueryBoolMinimumShouldMatchAsInteger();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'query.prefix.expansions'. <br>
|
||||
* The value is, e.g. 50 <br>
|
||||
|
@ -9489,6 +9535,26 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
return is(FessConfig.QUERY_BOOST_FUZZY_CONTENT_TRANSPOSITIONS);
|
||||
}
|
||||
|
||||
public String getQueryDefaultQueryType() {
|
||||
return get(FessConfig.QUERY_DEFAULT_query_type);
|
||||
}
|
||||
|
||||
public String getQueryDismaxTieBreaker() {
|
||||
return get(FessConfig.QUERY_DISMAX_tie_breaker);
|
||||
}
|
||||
|
||||
public java.math.BigDecimal getQueryDismaxTieBreakerAsDecimal() {
|
||||
return getAsDecimal(FessConfig.QUERY_DISMAX_tie_breaker);
|
||||
}
|
||||
|
||||
public String getQueryBoolMinimumShouldMatch() {
|
||||
return get(FessConfig.QUERY_BOOL_minimum_should_match);
|
||||
}
|
||||
|
||||
public Integer getQueryBoolMinimumShouldMatchAsInteger() {
|
||||
return getAsInteger(FessConfig.QUERY_BOOL_minimum_should_match);
|
||||
}
|
||||
|
||||
public String getQueryPrefixExpansions() {
|
||||
return get(FessConfig.QUERY_PREFIX_EXPANSIONS);
|
||||
}
|
||||
|
@ -11158,6 +11224,9 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
defaultMap.put(FessConfig.QUERY_BOOST_FUZZY_CONTENT_EXPANSIONS, "10");
|
||||
defaultMap.put(FessConfig.QUERY_BOOST_FUZZY_CONTENT_prefix_length, "0");
|
||||
defaultMap.put(FessConfig.QUERY_BOOST_FUZZY_CONTENT_TRANSPOSITIONS, "true");
|
||||
defaultMap.put(FessConfig.QUERY_DEFAULT_query_type, "bool");
|
||||
defaultMap.put(FessConfig.QUERY_DISMAX_tie_breaker, "0.1");
|
||||
defaultMap.put(FessConfig.QUERY_BOOL_minimum_should_match, "");
|
||||
defaultMap.put(FessConfig.QUERY_PREFIX_EXPANSIONS, "50");
|
||||
defaultMap.put(FessConfig.QUERY_PREFIX_SLOP, "0");
|
||||
defaultMap.put(FessConfig.QUERY_FUZZY_prefix_length, "0");
|
||||
|
|
148
src/main/java/org/codelibs/fess/query/DefaultQueryBuilder.java
Normal file
148
src/main/java/org/codelibs/fess/query/DefaultQueryBuilder.java
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.query;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.opensearch.core.common.io.stream.StreamOutput;
|
||||
import org.opensearch.core.xcontent.XContentBuilder;
|
||||
import org.opensearch.index.query.BoolQueryBuilder;
|
||||
import org.opensearch.index.query.DisMaxQueryBuilder;
|
||||
import org.opensearch.index.query.QueryBuilder;
|
||||
import org.opensearch.index.query.QueryBuilderVisitor;
|
||||
import org.opensearch.index.query.QueryRewriteContext;
|
||||
import org.opensearch.index.query.QueryShardContext;
|
||||
|
||||
public class DefaultQueryBuilder implements QueryBuilder {
|
||||
|
||||
private final QueryBuilder queryBuilder;
|
||||
|
||||
private final QueryType queryType;
|
||||
|
||||
public DefaultQueryBuilder(final QueryBuilder queryBuilder) {
|
||||
this.queryBuilder = queryBuilder;
|
||||
if (queryBuilder instanceof BoolQueryBuilder) {
|
||||
queryType = QueryType.BOOL;
|
||||
} else if (queryBuilder instanceof DisMaxQueryBuilder) {
|
||||
queryType = QueryType.DISMAX;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown query builder: " + queryBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
public DefaultQueryBuilder add(final QueryBuilder innerQueryBuilder) {
|
||||
switch (queryType) {
|
||||
case BOOL:
|
||||
((BoolQueryBuilder) queryBuilder).should(innerQueryBuilder);
|
||||
break;
|
||||
case DISMAX:
|
||||
((DisMaxQueryBuilder) queryBuilder).add(innerQueryBuilder);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
enum QueryType {
|
||||
BOOL, DISMAX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteableName() {
|
||||
return queryBuilder.getWriteableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query toQuery(final QueryShardContext context) throws IOException {
|
||||
return queryBuilder.toQuery(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragment() {
|
||||
return queryBuilder.isFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryBuilder queryName(final String queryName) {
|
||||
return queryBuilder.queryName(queryName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryName() {
|
||||
return queryBuilder.queryName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float boost() {
|
||||
return queryBuilder.boost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryBuilder boost(final float boost) {
|
||||
return queryBuilder.boost(boost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return queryBuilder.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryBuilder rewrite(final QueryRewriteContext queryShardContext) throws IOException {
|
||||
return queryBuilder.rewrite(queryShardContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(final QueryBuilderVisitor visitor) {
|
||||
queryBuilder.visit(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
|
||||
return queryBuilder.toXContent(builder, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(final StreamOutput out) throws IOException {
|
||||
queryBuilder.writeTo(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return queryBuilder.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if ((obj == null) || (getClass() != obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
final DefaultQueryBuilder other = (DefaultQueryBuilder) obj;
|
||||
return Objects.equals(queryBuilder, other.queryBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return queryBuilder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,7 @@ import static org.codelibs.core.stream.StreamUtil.stream;
|
|||
import java.lang.Character.UnicodeBlock;
|
||||
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.fess.Constants;
|
||||
import org.codelibs.fess.entity.QueryContext;
|
||||
import org.codelibs.fess.mylasta.direction.FessConfig;
|
||||
|
@ -27,6 +28,7 @@ import org.codelibs.fess.util.ComponentUtil;
|
|||
import org.dbflute.optional.OptionalThing;
|
||||
import org.lastaflute.web.util.LaRequestUtil;
|
||||
import org.opensearch.index.query.BoolQueryBuilder;
|
||||
import org.opensearch.index.query.DisMaxQueryBuilder;
|
||||
import org.opensearch.index.query.QueryBuilder;
|
||||
import org.opensearch.index.query.QueryBuilders;
|
||||
import org.opensearch.search.sort.SortBuilder;
|
||||
|
@ -72,30 +74,47 @@ public abstract class QueryCommand {
|
|||
(String[]) request.getAttribute(Constants.REQUEST_LANGUAGES)));
|
||||
}
|
||||
|
||||
protected BoolQueryBuilder buildDefaultQueryBuilder(final FessConfig fessConfig, final QueryContext context,
|
||||
protected DefaultQueryBuilder buildDefaultQueryBuilder(final FessConfig fessConfig, final QueryContext context,
|
||||
final DefaultQueryBuilderFunction builder) {
|
||||
final BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
|
||||
boolQuery.should(builder.apply(fessConfig.getIndexFieldTitle(), fessConfig.getQueryBoostTitleAsDecimal().floatValue()));
|
||||
boolQuery.should(builder.apply(fessConfig.getIndexFieldContent(), fessConfig.getQueryBoostContentAsDecimal().floatValue()));
|
||||
final DefaultQueryBuilder defaultQuery = createDefaultQueryBuilder();
|
||||
defaultQuery.add(builder.apply(fessConfig.getIndexFieldTitle(), fessConfig.getQueryBoostTitleAsDecimal().floatValue()));
|
||||
defaultQuery.add(builder.apply(fessConfig.getIndexFieldContent(), fessConfig.getQueryBoostContentAsDecimal().floatValue()));
|
||||
final float importantContentBoost = fessConfig.getQueryBoostImportantContentAsDecimal().floatValue();
|
||||
if (importantContentBoost >= 0.0f) {
|
||||
boolQuery.should(builder.apply(fessConfig.getIndexFieldImportantContent(), importantContentBoost));
|
||||
defaultQuery.add(builder.apply(fessConfig.getIndexFieldImportantContent(), importantContentBoost));
|
||||
}
|
||||
final float importantContantLangBoost = fessConfig.getQueryBoostImportantContentLangAsDecimal().floatValue();
|
||||
getQueryLanguages().ifPresent(langs -> stream(langs).of(stream -> stream.forEach(lang -> {
|
||||
boolQuery.should(
|
||||
defaultQuery.add(
|
||||
builder.apply(fessConfig.getIndexFieldTitle() + "_" + lang, fessConfig.getQueryBoostTitleLangAsDecimal().floatValue()));
|
||||
boolQuery.should(builder.apply(fessConfig.getIndexFieldContent() + "_" + lang,
|
||||
defaultQuery.add(builder.apply(fessConfig.getIndexFieldContent() + "_" + lang,
|
||||
fessConfig.getQueryBoostContentLangAsDecimal().floatValue()));
|
||||
if (importantContantLangBoost >= 0.0f) {
|
||||
boolQuery.should(builder.apply(fessConfig.getIndexFieldImportantContent() + "_" + lang, importantContantLangBoost));
|
||||
defaultQuery.add(builder.apply(fessConfig.getIndexFieldImportantContent() + "_" + lang, importantContantLangBoost));
|
||||
}
|
||||
})));
|
||||
getQueryFieldConfig().additionalDefaultList.stream().forEach(f -> {
|
||||
final QueryBuilder query = builder.apply(f.getFirst(), f.getSecond());
|
||||
boolQuery.should(query);
|
||||
defaultQuery.add(query);
|
||||
});
|
||||
return boolQuery;
|
||||
return defaultQuery;
|
||||
}
|
||||
|
||||
protected DefaultQueryBuilder createDefaultQueryBuilder() {
|
||||
final FessConfig fessConfig = ComponentUtil.getFessConfig();
|
||||
|
||||
if ("dismax".equals(fessConfig.getQueryDefaultQueryType())) {
|
||||
final DisMaxQueryBuilder disMaxQuery = QueryBuilders.disMaxQuery();
|
||||
disMaxQuery.tieBreaker(fessConfig.getQueryDismaxTieBreakerAsDecimal().floatValue());
|
||||
return new DefaultQueryBuilder(disMaxQuery);
|
||||
}
|
||||
|
||||
final BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
|
||||
final String minimumShouldMatch = fessConfig.getQueryBoolMinimumShouldMatch();
|
||||
if (StringUtil.isNotBlank(minimumShouldMatch)) {
|
||||
boolQuery.minimumShouldMatch(minimumShouldMatch);
|
||||
}
|
||||
return new DefaultQueryBuilder(boolQuery);
|
||||
}
|
||||
|
||||
protected QueryBuilder buildMatchPhraseQuery(final String f, final String text) {
|
||||
|
|
|
@ -34,7 +34,6 @@ import org.codelibs.fess.mylasta.direction.FessConfig;
|
|||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.lastaflute.core.message.UserMessages;
|
||||
import org.opensearch.common.unit.Fuzziness;
|
||||
import org.opensearch.index.query.BoolQueryBuilder;
|
||||
import org.opensearch.index.query.QueryBuilder;
|
||||
import org.opensearch.index.query.QueryBuilders;
|
||||
import org.opensearch.search.sort.SortOrder;
|
||||
|
@ -161,24 +160,24 @@ public class TermQueryCommand extends QueryCommand {
|
|||
final float boost, final String field, final String text) {
|
||||
context.addFieldLog(field, text);
|
||||
context.addHighlightedQuery(text);
|
||||
final BoolQueryBuilder boolQuery =
|
||||
final DefaultQueryBuilder defaultQuery =
|
||||
buildDefaultQueryBuilder(fessConfig, context, (f, b) -> buildMatchPhraseQuery(f, text).boost(b * boost));
|
||||
final Integer fuzzyMinLength = fessConfig.getQueryBoostFuzzyMinLengthAsInteger();
|
||||
if (fuzzyMinLength >= 0 && text.length() >= fuzzyMinLength) {
|
||||
boolQuery.should(QueryBuilders.fuzzyQuery(fessConfig.getIndexFieldTitle(), text)
|
||||
defaultQuery.add(QueryBuilders.fuzzyQuery(fessConfig.getIndexFieldTitle(), text)
|
||||
.boost(fessConfig.getQueryBoostFuzzyTitleAsDecimal().floatValue())
|
||||
.prefixLength(fessConfig.getQueryBoostFuzzyTitlePrefixLengthAsInteger())
|
||||
.transpositions(Constants.TRUE.equalsIgnoreCase(fessConfig.getQueryBoostFuzzyTitleTranspositions()))
|
||||
.fuzziness(Fuzziness.build(fessConfig.getQueryBoostFuzzyTitleFuzziness()))
|
||||
.maxExpansions(fessConfig.getQueryBoostFuzzyTitleExpansionsAsInteger()));
|
||||
boolQuery.should(QueryBuilders.fuzzyQuery(fessConfig.getIndexFieldContent(), text)
|
||||
defaultQuery.add(QueryBuilders.fuzzyQuery(fessConfig.getIndexFieldContent(), text)
|
||||
.prefixLength(fessConfig.getQueryBoostFuzzyContentPrefixLengthAsInteger())
|
||||
.transpositions(Constants.TRUE.equalsIgnoreCase(fessConfig.getQueryBoostFuzzyContentTranspositions()))
|
||||
.boost(fessConfig.getQueryBoostFuzzyContentAsDecimal().floatValue())
|
||||
.fuzziness(Fuzziness.build(fessConfig.getQueryBoostFuzzyContentFuzziness()))
|
||||
.maxExpansions(fessConfig.getQueryBoostFuzzyContentExpansionsAsInteger()));
|
||||
}
|
||||
return boolQuery;
|
||||
return defaultQuery;
|
||||
}
|
||||
|
||||
protected QueryBuilder convertSiteQuery(final FessConfig fessConfig, final QueryContext context, final TermQuery termQuery,
|
||||
|
|
|
@ -570,6 +570,10 @@ query.boost.fuzzy.content.expansions=10
|
|||
query.boost.fuzzy.content.prefix_length=0
|
||||
query.boost.fuzzy.content.transpositions=true
|
||||
|
||||
query.default.query_type=bool
|
||||
query.dismax.tie_breaker=0.1
|
||||
query.bool.minimum_should_match=
|
||||
|
||||
query.prefix.expansions=50
|
||||
query.prefix.slop=0
|
||||
query.fuzzy.prefix_length=0
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.codelibs.fess.helper;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -27,6 +28,7 @@ import org.codelibs.fess.Constants;
|
|||
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.query.BooleanQueryCommand;
|
||||
import org.codelibs.fess.query.BoostQueryCommand;
|
||||
import org.codelibs.fess.query.FuzzyQueryCommand;
|
||||
|
@ -41,6 +43,7 @@ import org.codelibs.fess.query.WildcardQueryCommand;
|
|||
import org.codelibs.fess.query.parser.QueryParser;
|
||||
import org.codelibs.fess.unit.UnitFessTestCase;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.dbflute.util.DfTypeUtil;
|
||||
import org.opensearch.index.query.BoolQueryBuilder;
|
||||
import org.opensearch.index.query.QueryBuilder;
|
||||
import org.opensearch.index.query.QueryBuilders;
|
||||
|
@ -88,7 +91,54 @@ public class QueryHelperTest extends UnitFessTestCase {
|
|||
new WildcardQueryCommand().register();
|
||||
}
|
||||
|
||||
private void setQueryType(final String queryType) {
|
||||
final FessConfig fessConfig = ComponentUtil.getFessConfig();
|
||||
ComponentUtil.setFessConfig(new FessConfig.SimpleImpl() {
|
||||
@Override
|
||||
public String get(String propertyKey) {
|
||||
return fessConfig.get(propertyKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getAsDecimal(String propertyKey) {
|
||||
return DfTypeUtil.toBigDecimal(get(propertyKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getAsInteger(String propertyKey) {
|
||||
return DfTypeUtil.toInteger(get(propertyKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryDefaultQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void test_build_simple() {
|
||||
setQueryType("bool");
|
||||
|
||||
float titleBoost = 0.5f;
|
||||
float contentBoost = 0.05f;
|
||||
|
||||
assertQuery(functionScoreQuery(simpleQuery("QUERY", titleBoost, contentBoost)), //
|
||||
Map.of("_default", List.of("QUERY")), //
|
||||
Set.of("QUERY"), //
|
||||
buildQuery("QUERY"));
|
||||
assertQuery(functionScoreQuery(simpleQuery("QUERY", titleBoost, contentBoost)), //
|
||||
Map.of("_default", List.of("QUERY")), //
|
||||
Set.of("QUERY"), //
|
||||
buildQuery(" QUERY"));
|
||||
assertQuery(functionScoreQuery(simpleQuery("QUERY", titleBoost, contentBoost)), //
|
||||
Map.of("_default", List.of("QUERY")), //
|
||||
Set.of("QUERY"), //
|
||||
buildQuery("QUERY "));
|
||||
}
|
||||
|
||||
public void test_build_simple_dismax() {
|
||||
setQueryType("dismax");
|
||||
|
||||
float titleBoost = 0.5f;
|
||||
float contentBoost = 0.05f;
|
||||
|
||||
|
@ -133,6 +183,7 @@ public class QueryHelperTest extends UnitFessTestCase {
|
|||
}
|
||||
|
||||
public void test_build_boost() {
|
||||
setQueryType("bool");
|
||||
assertQueryContext(
|
||||
"{\"function_score\":{\"query\":{\"bool\":{\"should\":[{\"match_phrase\":{\"title\":{\"query\":\"QUERY1\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":5.0}}},{\"match_phrase\":{\"content\":{\"query\":\"QUERY1\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.5}}},{\"fuzzy\":{\"title\":{\"value\":\"QUERY1\",\"fuzziness\":\"AUTO\",\"prefix_length\":0,\"max_expansions\":10,\"transpositions\":true,\"boost\":0.01}}},{\"fuzzy\":{\"content\":{\"value\":\"QUERY1\",\"fuzziness\":\"AUTO\",\"prefix_length\":0,\"max_expansions\":10,\"transpositions\":true,\"boost\":0.005}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"functions\":[{\"filter\":{\"match_all\":{\"boost\":1.0}},\"field_value_factor\":{\"field\":\"boost\",\"factor\":1.0,\"modifier\":\"none\"}}],\"score_mode\":\"multiply\",\"max_boost\":3.4028235E38,\"boost\":1.0}}",
|
||||
Map.of("_default", List.of("QUERY1")), //
|
||||
|
@ -153,6 +204,7 @@ public class QueryHelperTest extends UnitFessTestCase {
|
|||
}
|
||||
|
||||
public void test_build_wildcard() {
|
||||
setQueryType("bool");
|
||||
assertQueryContext(
|
||||
"{\"function_score\":{\"query\":{\"bool\":{\"should\":[{\"wildcard\":{\"title\":{\"wildcard\":\"*\",\"boost\":0.5}}},{\"wildcard\":{\"content\":{\"wildcard\":\"*\",\"boost\":0.05}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"functions\":[{\"filter\":{\"match_all\":{\"boost\":1.0}},\"field_value_factor\":{\"field\":\"boost\",\"factor\":1.0,\"modifier\":\"none\"}}],\"score_mode\":\"multiply\",\"max_boost\":3.4028235E38,\"boost\":1.0}}",
|
||||
Map.of("_default", List.of("*")), //
|
||||
|
@ -191,6 +243,7 @@ public class QueryHelperTest extends UnitFessTestCase {
|
|||
}
|
||||
|
||||
public void test_build_phrase() {
|
||||
setQueryType("bool");
|
||||
assertQueryContext(
|
||||
"{\"function_score\":{\"query\":{\"bool\":{\"should\":[{\"match_phrase\":{\"title\":{\"query\":\"QUERY1QUERY2\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.5}}},{\"match_phrase\":{\"content\":{\"query\":\"QUERY1QUERY2\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.05}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"functions\":[{\"filter\":{\"match_all\":{\"boost\":1.0}},\"field_value_factor\":{\"field\":\"boost\",\"factor\":1.0,\"modifier\":\"none\"}}],\"score_mode\":\"multiply\",\"max_boost\":3.4028235E38,\"boost\":1.0}}",
|
||||
Map.of("_default", List.of("QUERY1 QUERY2")), //
|
||||
|
@ -207,6 +260,7 @@ public class QueryHelperTest extends UnitFessTestCase {
|
|||
}
|
||||
|
||||
public void test_build_prefix() {
|
||||
setQueryType("bool");
|
||||
assertQueryContext(
|
||||
"{\"function_score\":{\"query\":{\"bool\":{\"should\":[{\"match_phrase_prefix\":{\"title\":{\"query\":\"query\",\"slop\":0,\"max_expansions\":50,\"zero_terms_query\":\"NONE\",\"boost\":0.5}}},{\"match_phrase_prefix\":{\"content\":{\"query\":\"query\",\"slop\":0,\"max_expansions\":50,\"zero_terms_query\":\"NONE\",\"boost\":0.05}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"functions\":[{\"filter\":{\"match_all\":{\"boost\":1.0}},\"field_value_factor\":{\"field\":\"boost\",\"factor\":1.0,\"modifier\":\"none\"}}],\"score_mode\":\"multiply\",\"max_boost\":3.4028235E38,\"boost\":1.0}}",
|
||||
Map.of("_default", List.of("QUERY*")), //
|
||||
|
@ -229,6 +283,7 @@ public class QueryHelperTest extends UnitFessTestCase {
|
|||
}
|
||||
|
||||
public void test_build_escape() {
|
||||
setQueryType("bool");
|
||||
assertQueryContext(
|
||||
"{\"function_score\":{\"query\":{\"bool\":{\"should\":[{\"match_phrase\":{\"title\":{\"query\":\"aaa:bbb\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.5}}},{\"match_phrase\":{\"content\":{\"query\":\"aaa:bbb\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.05}}},{\"fuzzy\":{\"title\":{\"value\":\"aaa:bbb\",\"fuzziness\":\"AUTO\",\"prefix_length\":0,\"max_expansions\":10,\"transpositions\":true,\"boost\":0.01}}},{\"fuzzy\":{\"content\":{\"value\":\"aaa:bbb\",\"fuzziness\":\"AUTO\",\"prefix_length\":0,\"max_expansions\":10,\"transpositions\":true,\"boost\":0.005}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"functions\":[{\"filter\":{\"match_all\":{\"boost\":1.0}},\"field_value_factor\":{\"field\":\"boost\",\"factor\":1.0,\"modifier\":\"none\"}}],\"score_mode\":\"multiply\",\"max_boost\":3.4028235E38,\"boost\":1.0}}",
|
||||
Map.of("_default", List.of("aaa:bbb")), //
|
||||
|
@ -335,6 +390,7 @@ public class QueryHelperTest extends UnitFessTestCase {
|
|||
}
|
||||
|
||||
public void test_build_fuzzy() {
|
||||
setQueryType("bool");
|
||||
assertQueryContext(
|
||||
"{\"function_score\":{\"query\":{\"bool\":{\"should\":[{\"fuzzy\":{\"title\":{\"value\":\"QUERY1\",\"fuzziness\":\"2\",\"prefix_length\":0,\"max_expansions\":50,\"transpositions\":true,\"boost\":0.5}}},{\"fuzzy\":{\"content\":{\"value\":\"QUERY1\",\"fuzziness\":\"2\",\"prefix_length\":0,\"max_expansions\":50,\"transpositions\":true,\"boost\":0.05}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"functions\":[{\"filter\":{\"match_all\":{\"boost\":1.0}},\"field_value_factor\":{\"field\":\"boost\",\"factor\":1.0,\"modifier\":\"none\"}}],\"score_mode\":\"multiply\",\"max_boost\":3.4028235E38,\"boost\":1.0}}",
|
||||
Map.of("_default", List.of("QUERY1")), //
|
||||
|
@ -357,6 +413,7 @@ public class QueryHelperTest extends UnitFessTestCase {
|
|||
}
|
||||
|
||||
public void test_build_range() {
|
||||
setQueryType("bool");
|
||||
assertQueryContext(
|
||||
"{\"function_score\":{\"query\":{\"bool\":{\"should\":[{\"match_phrase\":{\"title\":{\"query\":\"[aaaTObbb]\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.5}}},{\"match_phrase\":{\"content\":{\"query\":\"[aaaTObbb]\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.05}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"functions\":[{\"filter\":{\"match_all\":{\"boost\":1.0}},\"field_value_factor\":{\"field\":\"boost\",\"factor\":1.0,\"modifier\":\"none\"}}],\"score_mode\":\"multiply\",\"max_boost\":3.4028235E38,\"boost\":1.0}}",
|
||||
Map.of("_default", List.of("[aaa TO bbb]")), //
|
||||
|
@ -439,6 +496,14 @@ public class QueryHelperTest extends UnitFessTestCase {
|
|||
}
|
||||
|
||||
private QueryBuilder simpleQuery(String query, float titleBoost, float contentBoost) {
|
||||
if ("dismax".equals(ComponentUtil.getFessConfig().getQueryDefaultQueryType())) {
|
||||
return QueryBuilders.disMaxQuery().tieBreaker(0.1f)//
|
||||
.add(QueryBuilders.matchPhraseQuery("title", query).boost(titleBoost))//
|
||||
.add(QueryBuilders.matchPhraseQuery("content", query).boost(contentBoost))//
|
||||
.add(QueryBuilders.fuzzyQuery("title", query).boost(0.01f).maxExpansions(10))//
|
||||
.add(QueryBuilders.fuzzyQuery("content", query).boost(0.005f).maxExpansions(10))//
|
||||
;
|
||||
}
|
||||
return QueryBuilders.boolQuery()//
|
||||
.should(QueryBuilders.matchPhraseQuery("title", query).boost(titleBoost))//
|
||||
.should(QueryBuilders.matchPhraseQuery("content", query).boost(contentBoost))//
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.query;
|
||||
|
||||
import org.codelibs.fess.unit.UnitFessTestCase;
|
||||
import org.opensearch.index.query.QueryBuilders;
|
||||
|
||||
public class DefaultQueryBuilderTest extends UnitFessTestCase {
|
||||
public void test_invalid_null() {
|
||||
try {
|
||||
new DefaultQueryBuilder(null);
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
public void test_invalid_query() {
|
||||
try {
|
||||
new DefaultQueryBuilder(QueryBuilders.matchAllQuery());
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.codelibs.fess.query;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
@ -23,9 +24,11 @@ import org.apache.lucene.search.Query;
|
|||
import org.apache.lucene.search.TermQuery;
|
||||
import org.codelibs.fess.entity.QueryContext;
|
||||
import org.codelibs.fess.exception.InvalidQueryException;
|
||||
import org.codelibs.fess.mylasta.direction.FessConfig;
|
||||
import org.codelibs.fess.query.parser.QueryParser;
|
||||
import org.codelibs.fess.unit.UnitFessTestCase;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.dbflute.util.DfTypeUtil;
|
||||
import org.opensearch.index.query.BoolQueryBuilder;
|
||||
import org.opensearch.index.query.MatchPhraseQueryBuilder;
|
||||
import org.opensearch.index.query.PrefixQueryBuilder;
|
||||
|
@ -60,8 +63,34 @@ public class TermQueryCommandTest extends UnitFessTestCase {
|
|||
super.tearDown();
|
||||
}
|
||||
|
||||
private void setQueryType(final String queryType) {
|
||||
final FessConfig fessConfig = ComponentUtil.getFessConfig();
|
||||
ComponentUtil.setFessConfig(new FessConfig.SimpleImpl() {
|
||||
@Override
|
||||
public String get(String propertyKey) {
|
||||
return fessConfig.get(propertyKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getAsDecimal(String propertyKey) {
|
||||
return DfTypeUtil.toBigDecimal(get(propertyKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getAsInteger(String propertyKey) {
|
||||
return DfTypeUtil.toInteger(get(propertyKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryDefaultQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void test_convertTermQuery() throws Exception {
|
||||
assertQueryBuilder(BoolQueryBuilder.class,
|
||||
setQueryType("bool");
|
||||
assertQueryBuilder(DefaultQueryBuilder.class,
|
||||
"{\"bool\":{\"should\":[{\"match_phrase\":{\"title\":{\"query\":\"aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.5}}},{\"match_phrase\":{\"content\":{\"query\":\"aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.05}}}],\"adjust_pure_negative\":true,\"boost\":1.0}}",
|
||||
"aaa");
|
||||
assertQueryBuilder(MatchPhraseQueryBuilder.class,
|
||||
|
@ -70,7 +99,7 @@ public class TermQueryCommandTest extends UnitFessTestCase {
|
|||
assertQueryBuilder(MatchPhraseQueryBuilder.class,
|
||||
"{\"match_phrase\":{\"content\":{\"query\":\"aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":1.0}}}", //
|
||||
"content:aaa");
|
||||
assertQueryBuilder(BoolQueryBuilder.class,
|
||||
assertQueryBuilder(DefaultQueryBuilder.class,
|
||||
"{\"bool\":{\"should\":[{\"match_phrase\":{\"title\":{\"query\":\"xxx:aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.5}}},{\"match_phrase\":{\"content\":{\"query\":\"xxx:aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.05}}},{\"fuzzy\":{\"title\":{\"value\":\"xxx:aaa\",\"fuzziness\":\"AUTO\",\"prefix_length\":0,\"max_expansions\":10,\"transpositions\":true,\"boost\":0.01}}},{\"fuzzy\":{\"content\":{\"value\":\"xxx:aaa\",\"fuzziness\":\"AUTO\",\"prefix_length\":0,\"max_expansions\":10,\"transpositions\":true,\"boost\":0.005}}}],\"adjust_pure_negative\":true,\"boost\":1.0}}",
|
||||
"xxx:aaa");
|
||||
assertQueryBuilder(WildcardQueryBuilder.class, //
|
||||
|
@ -95,6 +124,42 @@ public class TermQueryCommandTest extends UnitFessTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public void test_convertTermQuery_dismax() throws Exception {
|
||||
setQueryType("dismax");
|
||||
assertQueryBuilder(DefaultQueryBuilder.class,
|
||||
"{\"dis_max\":{\"tie_breaker\":0.1,\"queries\":[{\"match_phrase\":{\"title\":{\"query\":\"aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.5}}},{\"match_phrase\":{\"content\":{\"query\":\"aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.05}}}],\"boost\":1.0}}",
|
||||
"aaa");
|
||||
assertQueryBuilder(MatchPhraseQueryBuilder.class,
|
||||
"{\"match_phrase\":{\"title\":{\"query\":\"aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":1.0}}}", //
|
||||
"title:aaa");
|
||||
assertQueryBuilder(MatchPhraseQueryBuilder.class,
|
||||
"{\"match_phrase\":{\"content\":{\"query\":\"aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":1.0}}}", //
|
||||
"content:aaa");
|
||||
assertQueryBuilder(DefaultQueryBuilder.class,
|
||||
"{\"dis_max\":{\"tie_breaker\":0.1,\"queries\":[{\"match_phrase\":{\"title\":{\"query\":\"xxx:aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.5}}},{\"match_phrase\":{\"content\":{\"query\":\"xxx:aaa\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.05}}},{\"fuzzy\":{\"title\":{\"value\":\"xxx:aaa\",\"fuzziness\":\"AUTO\",\"prefix_length\":0,\"max_expansions\":10,\"transpositions\":true,\"boost\":0.01}}},{\"fuzzy\":{\"content\":{\"value\":\"xxx:aaa\",\"fuzziness\":\"AUTO\",\"prefix_length\":0,\"max_expansions\":10,\"transpositions\":true,\"boost\":0.005}}}],\"boost\":1.0}}",
|
||||
"xxx:aaa");
|
||||
assertQueryBuilder(WildcardQueryBuilder.class, //
|
||||
"{\"wildcard\":{\"url\":{\"wildcard\":\"*aaa*\",\"boost\":1.0}}}", //
|
||||
"inurl:aaa");
|
||||
assertQueryBuilder(TermQueryBuilder.class, //
|
||||
"{\"term\":{\"url\":{\"value\":\"aaa\",\"boost\":1.0}}}", //
|
||||
"url:aaa");
|
||||
assertQueryBuilder(PrefixQueryBuilder.class, //
|
||||
"{\"prefix\":{\"site\":{\"value\":\"aaa\",\"boost\":1.0}}}", //
|
||||
"site:aaa");
|
||||
|
||||
assertQueryBuilder("{\"timestamp\":{\"order\":\"asc\"}}", "sort:timestamp");
|
||||
assertQueryBuilder("{\"timestamp\":{\"order\":\"asc\"}}", "sort:timestamp.asc");
|
||||
assertQueryBuilder("{\"timestamp\":{\"order\":\"desc\"}}", "sort:timestamp.desc");
|
||||
|
||||
try {
|
||||
assertQueryBuilder("", "sort:xxx");
|
||||
fail();
|
||||
} catch (InvalidQueryException e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
private void assertQueryBuilder(final String expect, final String text) throws Exception {
|
||||
QueryContext queryContext = assertQueryBuilder(null, null, text);
|
||||
List<SortBuilder<?>> sortBuilders = queryContext.sortBuilders();
|
||||
|
|
Loading…
Add table
Reference in a new issue