SearchEngine.java revision 494
1364N/A/*
1364N/A * CDDL HEADER START
1364N/A *
1364N/A * The contents of this file are subject to the terms of the
1364N/A * Common Development and Distribution License (the "License").
1364N/A * You may not use this file except in compliance with the License.
1364N/A *
1364N/A * See LICENSE.txt included in this distribution for the specific
1364N/A * language governing permissions and limitations under the License.
1364N/A *
1364N/A * When distributing Covered Code, include this CDDL HEADER in each
1364N/A * file and include the License file at LICENSE.txt.
1364N/A * If applicable, add the following below this CDDL HEADER, with the
1364N/A * fields enclosed by brackets "[]" replaced with your own identifying
1364N/A * information: Portions Copyright [yyyy] [name of copyright owner]
1364N/A *
1364N/A * CDDL HEADER END
1364N/A */
1364N/A
1364N/A/*
1364N/A * Copyright 2005 Trond Norbye. All rights reserved.
1364N/A * Use is subject to license terms.
1364N/A */
1370N/A
1364N/Apackage org.opensolaris.opengrok.search;
1364N/A
1370N/Aimport java.io.BufferedReader;
1364N/Aimport java.io.File;
1364N/Aimport java.io.FileInputStream;
1364N/Aimport java.io.FileNotFoundException;
1364N/Aimport java.io.FileReader;
1364N/Aimport java.io.IOException;
1364N/Aimport java.io.InputStreamReader;
1364N/Aimport java.io.Reader;
1364N/Aimport java.util.ArrayList;
1364N/Aimport java.util.Iterator;
1364N/Aimport java.util.List;
1364N/Aimport java.util.logging.Level;
1364N/Aimport org.apache.lucene.document.Document;
1364N/Aimport org.apache.lucene.document.Fieldable;
1364N/Aimport org.apache.lucene.index.IndexReader;
1364N/Aimport org.apache.lucene.queryParser.QueryParser;
1364N/Aimport org.apache.lucene.search.Hits;
1364N/Aimport org.apache.lucene.search.IndexSearcher;
1364N/Aimport org.apache.lucene.search.Query;
1364N/Aimport org.apache.lucene.search.Searcher;
1364N/Aimport org.opensolaris.opengrok.OpenGrokLogger;
1364N/Aimport org.opensolaris.opengrok.analysis.CompatibleAnalyser;
1364N/Aimport org.opensolaris.opengrok.analysis.Definitions;
1364N/Aimport org.opensolaris.opengrok.analysis.TagFilter;
1364N/Aimport org.opensolaris.opengrok.configuration.Project;
1364N/Aimport org.opensolaris.opengrok.configuration.RuntimeEnvironment;
1364N/Aimport org.opensolaris.opengrok.search.Summary.Fragment;
1364N/Aimport org.opensolaris.opengrok.search.context.Context;
1364N/Aimport org.opensolaris.opengrok.search.context.HistoryContext;
1364N/Aimport org.opensolaris.opengrok.web.Util;
1364N/A
1364N/A/**
1364N/A * This is an encapsulation of the details on how to seach in the index
1364N/A * database.
1364N/A *
1364N/A * @author Trond Norbye
1364N/A */
1364N/Apublic class SearchEngine {
1364N/A /**
1364N/A * Holds value of property definition.
1364N/A */
1364N/A private String definition;
1364N/A
1364N/A /**
1364N/A * Holds value of property file.
1364N/A */
1364N/A private String file;
1364N/A
1364N/A /**
1364N/A * Holds value of property freetext.
1364N/A */
1364N/A private String freetext;
1364N/A
1364N/A /**
1364N/A * Holds value of property history.
1364N/A */
1364N/A private String history;
1364N/A
1364N/A /**
1364N/A * Holds value of property symbol.
1364N/A */
1364N/A private String symbol;
1364N/A
1364N/A /**
1364N/A * Holds value of property indexDatabase.
1364N/A */
1364N/A private Query query;
1364N/A private final CompatibleAnalyser analyzer;
1364N/A private final QueryParser qparser;
1364N/A private Context sourceContext;
1364N/A private HistoryContext historyContext;
1364N/A private Summarizer summer;
1364N/A private final List<org.apache.lucene.search.Hit> hits;
1364N/A private final char[] content = new char[1024*8];
1364N/A private String source;
1364N/A private String data;
1364N/A
1364N/A /**
1364N/A * Creates a new instance of SearchEngine
1364N/A */
1364N/A public SearchEngine() {
1364N/A analyzer = new CompatibleAnalyser();
1364N/A qparser = new QueryParser("full", analyzer);
1364N/A qparser.setDefaultOperator(QueryParser.AND_OPERATOR);
1364N/A qparser.setAllowLeadingWildcard(RuntimeEnvironment.getInstance().isAllowLeadingWildcard());
1364N/A hits = new ArrayList<org.apache.lucene.search.Hit>();
1364N/A }
1364N/A
1364N/A public boolean isValidQuery() {
1370N/A boolean ret = false;
1364N/A String qry = Util.buildQueryString(freetext, definition, symbol, file, history);
1364N/A if (qry.length() > 0) {
1370N/A try {
1364N/A query = qparser.parse(qry);
1364N/A ret = true;
1370N/A } catch (Exception e) {
1364N/A }
1364N/A }
1364N/A
1370N/A return ret;
1364N/A }
1364N/A
1370N/A private void searchSingleDatabase(File root) throws IOException {
1364N/A IndexReader ireader = IndexReader.open(root);
1364N/A Searcher searcher = new IndexSearcher(ireader);
1364N/A Hits res = searcher.search(query);
1364N/A if (res.length() > 0) {
1370N/A Iterator iter = res.iterator();
1364N/A while (iter.hasNext()) {
1364N/A org.apache.lucene.search.Hit h = (org.apache.lucene.search.Hit) iter.next();
1364N/A hits.add(h);
1364N/A }
1364N/A }
1364N/A
1364N/A }
1364N/A
1370N/A public String getQuery() {
1364N/A return query.toString();
1364N/A }
1364N/A
1364N/A /**
1370N/A * Execute a search. Before calling this function, you must set the
1370N/A * appropriate seach critera with the set-functions.
1370N/A *
1364N/A * @return The number of hits
1364N/A */
1364N/A public int search() {
1364N/A source = RuntimeEnvironment.getInstance().getSourceRootPath();
1370N/A data = RuntimeEnvironment.getInstance().getDataRootPath();
1370N/A hits.clear();
1364N/A
1370N/A String qry = Util.buildQueryString(freetext, definition, symbol, file, history);
1364N/A if (qry.length() > 0) {
1364N/A try {
1370N/A query = qparser.parse(qry);
1364N/A RuntimeEnvironment env = RuntimeEnvironment.getInstance();
1364N/A File root = new File(env.getDataRootFile(), "index");
1364N/A
1364N/A if (env.hasProjects()) {
1364N/A // search all projects
1364N/A for (Project project : env.getProjects()) {
1364N/A searchSingleDatabase(new File(root, project.getPath()));
1364N/A }
1364N/A } else {
1364N/A // search the index database
1364N/A searchSingleDatabase(root);
1364N/A }
1364N/A } catch (Exception e) {
1364N/A OpenGrokLogger.getLogger().log(Level.WARNING, "Exception searching", e);
1364N/A }
1364N/A }
1364N/A if (!hits.isEmpty()) {
1364N/A sourceContext = null;
1364N/A summer = null;
1364N/A try {
1364N/A sourceContext = new Context(query);
1364N/A if(sourceContext.isEmpty()) {
1364N/A sourceContext = null;
1364N/A }
1364N/A summer = new Summarizer(query, analyzer);
1364N/A } catch (Exception e) {
1364N/A }
1364N/A
1364N/A historyContext = null;
1364N/A try {
1364N/A historyContext = new HistoryContext(query);
1364N/A if(historyContext.isEmpty()) {
1364N/A historyContext = null;
1364N/A }
1364N/A } catch (Exception e) {
1364N/A }
1364N/A }
1364N/A return hits.size();
1364N/A }
1364N/A
1364N/A public void more(int start, int end, List<Hit> ret) {
1364N/A int len = end;
1364N/A if (end > hits.size()) {
1364N/A len = hits.size();
1364N/A }
1364N/A for (int ii = start; ii < len; ++ii) {
1364N/A boolean alt = (ii % 2 == 0);
1364N/A boolean hasContext = false;
1364N/A try {
1364N/A Document doc = hits.get(ii).getDocument();
1364N/A String filename = doc.get("path");
1364N/A String genre = doc.get("t");
1364N/A Definitions tags = null;
1364N/A Fieldable tagsField = doc.getFieldable("tags");
1364N/A if (tagsField != null) {
1364N/A tags = Definitions.deserialize(tagsField.binaryValue());
1364N/A }
1364N/A int nhits = hits.size();
1364N/A
1364N/A if(sourceContext != null) {
1364N/A try {
1364N/A if ("p".equals(genre) && (source != null)) {
1364N/A hasContext = sourceContext.getContext(new InputStreamReader(new FileInputStream(source +
1364N/A filename)), null, null, null, filename,
1364N/A tags, nhits > 100, ret);
1364N/A } else if("x".equals(genre) && data != null && summer != null){
1364N/A int l = 0;
1364N/A Reader r = new TagFilter(new BufferedReader(new FileReader(data + "/xref" + filename)));
1364N/A try {
1364N/A l = r.read(content);
1364N/A } finally {
1364N/A r.close();
1364N/A }
1364N/A Summary sum = summer.getSummary(new String(content, 0, l));
1364N/A Fragment fragments[] = sum.getFragments();
1364N/A for (int jj = 0; jj < fragments.length; ++jj) {
1364N/A String match = fragments[jj].toString();
1364N/A if (match.length() > 0) {
1364N/A if (!fragments[jj].isEllipsis()) {
1364N/A Hit hit = new Hit(filename, fragments[jj].toString(), "", true, alt);
1364N/A ret.add(hit);
1364N/A }
1364N/A hasContext = true;
1364N/A }
1364N/A }
1364N/A } else {
1364N/A OpenGrokLogger.getLogger().warning("Unknown genre: " + genre);
1364N/A hasContext |= sourceContext.getContext(null, null, null, null, filename, tags, false, ret);
1364N/A }
1364N/A } catch (FileNotFoundException exp) {
1364N/A hasContext |= sourceContext.getContext(null, null, null, null, filename, tags, false, ret);
1364N/A }
1364N/A }
1364N/A if (historyContext != null) {
1364N/A hasContext |= historyContext.getContext(source + filename, filename, ret);
1364N/A }
1364N/A if(!hasContext) {
1364N/A ret.add(new Hit(filename, "...", "", false, alt));
1364N/A }
1364N/A } catch (IOException e) {
1364N/A OpenGrokLogger.getLogger().log(Level.WARNING, "Exception searching", e);
1364N/A } catch (ClassNotFoundException e) {
1364N/A OpenGrokLogger.getLogger().log(Level.WARNING, "Exception searching", e);
1364N/A }
1364N/A }
1364N/A
1364N/A }
1364N/A
1364N/A /**
1364N/A * Getter for property definition.
1364N/A *
1364N/A * @return Value of property definition.
1364N/A */
1364N/A public String getDefinition() {
1364N/A return this.definition;
1364N/A }
1364N/A
1364N/A /**
1364N/A * Setter for property definition.
1364N/A *
1364N/A * @param definition New value of property definition.
1364N/A */
1364N/A public void setDefinition(String definition) {
1364N/A this.definition = definition;
1364N/A }
1364N/A
1364N/A /**
1364N/A * Getter for property file.
1364N/A *
1364N/A * @return Value of property file.
1364N/A */
1364N/A public String getFile() {
1364N/A return this.file;
1364N/A }
1364N/A
1364N/A /**
1364N/A * Setter for property file.
949N/A *
1186N/A * @param file New value of property file.
1186N/A */
1294N/A public void setFile(String file) {
1186N/A this.file = file;
949N/A }
954N/A
1186N/A /**
949N/A * Getter for property freetext.
949N/A *
949N/A * @return Value of property freetext.
1186N/A */
1186N/A public String getFreetext() {
1186N/A return this.freetext;
1186N/A }
1186N/A
1186N/A /**
1186N/A * Setter for property freetext.
1186N/A *
1186N/A * @param freetext New value of property freetext.
1186N/A */
1186N/A public void setFreetext(String freetext) {
1186N/A this.freetext = freetext;
1186N/A }
1186N/A
1186N/A /**
1186N/A * Getter for property history.
1186N/A *
1186N/A * @return Value of property history.
1186N/A */
1186N/A public String getHistory() {
1186N/A return this.history;
1186N/A }
1186N/A
1186N/A /**
1186N/A * Setter for property history.
1186N/A *
1186N/A * @param history New value of property history.
1186N/A */
949N/A public void setHistory(String history) {
949N/A this.history = history;
1186N/A }
1186N/A
1186N/A /**
1186N/A * Getter for property symbol.
1186N/A *
1186N/A * @return Value of property symbol.
1186N/A */
1186N/A public String getSymbol() {
1186N/A return this.symbol;
1186N/A }
1186N/A
1254N/A /**
1254N/A * Setter for property symbol.
1254N/A *
1254N/A * @param symbol New value of property symbol.
1254N/A */
1186N/A public void setSymbol(String symbol) {
1186N/A this.symbol = symbol;
1186N/A }
1186N/A}
1186N/A