/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.solr.search; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.complexPhrase.ComplexPhraseQueryParser; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.StrUtils; import org.apache.solr.parser.QueryParser; import org.apache.solr.request.SolrQueryRequest; /** * Parse Solr's variant on the Lucene {@link org.apache.lucene.queryparser.complexPhrase.ComplexPhraseQueryParser} syntax. * <p> * Modified from {@link org.apache.solr.search.LuceneQParserPlugin} and {@link org.apache.solr.search.SurroundQParserPlugin} */ public class ComplexPhraseQParserPlugin extends QParserPlugin { public static final String NAME = "complexphrase"; private boolean inOrder = true; @Override public void init(NamedList args) { super.init(args); if (args != null) { Object val = args.get("inOrder"); if (val != null) { inOrder = StrUtils.parseBool(val.toString()); } } } @Override public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) { ComplexPhraseQParser qParser = new ComplexPhraseQParser(qstr, localParams, params, req); qParser.setInOrder(inOrder); return qParser; } /** * Modified from {@link org.apache.solr.search.LuceneQParser} and {@link org.apache.solr.search.SurroundQParserPlugin.SurroundQParser} */ static class ComplexPhraseQParser extends QParser { static final class SolrQueryParserDelegate extends SolrQueryParser { private SolrQueryParserDelegate(QParser parser, String defaultField) { super(parser, defaultField); } @Override protected org.apache.lucene.search.Query getWildcardQuery(String field, String termStr) throws SyntaxError { return super.getWildcardQuery(field, termStr); } @Override protected org.apache.lucene.search.Query getRangeQuery(String field, String part1, String part2, boolean startInclusive, boolean endInclusive) throws SyntaxError { return super.getRangeQuery(field, part1, part2, startInclusive, endInclusive); } @Override protected boolean isRangeShouldBeProtectedFromReverse(String field, String part1) { return super.isRangeShouldBeProtectedFromReverse(field, part1); } public String getLowerBoundForReverse() { return REVERSE_WILDCARD_LOWER_BOUND; } } ComplexPhraseQueryParser lparser; boolean inOrder = true; /** * When <code>inOrder</code> is true, the search terms must * exists in the documents as the same order as in query. * * @param inOrder parameter to choose between ordered or un-ordered proximity search */ public void setInOrder(final boolean inOrder) { this.inOrder = inOrder; } public ComplexPhraseQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) { super(qstr, localParams, params, req); } @Override public Query parse() throws SyntaxError { String qstr = getString(); String defaultField = getParam(CommonParams.DF); SolrQueryParserDelegate reverseAwareParser = new SolrQueryParserDelegate(this, defaultField); lparser = new ComplexPhraseQueryParser(defaultField, getReq().getSchema().getQueryAnalyzer()) { protected Query newWildcardQuery(org.apache.lucene.index.Term t) { try { org.apache.lucene.search.Query wildcardQuery = reverseAwareParser.getWildcardQuery(t.field(), t.text()); setRewriteMethod(wildcardQuery); return wildcardQuery; } catch (SyntaxError e) { throw new RuntimeException(e); } } private Query setRewriteMethod(org.apache.lucene.search.Query query) { if (query instanceof MultiTermQuery) { ((MultiTermQuery) query).setRewriteMethod( org.apache.lucene.search.MultiTermQuery.SCORING_BOOLEAN_REWRITE); } return query; } protected Query newRangeQuery(String field, String part1, String part2, boolean startInclusive, boolean endInclusive) { boolean reverse = reverseAwareParser.isRangeShouldBeProtectedFromReverse(field, part1); return super.newRangeQuery(field, reverse ? reverseAwareParser.getLowerBoundForReverse() : part1, part2, startInclusive || reverse, endInclusive); } } ; lparser.setAllowLeadingWildcard(true); if (localParams != null) { inOrder = localParams.getBool("inOrder", inOrder); } lparser.setInOrder(inOrder); QueryParser.Operator defaultOperator = QueryParsing.parseOP(getParam(QueryParsing.OP)); if (QueryParser.Operator.AND.equals(defaultOperator)) lparser.setDefaultOperator(org.apache.lucene.queryparser.classic.QueryParser.Operator.AND); else lparser.setDefaultOperator(org.apache.lucene.queryparser.classic.QueryParser.Operator.OR); try { return lparser.parse(qstr); } catch (ParseException pe) { throw new SyntaxError(pe); } } @Override public String[] getDefaultHighlightFields() { return lparser == null ? new String[]{} : new String[]{lparser.getField()}; } } }