2010-12-05 3 views
2

J'ai lu et recherché depuis un certain temps et je n'arrive pas à comprendre comment utiliser Lucene dans mon programme Java qui contient un jTable.Comment implémenter Lucene TableSearch avec jTable

Ce que je veux être en mesure de faire est de rechercher la table lors de la soumission d'une nouvelle entrée de ligne. Est-ce que je crée simplement un TableModel à partir de mon jTable et le passe dans le constructeur TableSearcher si j'inclue le fichier jar 3.3 Lucene dans mon chemin? J'ai inclus une partie de mon code ... s'il vous plaît, j'accueille n'importe quelle direction! Merci.

Voici ma méthode pour renseigner mon jtable à partir des données stockées dans des vecteurs:

...

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); 
    } .... 

Voici mon code qui insère une nouvelle ligne dans le 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(); 

} 

Et voici le modèle TableSearcher que j'utilise (j'ai ajouté de nouvelles fonctionnalités à la méthode de recherche). Qu'est-ce qui se passe est quand je saisis une nouvelle entrée, la recherche trouve cette entrée en tant que doublon et le renvoie dans mon jFrame je implémente dans la méthode de recherche du TableSearcher. Cela se produit uniquement avec une entrée unique qui ne correspond pas dans la table indexée. S'il y a un résultat de recherche dans l'index qui correspond à ma nouvelle entrée, alors seule l'entrée existante s'affiche dans mon jFrame, pas le nouveau que j'essaye.

// provided by Jonathan Simon <[email protected]> 

classe TableSearcher étend 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; 
    } 

} 

Répondre

0

Il semble que votre code ne pas indexer les données de la table avec Lucene. Un moyen simple de le faire est de créer votre propre modèle de table indexé en interne, avec une fonction de recherche exposée que vous pouvez connecter pour limiter les données affichées. C'est ce que j'ai écrit dans Swing Hacks il y a quelques années.

Sans l'indexation, Lucene ne fonctionnera pas automatiquement car elle se trouve dans votre classpath.

Jonathan

+0

donc je pourrais faire quelque chose comme ajouter une autre classe appelée TableSearcher qui est beaucoup comme celui-ci http://demo.spars.info/j/frameset.cgi? compo_id = 61780 & mode = frameset & ref = 3 & method = 334 & CASE = 0 & MORPHO = 1 & location = 1111111111111111111 & LANG = 1 et ensuite passer mon modèle de table actuel ici après avoir appuyé sur le bouton "Enregistrer" sur mon application. Puis-je afficher ces données dans un pop-up jpanel/jtable? – taraloca

0

un coup d'oeil à la very simple example

dans votre cas, vous feriez quelque chose comme cela pour créer le document, qui obtiendraient enregistré dans l'index.

ce code n'est pas complet ou nécessairement sans erreur ,; mais est plus d'un point de départ pour vous aider à aller

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();