com.revorg.goat.SearchDatabase.java Source code

Java tutorial

Introduction

Here is the source code for com.revorg.goat.SearchDatabase.java

Source

package com.revorg.goat;

/*
 * Copyright (c) Grover C. Fields, http://www.groverfields.com/, 2005-2009.
 * All rights reserved. Software written by Grover C. Fields and others.
 * $Id: LICENSE,v 1.0 2008/12/01 05:00:00 Grover Exp $
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Java, the Duke mascot, and all variants of Sun's Java "steaming coffee
 * cup" logo are trademarks of Sun Microsystems. Sun's, and James Gosling's,
 * pioneering role in inventing and promulgating (and standardizing) the Java 
 * language and environment is gratefully acknowledged.
 * 
 * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
 * inventing predecessor languages C and C++ is also gratefully acknowledged.
 */

import java.io.IOException;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TopFieldDocs;

import java.util.HashMap;
import java.util.Map;

/**
 * This class searches the Lucene Database Collections
 *
 * @version 1.0
 * @author  Grover C. Fields  (grover_fields@yahoo.com)
 * @author  http://www.groverfields.com
 */

public class SearchDatabase implements java.io.Serializable {
    private static String ActionResult;
    private static String ActionResultError;
    private static IndexReader reader;
    private static IndexWriter writer;
    private static IndexSearcher searcher;

    public SearchDatabase() {
    }

    /**
     * Searches the Lucene index based on file system documents.
     *
     * @param indexPath Directory that contains the Lucene Collection         
     * @param hitsPerPage           Number of hits per page
     * @param pageNum               The page number to search
     * @param searchString          The search string for searching
     * @param searchType            The type of results to return
     * @param sortField             The field to sort on if needed
     * @param sortDirection         The direction to sort by
     * @throws Exception
     * @return ActionResult
     */
    public static String doSingleSearch(String indexPath, int hitsPerPage, int pageNum, String searchString,
            String searchType, String sortField, String sortDirection) {
        try {
            if (searchString != null)
                searchString.trim().toLowerCase(); //Lower Case Search
            IndexReader reader = IndexReader.open(indexPath);
            IndexSearcher searcher = new IndexSearcher(indexPath);
            if (searcher == null) {
                throw new Exception("Unable to open index");
            }
            QueryParser parser = new QueryParser("contents", new StandardAnalyzer());
            Query query = parser.parse(searchString);
            if (query == null) {
                throw new Exception("Unable to build Query");
            }
            String returnText = "";
            returnText = doPagingSearch(indexPath, searcher, query, hitsPerPage, pageNum, searchType, sortField,
                    sortDirection);
            //System.out.println(returnText);
            reader.close();
            //Paging Results
            return returnText;
        }

        catch (Exception e) {
            ActionResultError = " caught a " + e.getClass() + " with message: " + e.getMessage();
            //System.out.println("Failure of DbSchema File: " + xmlFile);
        }
        ActionResult = "Failure";
        return ActionResult + ActionResultError;
    }

    /**
     * Searches the Lucene index based on database documents.
     *
     * @param indexPath Directory that contains the Lucene Collection         
     * @param hitsPerPage           Number of hits per page
     * @param pageNum               The page number to search
     * @param searchString          The search string for searching
     * @param searchType            The type of results to return
     * @param sortField             The field to sort on if needed
     * @param sortDirection         The direction to sort by
     * @throws Exception
     * @return ActionResult
     */

    public static String doMultiSearch(String indexPath, int hitsPerPage, int pageNum, String searchFieldsArray[],
            String searchString, String searchType, String sortField, String sortDirection) {
        try {
            if (searchString != null)
                searchString.trim().toLowerCase(); //Lower Case Search
            IndexReader reader = IndexReader.open(indexPath);
            IndexSearcher searcher = new IndexSearcher(indexPath);
            if (searcher == null) {
                throw new Exception("Unable to open index");
            }
            QueryParser parser = new MultiFieldQueryParser(searchFieldsArray, new StandardAnalyzer());
            Query query = parser.parse(searchString);
            if (query == null) {
                throw new Exception("Unable to build Query");
            }
            String returnText = "";
            returnText = doPagingSearch(indexPath, searcher, query, hitsPerPage, pageNum, searchType, sortField,
                    sortDirection);
            //System.out.println(returnText);
            reader.close();
            //Paging Results
            return returnText;
        }

        catch (Exception e) {
            ActionResultError = " caught a " + e.getClass() + " with message: " + e.getMessage();
            //System.out.println("Failure of DbSchema File: " + xmlFile);
        }
        ActionResult = "Failure";
        return ActionResult + ActionResultError;
    }

