FileDocCategorySizeDatePackage
ListSearcher.javaAPI DocApache Lucene 2.1.09301Wed Feb 14 10:46:10 GMT 2007org.apache.lucene.swing.models

ListSearcher

public class ListSearcher extends AbstractListModel
See table searcher explanation.
author
Jonathan Simon - jonathan_s_simon@yahoo.com

Fields Summary
private ListModel
listModel
private ArrayList
rowToModelIndex
The reference links between the decorated ListModel and this list model based on search criteria
private RAMDirectory
directory
In memory lucene index
private Analyzer
analyzer
Cached lucene analyzer
private static final String
ROW_NUMBER
Links between this list model and the decorated list model are maintained through links based on row number. This is a key constant to denote "row number" for indexing
private static final String
FIELD_NAME
Since we only have one field, unlike lists with multiple fields -- we are just using a constant to denote field name. This is most likely unnecessary and should be removed at a later date
private String
searchString
Cache the current search String. Also used internally to key whether there is an active search running or not. i.e. if searchString is null, there is no active search.
private ListDataListener
listModelListener
Constructors Summary
public ListSearcher(ListModel newModel)


       
        analyzer = new WhitespaceAnalyzer();
        setListModel(newModel);
        listModelListener = new ListModelHandler();
        newModel.addListDataListener(listModelListener);
        clearSearchingState();
    
Methods Summary
private voidclearSearchingState()

        searchString = null;
        rowToModelIndex.clear();
        for (int t=0; t<listModel.getSize(); t++){
            rowToModelIndex.add(new Integer(t));
        }
    
public org.apache.lucene.analysis.AnalyzergetAnalyzer()

return
The current lucene analyzer

        return analyzer;
    
public java.lang.ObjectgetElementAt(int index)

        return listModel.getElementAt(getModelRow(index));
    
private intgetModelRow(int row)

        return ((Integer) rowToModelIndex.get(row)).intValue();
    
public intgetSize()

        return (listModel == null) ? 0 : rowToModelIndex.size();
    
private booleanisSearching()

        return searchString != null;
    
private voidreindex()

        try {
            // recreate the RAMDirectory
            directory = new RAMDirectory();
            IndexWriter writer = new IndexWriter(directory, analyzer, true);

            // iterate through all rows
            for (int row=0; row < listModel.getSize(); row++){

                //for each row make a new document
                Document document = new Document();
                //add the row number of this row in the decorated list model
                //this will allow us to retrive the results later
                //and map this list model's row to a row in the decorated
                //list model
                document.add(new Field(ROW_NUMBER, "" + row, Field.Store.YES, Field.Index.TOKENIZED));
                //add the string representation of the row to the index
                document.add(new Field(FIELD_NAME, String.valueOf(listModel.getElementAt(row)).toLowerCase(), Field.Store.YES, Field.Index.TOKENIZED));
                writer.addDocument(document);
            }
            writer.optimize();
            writer.close();
        } catch (Exception e){
            e.printStackTrace();
        }
    
private voidresetSearchResults(org.apache.lucene.search.Hits hits)

param
hits The new result set to set this list to.

        try {
            //clear our index mapping this list model rows to
            //the decorated inner list model
            rowToModelIndex.clear();
            //iterate through the hits
            //get the row number stored at the index
            //that number is the row number of the decorated
            //tabble model row that we are mapping to
            for (int t=0; t<hits.length(); t++){
                Document document = hits.doc(t);
                Fieldable field = document.getField(ROW_NUMBER);
                rowToModelIndex.add(new Integer(field.stringValue()));
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    
public voidsearch(java.lang.String searchString)
Run a new search.

param
searchString Any valid lucene search string


        //if search string is null or empty, clear the search == search all
        if (searchString == null || searchString.equals("")){
            clearSearchingState();
            fireContentsChanged(this, 0, getSize());
            return;
        }


        try {
            //cache search String
            this.searchString = searchString;

            //make a new index searcher with the in memory (RAM) index.
            IndexSearcher is = new IndexSearcher(directory);

            //make an array of fields - one for each column
            String[] fields = {FIELD_NAME};

            //build a query based on the fields, searchString and cached analyzer
            //NOTE: This is an area for improvement since the MultiFieldQueryParser
            // has some weirdness.
            MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer);
            Query query =parser.parse(searchString);
            //run the search
            Hits hits = is.search(query);
            //reset this list model with the new results
            resetSearchResults(hits);
        } catch (Exception e){
            e.printStackTrace();
        }

        //notify all listeners that the list has been changed
        fireContentsChanged(this, 0, getSize());
    
public voidsetAnalyzer(org.apache.lucene.analysis.Analyzer analyzer)

param
analyzer The new analyzer to use

        this.analyzer = analyzer;
        //reindex from the model with the new analyzer
        reindex();

        //rerun the search if there is an active search
        if (isSearching()){
            search(searchString);
        }
    
private voidsetListModel(javax.swing.ListModel newModel)

        //remove listeners if there...
        if (newModel != null) {
            newModel.removeListDataListener(listModelListener);
        }

        listModel = newModel;
        if (listModel != null) {
            listModel.addListDataListener(listModelListener);
        }

        //recalculate the links between this list model and
        //the inner list model since the decorated model just changed
        reindex();

        // let all listeners know the list has changed
        fireContentsChanged(this, 0, getSize());