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