    /**
     * This demonstrates a typical paging search scenario, where the search engine presents 
     * pages of size n to the user. The user can then go to the next page if interested in
     * the next hits.
     * 
     * When the query is executed for the first time, then only enough results are collected
     * to fill 5 result pages. If the user wants to page beyond this limit, then the query
     * is executed another time and all hits are collected.
     *
      * @param indexPath Directory that contains the Lucene Collection   
      * @param searcher              The searcher used by Lucene
      * @param hitsPerPage           Number of hits per page
      * @param pageNum               The page number to search
      * @param searchType            The type of results to return
      * @param sortField             The field to sort on if needed
      * @param sortDirection         The direction to sort by
      * @throws Exception
      * @return ActionResult
      */
    private static String doPagingSearch(String indexPath, Searcher searcher, Query query, int hitsPerPage,
            int pageNum, String searchType, String sortField, String sortDirection) throws Exception {
        try {
            XMLReader readerXML = new XMLReader(); //XML Reader Class   
            String configFile = ConfigFiles.getSchemaFile(indexPath);
            String[] indexTypeArray = new String[Integer.parseInt(readerXML.getTotalNodes(configFile))];
            String[] columnNamesArray = new String[Integer.parseInt(readerXML.getTotalNodes(configFile))];
            int totalNodes = columnNamesArray.length;
            String textResultSet = "";
            String nodeName = "";

            //Sort .:.  Index Type must be PrimaryKey,Keyword,Date
            Sort sortby = new Sort();
            if (sortField != null)
                sortField.trim().toLowerCase(); //Change Field TO LowerCase
            //Get Column Names
            for (int i = 0; i < totalNodes; i++) {
                columnNamesArray[i] = readerXML.getNodeValueByFile(configFile, i, "columnname");
                indexTypeArray[i] = readerXML.getNodeValueByFile(configFile, i, "indextype");

                /* Make Sure Field Can Be Seached */
                if (columnNamesArray[i].equalsIgnoreCase(sortField)
                        && (indexTypeArray[i].equalsIgnoreCase("PrimaryKey")
                                || indexTypeArray[i].equalsIgnoreCase("Keyword")
                                || indexTypeArray[i].equalsIgnoreCase("Date"))) {
                    //Sort Ascending 
                    if (sortDirection != null && sortDirection.equalsIgnoreCase("desc")) {
                        System.out.println("desc");
                        sortby = new Sort(sortField, true);
                    } else if (sortDirection != null && sortDirection.equalsIgnoreCase("asc")) {
                        System.out.println("asc");
                        sortby = new Sort(sortField, false);
                    }

                }

            }

            if (hitsPerPage == 0)
                hitsPerPage = 1;
            int recordSet = (pageNum * hitsPerPage) + 100;

            //VERSION 1 OF SIMPLE RESULT SET 
            // Collect enough docs to show 5 pages
            //TopDocCollector collector = new TopDocCollector((pageNum * hitsPerPage)+100);       
            //searcher.search(query, collector);
            //ScoreDoc[] hits = collector.topDocs().scoreDocs;      
            //int numTotalHits = collector.getTotalHits();     

            TopFieldDocs resultDocs = searcher.search(query, null, recordSet, sortby);
            ScoreDoc[] hits = resultDocs.scoreDocs;
            int numTotalHits = resultDocs.totalHits;

            //Start
            int start = (pageNum - 1);
            if (start < 0)
                start = 0;

            if (pageNum > 1) {
                start = (pageNum * hitsPerPage) - hitsPerPage;
            }

            int end = (pageNum * hitsPerPage);

            if (searchType.equalsIgnoreCase("xml") && numTotalHits == 0) {
                textResultSet = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + System.getProperty("line.separator");
                textResultSet = textResultSet + "<goaterror>\n" + "  <error type=\"noresults\" code=\"1.1\">\n"
                        + "    <title>Dang. We didn't find anything for you there.</title>\n" + "    <text>\n"
                        + "      <p> We couldn't find any result for <strong>" + query + "</strong>.</p>\n"
                        + "    </text>\n" + "  </error>\n" + "</goaterror>";
                return textResultSet;
            }

            if (searchType.equalsIgnoreCase("xml") && numTotalHits > 0) {
                textResultSet = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + System.getProperty("line.separator");
                textResultSet = textResultSet + "<resultset>" + System.getProperty("line.separator");
                textResultSet = textResultSet + "<searchterm><![CDATA[" + query + "]]></searchterm>"
                        + System.getProperty("line.separator");
                textResultSet = textResultSet + "<start>" + (start + 1) + "</start>"
                        + System.getProperty("line.separator");
                textResultSet = textResultSet + "<end>" + end + "</end>" + System.getProperty("line.separator");
                textResultSet = textResultSet + "<totalresults>" + numTotalHits + "</totalresults>"
                        + System.getProperty("line.separator");
                textResultSet = textResultSet + "<totalpages>" + (numTotalHits / hitsPerPage) + "</totalpages>"
                        + System.getProperty("line.separator");
                textResultSet = textResultSet + "<rows>";

            }

            /*
             * V1 IMPLEMENTATION ALSO
            if (end > hits.length) {
              collector = new TopDocCollector(numTotalHits);
              searcher.search(query, collector);
              hits = collector.topDocs().scoreDocs;
            }
            */

            end = Math.min(hits.length, start + hitsPerPage);

            for (int i = start; i < end; i++) {
                //Document doc = searcher.doc(hits[i].doc);
                int docId = hits[i].doc;
                Document d = searcher.doc(docId);
                for (int x = 0; x < totalNodes; x++) {
                    nodeName = columnNamesArray[x];

                    //XML
                    if (searchType.equalsIgnoreCase("xml")) {
                        //System.out.println("i " + i + " x " + x + " Node: " + nodeName);
                        if (x == 0) {
                            textResultSet = textResultSet + System.getProperty("line.separator") + "<row number=\""
                                    + (i + 1) + "\"" + " score=\"" + hits[i].score + "\">";
                        }
                        textResultSet = textResultSet + "<" + nodeName + "><![CDATA[" + d.get(nodeName) + "]]></"
                                + nodeName + ">";
                        if (x == totalNodes - 1) {
                            textResultSet = textResultSet + "</row>";
                        }

                    } else if (searchType.equalsIgnoreCase("primary")
                            && indexTypeArray[x].equalsIgnoreCase("PrimaryKey") == true) {
                        if (textResultSet.length() > 0)
                            textResultSet = textResultSet + ",";
                        textResultSet = textResultSet + d.get(nodeName);
                    }
                }
            }

            //Close
            if (searchType.equalsIgnoreCase("xml") && numTotalHits > 0 && textResultSet.length() > 0) {
                textResultSet = textResultSet + "</rows></resultset>" + System.getProperty("line.separator");
            } else if (searchType.equalsIgnoreCase("primary") && numTotalHits > 0 && textResultSet.length() > 0) {
                textResultSet = (numTotalHits) + "|" + (numTotalHits / hitsPerPage) + "|" + textResultSet
                        + System.getProperty("line.separator");
            } else {
                return null;
            }

            return textResultSet;

        }

        catch (Exception e) {
            ActionResultError = " caught a " + e.getClass() + " with message: " + e.getMessage();
            //System.out.println("Failure of DbSchema File: " + xmlFile);
        }
        ActionResult = "Failure";
        return ActionResult + ActionResultError;
    }

}