如何使用jTable实现Lucene TableSearch

时间:2010-12-05 03:03:58

标签: java lucene

我一直在阅读和搜索相当长的一段时间,似乎无法理解如何在包含jTable的Java程序中使用Lucene。

我希望能够做的是在提交新行条目时搜索表格。如果我在路径中包含3.3 Lucene jar文件,我是否只是从我的jTable创建一个TableModel并将其传递给TableSearcher构造函数?我已经包含了一些代码......拜托,我欢迎任何方向!谢谢。

这是我从存储在向量中的数据填充jTable的方法:

...

public static boolean hasSearchResults = false;
public String selectedRequirementName;
public TableSearcher ts;
DefaultTableModel sc;

public TablePanel(int z, String name, String reason) { //pulls in panel number, project name, and whether the project was new or opened, from the MainGUI class
    initComponents();
    sc=(DefaultTableModel) reqTable.getModel();
    ts = new TableSearcher(sc);

    aProject = new Project(reason, name); //calls Project class to control the project

    try{

        requirementsVector = new Vector(aProject.getRequirementsList());
        requirementsList =new String[requirementsVector.size()];

        for(int i=0; i < requirementsVector.size(); i++){
            requirementsList[i] = requirementsVector.get(i).getName();
            System.out.println(requirementsList[i]);

            sc.addRow(new Object[]{
            requirementsVector.get(i).getName(),
            requirementsVector.get(i).getDefinition(),
            requirementsVector.get(i).getType(),
            requirementsVector.get(i).getPriority(),
            requirementsVector.get(i).getAssigned(),
            requirementsVector.get(i).getDue(),
            requirementsVector.get(i).getStatus()});
                //this.editingProjectName = name;

        }
    }catch(NullPointerException e1){
         System.out.println(e1);
    } ....

这是我的代码,它在jTable中插入一个新行:

private void ConfirmActionPerformed(java.awt.event.ActionEvent evt) {                                        
    String ReqName = nameTextField.getText();
    String ReqDescription = descriptionTextField.getText();
    String Type = (String)jType.getSelectedItem();
    String Priority = (String)PriorityComboBox.getSelectedItem();
    String Assigned = (String)jDateAssignedMonth.getSelectedItem() + "/" + (String)jDateAssignedDay.getSelectedItem() + "/" + (String)jDateAssignedYear.getSelectedItem();
    String Due = (String)jDateDueMonth.getSelectedItem() + "/" + (String)jDateDueDay.getSelectedItem() + "/" + (String)jDateDueYear.getSelectedItem();
    String Status = (String)jStatus.getSelectedItem();

    // search string pass to TableSearcher
    ts.search(ReqDescription);


    if (editingaRow == false && !hasSearchResults){
        sc.addRow(new Object[]{
        ReqName,ReqDescription,Type,Priority,Assigned, Due, Status
        });
        requirementsVector.add(new Requirement(ReqName, ReqDescription, Type, Priority, Assigned, Due,Status));
        aProject.saveRevision(requirementsVector, name);
    }else if (editingaRow == true){
        sc.setValueAt(ReqName,selectedRow,0);
        sc.setValueAt(ReqDescription,selectedRow,1);
        sc.setValueAt(Type,selectedRow,2);
        sc.setValueAt(Priority,selectedRow,3);
        sc.setValueAt(Assigned,selectedRow,4);
        sc.setValueAt(Due,selectedRow,5);
        sc.setValueAt(Status,selectedRow,6);

        requirementsVector.setElementAt(new Requirement(ReqName, ReqDescription, Type, Priority, Assigned, Due,Status),(selectedRow));

        aProject.saveRevision(requirementsVector, name);

        editingaRow = false;

    }
    disableRequirementEditor();
    newReq.setEnabled(true);
    reqTable.clearSelection();

} 

这是我正在使用的TableSearcher模型(我在搜索方法中添加了新功能)。发生的事情是当我输入一个新条目时,搜索会将该条目作为重复条目发现并在我在jqrame中将其返回给我在TableSearcher的搜索方法中实现。只有在索引表中没有匹配项的唯一条目才会发生这种情况。如果索引中的搜索结果与我的新条目匹配,则只有现有条目显示在我的jFrame中,而不是我正在尝试的新条目。

//  provided by Jonathan Simon <jonathan_s_simon@yahoo.com>

class TableSearcher扩展了AbstractTableModel {

/**
 * The inner table model we are decorating
 */
protected TableModel tableModel;

/**
 * This listener is used to register this class as a listener to
 * the decorated table model for update events
 */
private TableModelListener tableModelListener;

/**
 * these keeps reference to the decorated table model for data
 * only rows that match the search criteria are linked
 */
private ArrayList rowToModelIndex = new ArrayList();


//Lucene stuff.

/**
 * In memory lucene index
 */
private RAMDirectory directory;

/**
 * Cached lucene analyzer
 */
private Analyzer analyzer;

/**
 * Links between this table model and the decorated table model
 * are maintained through links based on row number. This is a
 * key constant to denote "row number" for indexing
 */
private static final String ROW_NUMBER = "ROW_NUMBER";

/**
 * 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 String searchString = null;

/**
 * @param tableModel The table model to decorate
 */
public TableSearcher(TableModel tableModel) {
    analyzer = new WhitespaceAnalyzer();
    tableModelListener = new TableModelHandler();
    setTableModel(tableModel);
    tableModel.addTableModelListener(tableModelListener);
    clearSearchingState();
}

/**
 *
 * @return The inner table model this table model is decorating
 */
public TableModel getTableModel() {
    return tableModel;
}

/**
 * Set the table model used by this table model
 * @param tableModel The new table model to decorate
 */
public final void setTableModel(TableModel tableModel) {

    //remove listeners if there...
    if (this.tableModel != null) {
        this.tableModel.removeTableModelListener(tableModelListener);
    }

    this.tableModel = tableModel;
    if (this.tableModel != null) {
        this.tableModel.addTableModelListener(tableModelListener);
    }

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

    // let all listeners know the table has changed
    fireTableStructureChanged();
}


/**
 * Reset the search results and links to the decorated (inner) table
 * model from this table model.
 */
private void reindex() {
    try {
        // recreate the RAMDirectory
        directory = new RAMDirectory();
        IndexWriter writer = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);

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

            //for each row make a new document
            Document document = new Document();
            //add the row number of this row in the decorated table model
            //this will allow us to retrive the results later
            //and map this table model's row to a row in the decorated
            //table model
            document.add(new Field(ROW_NUMBER, "" + row, Field.Store.YES, Field.Index.ANALYZED));
            //iterate through all columns
            //index the value keyed by the column name
            //NOTE: there could be a problem with using column names with spaces
            for (int column=0; column < tableModel.getColumnCount(); column++){
                String columnName = tableModel.getColumnName(column);
                String columnValue = String.valueOf(tableModel.getValueAt(row, column)).toLowerCase();
                document.add(new Field(columnName, columnValue, Field.Store.YES, Field.Index.ANALYZED));
            }
            writer.addDocument(document);
        }
        writer.optimize();
        writer.close();
    } catch (Exception e){
        e.printStackTrace();
    }
}

