/* * Copyright 2004-2009 the original author or authors. * * 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.compass.core.lucene.util; import java.io.IOException; import java.util.ArrayList; import org.apache.lucene.document.Document; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermEnum; import org.apache.lucene.index.TermFreqVector; import org.apache.lucene.search.Filter; import org.apache.lucene.search.Query; import org.apache.lucene.store.Directory; import org.compass.core.Compass; import org.compass.core.CompassHits; import org.compass.core.CompassQuery; import org.compass.core.CompassQueryFilter; import org.compass.core.CompassSession; import org.compass.core.Resource; import org.compass.core.engine.SearchEngineException; import org.compass.core.engine.SearchEngineQuery; import org.compass.core.engine.SearchEngineQueryFilter; import org.compass.core.impl.DefaultCompassHits; import org.compass.core.impl.DefaultCompassQuery; import org.compass.core.impl.DefaultCompassQueryFilter; import org.compass.core.lucene.LuceneResource; import org.compass.core.lucene.engine.LuceneSearchEngineFactory; import org.compass.core.lucene.engine.LuceneSearchEngineHits; import org.compass.core.lucene.engine.LuceneSearchEngineInternalSearch; import org.compass.core.lucene.engine.LuceneSearchEngineQuery; import org.compass.core.lucene.engine.LuceneSearchEngineQueryFilter; import org.compass.core.lucene.engine.analyzer.LuceneAnalyzerManager; import org.compass.core.lucene.engine.manager.LuceneSearchEngineIndexManager; import org.compass.core.spi.InternalCompass; import org.compass.core.spi.InternalCompassQuery; import org.compass.core.spi.InternalCompassSession; import org.compass.core.spi.InternalResource; /** * Allows to create Compass related objects based on external (internally no supported by Compass) * Lucene objects. * * @author kimchy */ public abstract class LuceneHelper { /** * Creates a new {@link CompassQuery} based on a Lucene {@link Query}. * * <p>Allows to create {@link CompassQuery} based on external Lucene {@link Query} that is not supported * by one of Compass query builders. * * @param compass Compass instance * @param query The lucene query to wrap * @return A compass query wrapping the lucene query */ public static CompassQuery createCompassQuery(Compass compass, Query query) { InternalCompass internalCompass = (InternalCompass) compass; SearchEngineQuery searchEngineQuery = new LuceneSearchEngineQuery((LuceneSearchEngineFactory) internalCompass.getSearchEngineFactory(), query); return new DefaultCompassQuery(searchEngineQuery, internalCompass); } /** * Creates a new {@link CompassQuery} based on a Lucene {@link Query}. * * <p>Allows to create {@link CompassQuery} based on external Lucene {@link Query} that is not supported * by one of Compass query builders. * * @param session Compass session * @param query The lucene query to wrap * @return A compass query wrapping the lucene query */ public static CompassQuery createCompassQuery(CompassSession session, Query query) { InternalCompassSession internalCompassSession = (InternalCompassSession) session; SearchEngineQuery searchEngineQuery = new LuceneSearchEngineQuery((LuceneSearchEngineFactory) internalCompassSession.getCompass().getSearchEngineFactory(), query); InternalCompassQuery compassQuery = new DefaultCompassQuery(searchEngineQuery, internalCompassSession.getCompass()); compassQuery.attach(session); return compassQuery; } /** * Returns the underlying {@link LuceneSearchEngineQuery} of the given {@link CompassQuery}. * <p/> * Can be used for example to add custom Sorting using * {@link LuceneSearchEngineQuery#addSort(org.apache.lucene.search.SortField)}, or get the actual lucene query * using {@link org.compass.core.lucene.engine.LuceneSearchEngineQuery#getQuery()}. * * @param query The compass query to extract the lucene search engine query from * @return The lucene search engine query extracted from the compass query */ public static LuceneSearchEngineQuery getLuceneSearchEngineQuery(CompassQuery query) { return (LuceneSearchEngineQuery) ((DefaultCompassQuery) query).getSearchEngineQuery(); } /** * Creates a new {@link CompassQueryFilter} based on a Lucene {@link Filter}. * <p/> * Allows to create {@link CompassQueryFilter} based on external Lucene {@link Filter} that is not supported * by one fo Comapss query filter builders. * * @param session Comapss session * @param filter The lucene filter to wrap * @return A compass query filter wrapping lucene query. */ public static CompassQueryFilter createCompassQueryFilter(CompassSession session, Filter filter) { SearchEngineQueryFilter searchEngineQueryFilter = new LuceneSearchEngineQueryFilter(filter); return new DefaultCompassQueryFilter(searchEngineQueryFilter); } /** * Returns the underlying {@link LuceneSearchEngineQueryFilter} of the given {@link CompassQueryFilter}. * <p/> * Can be used to get the actual Lucene {@link Filter} using * {@link org.compass.core.lucene.engine.LuceneSearchEngineQueryFilter#getFilter()}. * * @param filter The compass query filter to extract the lucene search engine query filter from * @return The lucene search engine query filter extracted from the compass query filter */ public static LuceneSearchEngineQueryFilter getLuceneSearchEngineQueryFilter(CompassQueryFilter filter) { return (LuceneSearchEngineQueryFilter) ((DefaultCompassQueryFilter) filter).getFilter(); } /** * Returns the underlying {@link LuceneSearchEngineHits} of the given {@link CompassHits}. * <p/> * Used mainly to access the actual Lucene {@link org.apache.lucene.search.Hits}, or get * Lucene {@link org.apache.lucene.search.Explanation}. */ public static LuceneSearchEngineHits getLuceneSearchEngineHits(CompassHits hits) { return (LuceneSearchEngineHits) ((DefaultCompassHits) hits).getSearchEngineHits(); } /** * Returns Compass own internal <code>LuceneAnalyzerManager</code>. Can be used * to access Lucene {@link org.apache.lucene.analysis.Analyzer} at runtime. */ public static LuceneAnalyzerManager getLuceneAnalyzerManager(Compass compass) { return ((LuceneSearchEngineFactory) ((InternalCompass) compass).getSearchEngineFactory()).getAnalyzerManager(); } /** * Returns the given search engine "internals" used for search. For Lucene, returns * {@link LuceneSearchEngineInternalSearch} which allows to access Lucene * {@link org.apache.lucene.index.IndexReader} and {@link org.apache.lucene.search.Searcher}. * <p/> * The search internals will be ones that are executed against the whole index. In order to search on * specific aliases or sub indexes, please use {@link #getLuceneInternalSearch(org.compass.core.CompassSession,String[],String[])} . * * @param session A compass session within a transaction * @return Lucene search "internals" */ public static LuceneSearchEngineInternalSearch getLuceneInternalSearch(CompassSession session) { return (LuceneSearchEngineInternalSearch) ((InternalCompassSession) session).getSearchEngine().internalSearch(null, null); } /** * Returns the given search engine "internals" used for search. For Lucene, returns * {@link LuceneSearchEngineInternalSearch} which allows to access Lucene * {@link org.apache.lucene.index.IndexReader} and {@link org.apache.lucene.search.Searcher}. * <p/> * The search can be narrowed down to specific sub indexes or aliases. A <code>null</code> value * means all the sub indexes/aliases. * * @param session A compass sessino within a transaction * @param subIndexes A set of sub indexes to narrow down the index scope * @param aliases A set of aliases to narrow down the index scope * @return Lucene search "internals" */ public static LuceneSearchEngineInternalSearch getLuceneInternalSearch(CompassSession session, String[] subIndexes, String[] aliases) { return (LuceneSearchEngineInternalSearch) ((InternalCompassSession) session).getSearchEngine().internalSearch(subIndexes, aliases); } /** * Returns the actual Lucene {@link Document} that the {@link Resource} wraps. * * @param resource The resource to get the document from * @return The Lucene document that resource wraps */ public static Document getDocument(Resource resource) { return ((LuceneResource) resource).getDocument(); } /** * Returns Lucene {@link TermFreqVector} using the given Compass session and {@link Resource}. * * @param session Compass session * @param resource The resource to get the term freq vector for * @return The term infos freq vector for the given resource * @throws SearchEngineException */ public static TermFreqVector[] getTermFreqVectors(CompassSession session, Resource resource) throws SearchEngineException { resource = ((InternalCompassSession) session).getResourceByIdResourceNoCache(resource); String subIndex = ((InternalResource) resource).getSubIndex(); LuceneSearchEngineInternalSearch internalSearch = getLuceneInternalSearch(session, new String[]{subIndex}, null); try { return internalSearch.getReader().getTermFreqVectors(((LuceneResource) resource).getDocNum()); } catch (IOException e) { throw new SearchEngineException("Failed to fetch term info for resource [" + resource + "]", e); } } /** * Returns Lucene {@link TermFreqVector} for the given property and resource, using the session. * * @param session Compass session * @param resource The resource to get the term freq vector for * @param propertyName Theh property name (Lucene field name) to get the term freq vector for * @return Teh term info freq vector for the given resource and property * @throws SearchEngineException */ public static TermFreqVector getTermFreqVector(CompassSession session, Resource resource, String propertyName) throws SearchEngineException { resource = ((InternalCompassSession) session).getResourceByIdResourceNoCache(resource); String subIndex = ((InternalResource) resource).getSubIndex(); LuceneSearchEngineInternalSearch internalSearch = getLuceneInternalSearch(session, new String[]{subIndex}, null); try { return internalSearch.getReader().getTermFreqVector(((LuceneResource) resource).getDocNum(), propertyName); } catch (IOException e) { throw new SearchEngineException("Failed to fetch term info for resource [" + resource + "]", e); } } /** * Returns the lucene {@link org.apache.lucene.store.Directory} associated with the given sub index. */ public static Directory getDirectory(Compass compass, String subIndex) { return ((LuceneSearchEngineIndexManager) ((InternalCompass) compass).getSearchEngineIndexManager()).getStore().openDirectory(subIndex); } /** * Returns all the values of for the given propery name. */ public static String[] findPropertyValues(CompassSession session, String propertyName) throws SearchEngineException { LuceneSearchEngineInternalSearch internalSearch = getLuceneInternalSearch(session); ArrayList<String> list = new ArrayList<String>(); try { TermEnum te = internalSearch.getReader().terms(new Term(propertyName, "")); while (propertyName.equals(te.term().field())) { String value = te.term().text(); list.add(value); if (!te.next()) { break; } } } catch (IOException e) { throw new SearchEngineException("Failed to read property values for property [" + propertyName + "]"); } return list.toArray(new String[list.size()]); } }