/* * Hibernate Search, full-text search for your domain model * * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.search.query.engine.impl; 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.ConstantScoreQuery; import org.apache.lucene.search.DisjunctionMaxQuery; import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.NumericRangeQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; /** * Helper class to extract field names from the Lucene queries taking query types into account. * * @author Hardy Ferentschik */ public class FieldNameCollector { private FieldNameCollector() { } public static FieldCollection extractFieldNames(Query query) { // first we need to find all composing queries since some query types are just containers Set<Query> composingQueries = new HashSet<>(); collectComposingQueries( query, composingQueries ); FieldCollection fieldCollection = new FieldCollection(); for ( Query composingQuery : composingQueries ) { if ( composingQuery instanceof NumericRangeQuery ) { fieldCollection.addNumericFieldName( ( (NumericRangeQuery) composingQuery ).getField() ); } else if ( composingQuery instanceof MultiTermQuery ) { fieldCollection.addStringFieldName( ( (MultiTermQuery) composingQuery ).getField() ); } else if ( composingQuery instanceof TermQuery ) { TermQuery termQuery = (TermQuery) composingQuery; fieldCollection.addStringFieldName( termQuery.getTerm().field() ); } else if ( composingQuery instanceof PhraseQuery ) { PhraseQuery phraseQuery = (PhraseQuery) composingQuery; // all terms must be against the same field, it's enough to look at the first fieldCollection.addStringFieldName( phraseQuery.getTerms()[0].field() ); } else if ( composingQuery instanceof MultiPhraseQuery ) { MultiPhraseQuery phraseQuery = (MultiPhraseQuery) composingQuery; // all terms must be against the same field, it's enough to look at the first fieldCollection.addStringFieldName( phraseQuery.getTermArrays().get( 0 )[0].field() ); } } return fieldCollection; } private static void collectComposingQueries(Query query, Set<Query> composingQueries) { if ( query instanceof BooleanQuery ) { BooleanQuery booleanQuery = (BooleanQuery) query; for ( BooleanClause clause : booleanQuery.getClauses() ) { collectComposingQueries( clause.getQuery(), composingQueries ); } } else if ( query instanceof DisjunctionMaxQuery ) { DisjunctionMaxQuery disjunctionMaxQuery = (DisjunctionMaxQuery) query; for ( Query subQuery : disjunctionMaxQuery.getDisjuncts() ) { collectComposingQueries( subQuery, composingQueries ); } } else if ( query instanceof ConstantScoreQuery ) { // this one is tricky, the ConstantScoreQuery can wrap a query or a filter. ConstantScoreQuery constantScoreQuery = (ConstantScoreQuery) query; if ( constantScoreQuery.getQuery() != null ) { collectComposingQueries( constantScoreQuery.getQuery(), composingQueries ); } } else { composingQueries.add( query ); } } public static class FieldCollection { private final Set<String> numericFieldNames; private final Set<String> stringFieldNames; public FieldCollection() { numericFieldNames = new HashSet<>(); stringFieldNames = new HashSet<>(); } void addNumericFieldName(String fieldName) { numericFieldNames.add( fieldName ); } void addStringFieldName(String fieldName) { stringFieldNames.add( fieldName ); } public Set<String> getNumericFieldNames() { return numericFieldNames; } public Set<String> getStringFieldNames() { return stringFieldNames; } @Override public String toString() { return "FieldCollection{" + "numericFieldNames=" + numericFieldNames + ", stringFieldNames=" + stringFieldNames + '}'; } } }