/**
 * @return The current lucene analyzer
 */
public Analyzer getAnalyzer() {
    return analyzer;
}

/**
 * @param analyzer The new analyzer to use
 */
public void setAnalyzer(Analyzer analyzer) {
    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);
    }
}

/**
 * Run a new search.
 *
 * @param searchString Any valid lucene search string
 */
public void search(String searchString){
    // to store row numbers of results rows to display later
    Vector<String> rowNums = new Vector();

    //if search string is null or empty, clear the search == search all
    if (searchString == null || searchString.equals("")){
        clearSearchingState();
        fireTableDataChanged();
        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 = new String[tableModel.getColumnCount()];
        for (int t=0; t<tableModel.getColumnCount(); t++){
            fields[t]=tableModel.getColumnName(t);
        }

        //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);
       for (int t=0; t<hits.length(); t++){

            Document document = hits.doc(t);
            Fieldable field = document.getField(ROW_NUMBER);
            // adding row numbers to vector
            rowNums.add(field.stringValue());

        }

        // trying to display search results in new table
        if(!rowNums.isEmpty()){
                TablePanel.hasSearchResults = true;
                for (int v=0; v<rowNums.size(); v++){
                    System.out.println("Match in row number  " + rowNums.elementAt(v));
                }

                JFrame frame = new JFrame("Possible Duplicates");

                String colNames[] = {"Name", "Definition", "Type", "Priority", "Date Assigned", "Due Date", "Status"};

                DefaultTableModel dtm = new DefaultTableModel(null,colNames);

                for (int r = 0; r<rowNums.size(); r++){
                    String ReqName = (String) tableModel.getValueAt(Integer.parseInt(rowNums.elementAt(r)), 0);
                    String ReqDescription = (String) tableModel.getValueAt(Integer.parseInt(rowNums.elementAt(r)), 1);
                    String Type = (String) tableModel.getValueAt(Integer.parseInt(rowNums.elementAt(r)), 2);
                    String Priority = (String) tableModel.getValueAt(Integer.parseInt(rowNums.elementAt(r)), 3);
                    String Assigned = (String) tableModel.getValueAt(Integer.parseInt(rowNums.elementAt(r)), 4);
                    String Due = (String) tableModel.getValueAt(Integer.parseInt(rowNums.elementAt(r)), 5);
                    String Status = (String) tableModel.getValueAt(Integer.parseInt(rowNums.elementAt(r)), 6);
                    dtm.addRow(new Object[]{
                         ReqName,ReqDescription,Type,Priority,Assigned, Due, Status
                           });
                }

                JTable tblResults = new JTable(dtm);
                JScrollPane sp = new JScrollPane(tblResults);
                JPanel panel = new JPanel(new BorderLayout());
                panel.setPreferredSize(new Dimension(900,300));
                panel.add(sp,BorderLayout.CENTER);
                panel.add(new JLabel("Possible Duplicates",JLabel.CENTER),BorderLayout.SOUTH);
                JOptionPane.showConfirmDialog(null,panel);

            }
        //reset this table model with the new results
        resetSearchResults(hits);
    } catch (Exception e){
        e.printStackTrace();
    }

    //notify all listeners that the table has been changed
    fireTableStructureChanged();
}

