org.apache.lucene.monitor.QueryDecomposer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lucene-monitor Show documentation
Show all versions of lucene-monitor Show documentation
Apache Lucene (module: monitor)
/*
* 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.lucene.monitor;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.DisjunctionMaxQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.CollectionUtil;
/**
* Split a disjunction query into its consituent parts, so that they can be indexed and run
* separately in the Monitor.
*/
public class QueryDecomposer {
/**
* Split a query up into individual parts that can be indexed and run separately
*
* @param q the query
* @return a collection of subqueries
*/
public Set decompose(Query q) {
if (q instanceof BooleanQuery) return decomposeBoolean((BooleanQuery) q);
if (q instanceof DisjunctionMaxQuery) {
Set subqueries = new HashSet<>();
for (Query subq : ((DisjunctionMaxQuery) q).getDisjuncts()) {
subqueries.addAll(decompose(subq));
}
return subqueries;
}
if (q instanceof BoostQuery) {
return decomposeBoostQuery((BoostQuery) q);
}
return Collections.singleton(q);
}
public Set decomposeBoostQuery(BoostQuery q) {
if (q.getBoost() == 1.0) return decompose(q.getQuery());
Set boostedDecomposedQueries = new HashSet<>();
for (Query subq : decompose(q.getQuery())) {
boostedDecomposedQueries.add(new BoostQuery(subq, q.getBoost()));
}
return boostedDecomposedQueries;
}
/**
* Decompose a {@link org.apache.lucene.search.BooleanQuery}
*
* @param q the boolean query
* @return a collection of subqueries
*/
public Set decomposeBoolean(BooleanQuery q) {
if (q.getMinimumNumberShouldMatch() > 1) return Collections.singleton(q);
Set subqueries = new HashSet<>();
Set exclusions = new HashSet<>();
Set mandatory = new HashSet<>();
for (BooleanClause clause : q) {
if (clause.getOccur() == BooleanClause.Occur.MUST
|| clause.getOccur() == BooleanClause.Occur.FILTER) mandatory.add(clause.getQuery());
else if (clause.getOccur() == BooleanClause.Occur.MUST_NOT) exclusions.add(clause.getQuery());
else {
subqueries.addAll(decompose(clause.getQuery()));
}
}
// More than one MUST clause, or a single MUST clause with disjunctions
if (mandatory.size() > 1 || (mandatory.size() == 1 && subqueries.size() > 0))
return Collections.singleton(q);
// If we only have a single MUST clause and no SHOULD clauses, then we can
// decompose the MUST clause instead
if (mandatory.size() == 1) {
subqueries.addAll(decompose(mandatory.iterator().next()));
}
if (exclusions.size() == 0) return subqueries;
// If there are exclusions, then we need to add them to all the decomposed
// queries
Set rewrittenSubqueries = CollectionUtil.newHashSet(subqueries.size());
for (Query subquery : subqueries) {
BooleanQuery.Builder bq = new BooleanQuery.Builder();
bq.add(subquery, BooleanClause.Occur.MUST);
for (Query ex : exclusions) {
bq.add(ex, BooleanClause.Occur.MUST_NOT);
}
rewrittenSubqueries.add(bq.build());
}
return rewrittenSubqueries;
}
}