/* * 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.dsl.impl; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.Query; import org.hibernate.search.annotations.Store; import org.hibernate.search.engine.integration.impl.ExtendedSearchIntegrator; import org.hibernate.search.engine.metadata.impl.DocumentFieldMetadata; import org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity; import org.hibernate.search.query.dsl.MoreLikeThisTermination; import org.hibernate.search.query.dsl.MoreLikeThisToEntityContentAndTermination; import org.hibernate.search.util.logging.impl.Log; import org.hibernate.search.util.logging.impl.LoggerFactory; /** * @author Emmanuel Bernard */ public abstract class ConnectedMoreLikeThisQueryBuilder { private static final Log log = LoggerFactory.make(); private final QueryBuildingContext queryContext; private final QueryCustomizer queryCustomizer; private final FieldsContext fieldsContext; private final INPUT_TYPE inputType; private final Object input; private final MoreLikeThisQueryContext moreLikeThisContext; public ConnectedMoreLikeThisQueryBuilder(Object id, INPUT_TYPE inputType, FieldsContext fieldsContext, MoreLikeThisQueryContext moreLikeThisContext, QueryCustomizer queryCustomizer, QueryBuildingContext queryContext) { this.queryContext = queryContext; this.queryCustomizer = queryCustomizer; this.moreLikeThisContext = moreLikeThisContext; this.fieldsContext = fieldsContext; this.inputType = inputType; this.input = id; } /** * We could encapsulate that into a MoreLikeThisContentObject but going for this approach for now * to save memory pressure. * If the code becomes too nasty, change it. */ public enum INPUT_TYPE { ID, ENTITY, READER, STRING } public Query createQuery() { Query query; final ExtendedSearchIntegrator searchIntegrator = queryContext.getExtendedSearchIntegrator(); final DocumentBuilderIndexedEntity documentBuilder = queryContext.getDocumentBuilder(); IndexReader indexReader = searchIntegrator.getIndexReaderAccessor().open( queryContext.getEntityType() ); // retrieving the docId and building the more like this query form the term vectors must be using the same index reader try { String[] fieldNames = getAllCompatibleFieldNames( documentBuilder ); if ( fieldsContext.size() == 0 ) { // Use all compatible fields when comparingAllFields is used fieldsContext.addAll( fieldNames ); } query = new MoreLikeThisBuilder( documentBuilder, searchIntegrator ) .compatibleFieldNames( fieldNames ) .fieldsContext( fieldsContext ) .queryContext( queryContext ) .indexReader( indexReader ) .inputType( inputType ) .input( input ) .otherMoreLikeThisContext( moreLikeThisContext ) .createQuery(); } finally { searchIntegrator.getIndexReaderAccessor().close( indexReader ); } //TODO implement INPUT_TYPE.READER //TODO implement INPUT_TYPE.STRING return queryCustomizer.setWrappedQuery( query ).createQuery(); } private String[] getAllCompatibleFieldNames(DocumentBuilderIndexedEntity documentBuilder) { Collection<DocumentFieldMetadata> allFieldMetadata = documentBuilder.getTypeMetadata().getAllDocumentFieldMetadata(); List<String> fieldNames = new ArrayList<String>( allFieldMetadata.size() ); for ( DocumentFieldMetadata fieldMetadata : allFieldMetadata ) { boolean hasTermVector = fieldMetadata.getTermVector() != Field.TermVector.NO; boolean isStored = fieldMetadata.getStore() != Store.NO; boolean isIdOrEmbeddedId = fieldMetadata.isId() || fieldMetadata.isIdInEmbedded(); if ( ( hasTermVector || isStored ) && !isIdOrEmbeddedId ) { fieldNames.add( fieldMetadata.getAbsoluteName() ); } } if ( fieldNames.size() == 0 ) { throw log.noFieldCompatibleForMoreLikeThis( documentBuilder.getBeanClass() ); } return fieldNames.toArray( new String[fieldNames.size()] ); } public static final class MoreLikeThisTerminationImpl extends ConnectedMoreLikeThisQueryBuilder implements MoreLikeThisTermination { public MoreLikeThisTerminationImpl(Object id, INPUT_TYPE inputType, FieldsContext fieldsContext, MoreLikeThisQueryContext moreLikeThisContext, QueryCustomizer queryCustomizer, QueryBuildingContext queryContext) { super( id, inputType, fieldsContext, moreLikeThisContext, queryCustomizer, queryContext ); } } public static final class MoreLikeThisToEntityContentAndTerminationImpl extends ConnectedMoreLikeThisQueryBuilder implements MoreLikeThisToEntityContentAndTermination { public MoreLikeThisToEntityContentAndTerminationImpl(Object id, INPUT_TYPE inputType, FieldsContext fieldsContext, MoreLikeThisQueryContext moreLikeThisContext, QueryCustomizer queryCustomizer, QueryBuildingContext queryContext) { super( id, inputType, fieldsContext, moreLikeThisContext, queryCustomizer, queryContext ); } } }