/**
 *
 * @param hits The new result set to set this table to.
 */
private void resetSearchResults(Hits hits) {
    try {
        //clear our index mapping this table model rows to
        //the decorated inner table 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()));
            System.out.println("Something  " + rowToModelIndex.add(new Integer(field.stringValue())));
            clearSearchingState();
        }
    } catch (Exception e){
        e.printStackTrace();
    }
}

private int getModelRow(int row){
    return ((Integer) rowToModelIndex.get(row)).intValue();
}

/**
 * Clear the currently active search
 * Resets the complete dataset of the decorated
 * table model.
 */
private void clearSearchingState(){
    searchString = null;
    rowToModelIndex.clear();
    for (int t=0; t<tableModel.getRowCount(); t++){
        rowToModelIndex.add(new Integer(t));
    }
}

// TableModel interface methods
public int getRowCount() {
    return (tableModel == null) ? 0 : rowToModelIndex.size();
}

public int getColumnCount() {
    return (tableModel == null) ? 0 : tableModel.getColumnCount();
}

public String getColumnName(int column) {
    return tableModel.getColumnName(column);
}

public Class getColumnClass(int column) {
    return tableModel.getColumnClass(column);
}

public boolean isCellEditable(int row, int column) {
    return tableModel.isCellEditable(getModelRow(row), column);
}

public Object getValueAt(int row, int column) {
    return tableModel.getValueAt(getModelRow(row), column);
}

public void setValueAt(Object aValue, int row, int column) {
    tableModel.setValueAt(aValue, getModelRow(row), column);
}

private boolean isSearching() {
    return searchString != null;
}

private class TableModelHandler implements TableModelListener {
    public void tableChanged(TableModelEvent e) {
        // If we're not searching, just pass the event along.
        if (!isSearching()) {
            clearSearchingState();
            reindex();
            fireTableChanged(e);
            return;
        }

        // Something has happened to the data that may have invalidated the search.
        reindex();
        search(searchString);
        fireTableDataChanged();
        return;
    }

}

2 个答案:

答案 0 :(得分:0)

看起来您的代码没有使用Lucene索引表数据。一种简单的方法是创建自己的内部索引表模型,使用可以连接的公开搜索功能来限制显示的数据。这就是我几年前在Swing Hacks中所写的内容。

没有索引,Lucene不会自动“工作”,因为它在你的类路径中。

Jonathan

答案 1 :(得分:0)

查看very simple example

在你的情况下,你会做这样的事情来创建文档,它将被保存在索引中。

此代码不完整或无错误;但更多的是让你前进的起点

  Document doc = new Document(); 
  doc.add(new Field("ReqName", ReqName, Field.Store.YES, Field.Index.NOT_ANALYZED));   
  doc.add(new Field("ReqDescription", ReqDescription, Field.Store.YES, Field.Index.ANALYZED)); 
  doc.add(new Field("Type", Type, Field.Store.YES, Field.Index.NOT_ANALYZED));   
  doc.add(new Field("Priority", Priority, Field.Store.YES, Field.Index.NOT_ANALYZED));   
  doc.add(new Field("Assigned", Assigned, Field.Store.YES, Field.Index.NOT_ANALYZED));   
  doc.add(new Field("Due", Due, Field.Store.YES, Field.Index.NOT_ANALYZED));   
  doc.add(new Field("Status", Status, Field.Store.YES, Field.Index.NOT_ANALYZED));   
  writer.addDocument(doc); 
  writer.close();