fix #2778 Implement phrase query handling for single-word terms enclosed in quotes
This commit is contained in:
parent
79cd2a60bd
commit
6d0530a778
3 changed files with 159 additions and 2 deletions
|
@ -25,7 +25,10 @@ import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
|
|||
import org.apache.lucene.queryparser.classic.ParseException;
|
||||
import org.apache.lucene.queryparser.classic.QueryParser.Operator;
|
||||
import org.apache.lucene.queryparser.ext.ExtendableQueryParser;
|
||||
import org.apache.lucene.queryparser.ext.Extensions.Pair;
|
||||
import org.apache.lucene.search.PhraseQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.codelibs.fess.Constants;
|
||||
import org.codelibs.fess.exception.QueryParseException;
|
||||
|
||||
|
@ -53,7 +56,7 @@ public class QueryParser {
|
|||
}
|
||||
|
||||
protected org.apache.lucene.queryparser.classic.QueryParser createQueryParser() {
|
||||
final ExtendableQueryParser parser = new ExtendableQueryParser(defaultField, analyzer);
|
||||
final LuceneQueryParser parser = new LuceneQueryParser(defaultField, analyzer);
|
||||
parser.setAllowLeadingWildcard(allowLeadingWildcard);
|
||||
parser.setDefaultOperator(defaultOperator);
|
||||
return parser;
|
||||
|
@ -109,4 +112,43 @@ public class QueryParser {
|
|||
public interface FilterChain {
|
||||
Query parse(final String query);
|
||||
}
|
||||
|
||||
protected static class LuceneQueryParser extends org.apache.lucene.queryparser.classic.QueryParser {
|
||||
|
||||
private final String defaultField;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExtendableQueryParser} instance
|
||||
*
|
||||
* @param f the default query field
|
||||
* @param a the analyzer used to find terms in a query string
|
||||
*/
|
||||
public LuceneQueryParser(final String f, final Analyzer a) {
|
||||
super(f, a);
|
||||
this.defaultField = f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query getFieldQuery(final String field, final String queryText, boolean quoted) throws ParseException {
|
||||
final org.apache.lucene.search.Query query = super.getFieldQuery(field, queryText, quoted);
|
||||
if (quoted && query instanceof TermQuery termQuery) {
|
||||
final Pair<String, String> splitField = splitField(defaultField, field);
|
||||
if (defaultField.equals(splitField.cur)) {
|
||||
final PhraseQuery.Builder builder = new PhraseQuery.Builder();
|
||||
builder.add(termQuery.getTerm());
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
protected Pair<String, String> splitField(String defaultField, String field) {
|
||||
int indexOf = field.indexOf(':');
|
||||
if (indexOf < 0)
|
||||
return new Pair<>(field, null);
|
||||
final String indexField = indexOf == 0 ? defaultField : field.substring(0, indexOf);
|
||||
final String extensionKey = field.substring(indexOf + 1);
|
||||
return new Pair<>(indexField, extensionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,7 +234,9 @@ public class QueryHelperTest extends UnitFessTestCase {
|
|||
Map.of("_default", List.of("aaa:bbb")), //
|
||||
Set.of("aaa:bbb"), //
|
||||
buildQuery("aaa\\:bbb"));
|
||||
assertQueryContext(buildQuery("aaa\\:bbb").getQueryBuilder().toString().replaceAll("\\s", ""), buildQuery("\"aaa\\:bbb\""));
|
||||
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}}}],\"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}}",
|
||||
buildQuery("\"aaa\\:bbb\""));
|
||||
|
||||
assertQueryContext(
|
||||
"{\"function_score\":{\"query\":{\"match_phrase\":{\"title\":{\"query\":\"aaa:bbb\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"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}}",
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright 2012-2023 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.parser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.BoostQuery;
|
||||
import org.apache.lucene.search.FuzzyQuery;
|
||||
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.WildcardQuery;
|
||||
import org.codelibs.fess.unit.UnitFessTestCase;
|
||||
|
||||
public class QueryParserTest extends UnitFessTestCase {
|
||||
|
||||
public void test_LuceneQueryParser() {
|
||||
QueryParser queryParser = new QueryParser();
|
||||
|
||||
Query query = queryParser.createDefaultFilterChain().parse("fess");
|
||||
assertEquals(TermQuery.class, query.getClass());
|
||||
assertEquals("_default:fess", ((TermQuery) query).getTerm().toString());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("title:fess");
|
||||
assertEquals(TermQuery.class, query.getClass());
|
||||
assertEquals("title:fess", ((TermQuery) query).getTerm().toString());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("fess*");
|
||||
assertEquals(PrefixQuery.class, query.getClass());
|
||||
assertEquals("_default:fess", ((PrefixQuery) query).getPrefix().toString());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("fe?s");
|
||||
assertEquals(WildcardQuery.class, query.getClass());
|
||||
assertEquals("_default:fe?s", ((WildcardQuery) query).getTerm().toString());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("fess~");
|
||||
assertEquals(FuzzyQuery.class, query.getClass());
|
||||
assertEquals("_default:fess", ((FuzzyQuery) query).getTerm().toString());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("fess^10");
|
||||
assertEquals(BoostQuery.class, query.getClass());
|
||||
assertEquals("_default:fess", ((BoostQuery) query).getQuery().toString());
|
||||
assertEquals(10.0f, ((BoostQuery) query).getBoost());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("\"fess\"");
|
||||
assertEquals(PhraseQuery.class, query.getClass());
|
||||
assertEquals("_default:fess", ((PhraseQuery) query).getTerms()[0].toString());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("\"fess codelibs\"");
|
||||
assertEquals(PhraseQuery.class, query.getClass());
|
||||
assertEquals("_default:fess", ((PhraseQuery) query).getTerms()[0].toString());
|
||||
assertEquals("_default:codelibs", ((PhraseQuery) query).getTerms()[1].toString());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("fess codelibs");
|
||||
assertEquals(BooleanQuery.class, query.getClass());
|
||||
List<BooleanClause> clauses = ((BooleanQuery) query).clauses();
|
||||
assertEquals(TermQuery.class, clauses.get(0).getQuery().getClass());
|
||||
assertEquals("_default:fess", clauses.get(0).getQuery().toString());
|
||||
assertEquals(Occur.MUST, clauses.get(0).getOccur());
|
||||
assertEquals(TermQuery.class, clauses.get(1).getQuery().getClass());
|
||||
assertEquals("_default:codelibs", clauses.get(1).getQuery().toString());
|
||||
assertEquals(Occur.MUST, clauses.get(1).getOccur());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("fess AND codelibs");
|
||||
assertEquals(BooleanQuery.class, query.getClass());
|
||||
clauses = ((BooleanQuery) query).clauses();
|
||||
assertEquals(TermQuery.class, clauses.get(0).getQuery().getClass());
|
||||
assertEquals("_default:fess", clauses.get(0).getQuery().toString());
|
||||
assertEquals(Occur.MUST, clauses.get(0).getOccur());
|
||||
assertEquals(TermQuery.class, clauses.get(1).getQuery().getClass());
|
||||
assertEquals("_default:codelibs", clauses.get(1).getQuery().toString());
|
||||
assertEquals(Occur.MUST, clauses.get(1).getOccur());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("fess OR codelibs");
|
||||
assertEquals(BooleanQuery.class, query.getClass());
|
||||
clauses = ((BooleanQuery) query).clauses();
|
||||
assertEquals(TermQuery.class, clauses.get(0).getQuery().getClass());
|
||||
assertEquals("_default:fess", clauses.get(0).getQuery().toString());
|
||||
assertEquals(Occur.SHOULD, clauses.get(0).getOccur());
|
||||
assertEquals(TermQuery.class, clauses.get(1).getQuery().getClass());
|
||||
assertEquals("_default:codelibs", clauses.get(1).getQuery().toString());
|
||||
assertEquals(Occur.SHOULD, clauses.get(1).getOccur());
|
||||
|
||||
query = queryParser.createDefaultFilterChain().parse("\"fess\" codelibs");
|
||||
assertEquals(BooleanQuery.class, query.getClass());
|
||||
clauses = ((BooleanQuery) query).clauses();
|
||||
assertEquals(PhraseQuery.class, clauses.get(0).getQuery().getClass());
|
||||
assertEquals("_default:fess", ((PhraseQuery) clauses.get(0).getQuery()).getTerms()[0].toString());
|
||||
assertEquals(Occur.MUST, clauses.get(0).getOccur());
|
||||
assertEquals(TermQuery.class, clauses.get(1).getQuery().getClass());
|
||||
assertEquals("_default:codelibs", clauses.get(1).getQuery().toString());
|
||||
assertEquals(Occur.MUST, clauses.get(1).getOccur());
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue