org.opentravel.schemacompiler.index.QueryTask.java Source code

Java tutorial

Introduction

Here is the source code for org.opentravel.schemacompiler.index.QueryTask.java

Source

/**
 * Copyright (C) 2014 OpenTravel Alliance (info@opentravel.org)
 *
 * 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.opentravel.schemacompiler.index;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.search.TopDocs;
import org.opentravel.ns.ota2.repositoryinfo_v01_00.LibraryInfoType;
import org.opentravel.schemacompiler.model.TLLibraryStatus;
import org.opentravel.schemacompiler.repository.RepositoryException;
import org.opentravel.schemacompiler.repository.RepositoryItem;
import org.opentravel.schemacompiler.repository.RepositoryManager;
import org.opentravel.schemacompiler.repository.impl.RepositoryUtils;

/**
 * Performs a free-text search of the repository and returns the results as a list of repository
 * items.
 * 
 * @author S. Livezey
 */
public class QueryTask extends AbstractFreeTextSearchTask {

    public static final int MAX_SEARCH_RESULTS = 50;

    private static Log log = LogFactory.getLog(QueryTask.class);

    private SearcherManager searchManager;
    private Analyzer indexAnalyzer;

    /**
     * Constructor that provides the search manager to use for free-text searches, and the
     * repository manager to use when accessing all repository content.
     * 
     * @param searchManager
     *            the Lucene search manager to use for free-text searches
     * @param repositoryManager
     *            the repository that owns all content to be indexed
     */
    public QueryTask(SearcherManager searchManager, RepositoryManager repositoryManager) {
        super(repositoryManager);
        this.searchManager = searchManager;
        this.indexAnalyzer = new StandardAnalyzer();
    }

    /**
     * Performs a search of the repository using the index reader provided and returns the list of
     * matching repository items.
     * 
     * @param queryString
     *            the query string for the search
     * @param latestVersionsOnly
     *            flag indicating whether the results should include all matching versions or just
     *            the latest version of each library
     * @param includeDraftVersions
     *            flag indicating whether items in <code>DRAFT</code> status should be included in
     *            the resulting list
     * @param reader
     *            the index reader to use when performing the search
     * @throws RepositoryException
     *             thrown if an error occurs while executing the search
     */
    public List<RepositoryItem> queryRepositoryItems(String queryString, boolean latestVersionsOnly,
            boolean includeDraftVersions) throws RepositoryException {
        List<Document> indexDocuments = new ArrayList<Document>();
        IndexSearcher searcher = null;

        // Search the index for matching documents
        refreshSearcher();
        try {
            searcher = searchManager.acquire();
            Query query = buildQuery(queryString, latestVersionsOnly, includeDraftVersions);
            TopDocs scoredResults = searcher.search(query, MAX_SEARCH_RESULTS);

            for (ScoreDoc scoreDoc : scoredResults.scoreDocs) {
                indexDocuments.add(searcher.doc(scoreDoc.doc));
            }

        } catch (Exception e) {
            throw new RepositoryException("Error executing free-text search.", e);

        } finally {
            try {
                if (searcher != null)
                    searchManager.release(searcher);

            } catch (IOException e) {
                throw new RepositoryException("Error releasing free-text searcher.", e);
            }
        }

        // Attempt to resolve each matching document to a repository item
        List<RepositoryItem> searchResults = new ArrayList<RepositoryItem>();

        for (Document indexDoc : indexDocuments) {
            RepositoryItem item = getRepositoryItem(indexDoc);

            if (item != null) {
                searchResults.add(item);
            }
        }
        return searchResults;
    }

    /**
     * Builds a Lucene query using the information provided.
     * 
     * @param contentTerms
     *            the terms to use for the content portion of the query
     * @param latestVersionsOnly
     *            flag indicating whether the results should include all matching versions or just
     *            the latest version of each library
     * @param includeDraftVersions
     *            flag indicating whether items in <code>DRAFT</code> status should be included in
     *            the resulting list
     * @return Query
     * @throws ParseException
     *             thrown if the query text cannot be parsed
     */
    private Query buildQuery(String contentTerms, boolean latestVersionsOnly, boolean includeDraftVersions)
            throws ParseException {
        QueryParser parser = new QueryParser(CONTENT_FIELD, indexAnalyzer);
        StringBuilder queryText = new StringBuilder(VERSION_TYPE_FIELD).append(':');

        // Create the search term for the 'versionType' field
        if (latestVersionsOnly) {
            if (includeDraftVersions) {
                queryText.append(IndexVersionType.HEAD).append(" AND ");
            } else {
                queryText.append(IndexVersionType.HEAD_FINAL).append(" AND ");
            }
        } else {
            queryText.append(IndexVersionType.STANDARD).append(" AND ");
        }

        // If needed, create a search term for the status field
        if (!includeDraftVersions) {
            queryText.append(STATUS_FIELD).append(':').append(TLLibraryStatus.FINAL.toString()).append(" AND ");
        }

        // Add the remaining content terms for the query
        queryText.append("(").append(contentTerms).append(")");
        return parser.parse(queryText.toString());
    }

    /**
     * Refreshes the searcher to be current as of the latest indexing job.
     */
    private synchronized void refreshSearcher() {
        try {
            searchManager.maybeRefreshBlocking();

        } catch (IOException e) {
            log.error("Error refreshing free-text searcher.", e);
        }
    }

    /**
     * Returns the repository item associated with the given Lucene index document, or null if no
     * such item exists.
     * 
     * @param indexDoc
     *            the Lucene index document that was returned in a search result
     * @return RepositoryItem
     */
    private RepositoryItem getRepositoryItem(Document indexDoc) {
        String baseNamespace = indexDoc.get(BASE_NAMESPACE_FIELD);
        String filename = indexDoc.get(FILENAME_FIELD);
        String version = indexDoc.get(VERSION_FIELD);
        RepositoryItem item = null;
        try {
            if ((baseNamespace != null) && (filename != null) && (version != null)) {
                LibraryInfoType libraryMetadata = repositoryManager.getFileManager()
                        .loadLibraryMetadata(baseNamespace, filename, version);
                RepositoryItem candidateItem = RepositoryUtils.createRepositoryItem(repositoryManager,
                        libraryMetadata);
                File metadataFile = getMetadataFile(candidateItem);
                File contentFile = getContentFile(candidateItem);

                if (metadataFile.exists() && contentFile.exists()) {
                    item = candidateItem;
                }
            }

        } catch (RepositoryException e) {
            log.warn("Repository item found in search index, but could not be located: " + filename);
        }
        return item;
    }

    protected void displayIndex() {
        IndexSearcher searcher = null;
        try {
            searcher = searchManager.acquire();
            IndexReader reader = searcher.getIndexReader();

            for (int i = 0; i < reader.maxDoc(); i++) {
                Document doc = reader.document(i);

                System.out.println("DOCUMENT: " + doc.get(IDENTITY_FIELD));
                System.out.println("  " + BASE_NAMESPACE_FIELD + " : " + doc.get(BASE_NAMESPACE_FIELD));
                System.out.println("  " + FILENAME_FIELD + " : " + doc.get(FILENAME_FIELD));
                System.out.println("  " + STATUS_FIELD + " : " + doc.get(STATUS_FIELD));
                System.out.println("  " + VERSION_FIELD + " : " + doc.get(VERSION_FIELD));
                System.out.println("  " + VERSION_TYPE_FIELD + " : " + doc.get(VERSION_TYPE_FIELD));
            }
        } catch (Throwable t) {
            t.printStackTrace(System.out);

        } finally {
            try {
                if (searcher != null)
                    searchManager.release(searcher);

            } catch (IOException e) {
                // Ignore error and continue
            }
        }
    }

}