2005-03-08 20:52:13 -05:00
|
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
|
|
<html>
|
|
|
|
<head>
|
2005-03-08 20:59:14 -05:00
|
|
|
<title>Lucene Powered Swing Data Models</title>
|
2005-03-08 20:52:13 -05:00
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1><strong> Lucene Powered Swing Data Models </strong></h1>
|
|
|
|
<p><strong>by Jonathan Simon </strong></p>
|
|
|
|
<p> </p>
|
|
|
|
<p><strong>What it is.</strong></p>
|
|
|
|
<p>This package contains classes that help you easily integrate Lucene based searching
|
|
|
|
into your Swing components. Currently there are classes to index and search
|
|
|
|
JTables and JLists. This is done using model decorators rather than custom models
|
|
|
|
to make it easier to search current models as well as new ones. </p>
|
|
|
|
<p><em>These models do not actually contain any data</em>. Rather, the ListModel
|
|
|
|
decorator (ListSearcher) and the TableModel decorator (TableSearcher) take a
|
|
|
|
model in the constructor and delegate all calls to it (after a little alteration,
|
|
|
|
but we'll get to that). That said, these are not full fledged models themselves.
|
|
|
|
You still have to have another model to decorate with the searching models.
|
|
|
|
If you are adding searching to a pre-existing model, you can use your pre-existing
|
|
|
|
model directly. Otherwise, you can implement a model from scratch or use a pre-existing
|
|
|
|
one to get started. </p>
|
|
|
|
<p><strong>What it isn't. </strong></p>
|
|
|
|
<p>A complete component: These are just models. They are not complete components
|
|
|
|
with search fields and buttons laid out like a searchable interface. You still
|
|
|
|
have to build that since the UI changes drastically between applciations.</p>
|
|
|
|
<p>A complete model: There are just model decorators. You can't just set the model
|
|
|
|
of a JList or JTable to one of these models, and you can't add data directly
|
|
|
|
to these models. </p>
|
|
|
|
<p>A front end for a lucene index: In other words, you can't use these classes
|
|
|
|
to point a JTable directly to a Lucene index. Although that's interesting in
|
|
|
|
its own right, this is not that. </p>
|
|
|
|
<p><strong>Usage: </strong></p>
|
|
|
|
<p>Coding to both models nearly identical. They both take the model to decorate
|
|
|
|
at construction time. Here is the code from the demo to decorate a JTable model
|
|
|
|
with the TableSearcher and set it as the table model. </p>
|
|
|
|
<pre><code>//make a new JTable
|
|
|
|
JTable table = new JTable();
|
|
|
|
//make my base model, the model with the data
|
|
|
|
BaseTableModel tableModel = new BaseTableModel(DataStore.getRestaurants());
|
|
|
|
//decorate the tableModel with the TableSearcher
|
|
|
|
TableSearcher searchTableModel = new TableSearcher(tableModel);
|
|
|
|
//set the TableModel in the table to the TableSearcher
|
|
|
|
table.setModel(searchTableModel);
|
|
|
|
</code></pre>
|
|
|
|
<p>Initially, you won't notice a difference. This is because there is no active
|
|
|
|
search which displays all data from the underlying model. You search by calling
|
|
|
|
the <code>search</code>() method passing a search string. This filters the data
|
|
|
|
set down without changing the underlying data model -- one of the main reasons
|
|
|
|
for decorating in the first place. Any valid Lucene search string should work
|
|
|
|
(see notes for more info on this). You'll probaby have some code somewhere like
|
|
|
|
this in your app to connect a text field and search button to the model. </p>
|
|
|
|
<pre><code>//create components
|
|
|
|
final JTextField searchField = new JTextField();
|
|
|
|
JButton searchButton = new JButton("Go");
|
|
|
|
|
|
|
|
//make an action listener
|
|
|
|
ActionListener searchListener = new ActionListener() {
|
|
|
|
public void actionPerformed(ActionEvent e) {
|
|
|
|
searchTableModel.search(searchField.getText().trim().toLowerCase());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//register listeners
|
|
|
|
searchButton.addActionListener(searchListener);
|
|
|
|
searchField.addActionListener(searchListener);</code></pre>
|
|
|
|
<p>You also might want to have a clear search button, working the same way. But
|
|
|
|
to keep things simple, if you search will a <code>null </code>String or an empty
|
|
|
|
String, the search clears and you will once again see all of your data. </p>
|
|
|
|
<p><strong>Demo notes:</strong> </p>
|
|
|
|
<p>The list demo does real time searching. In other words, as you type, searches
|
|
|
|
run and the result set updates. The table demo has a search button, and only
|
|
|
|
searches when the button is clicked. They both work, I just implemented them
|
|
|
|
this way to show the different UI metaphors and that they both work.</p>
|
|
|
|
<p><strong>Implementation notes: </strong></p>
|
|
|
|
<p>This code started as a proof of concept so it's not a <em>fully</em> featured
|
|
|
|
model. Don't get me wrong, it <em>fully</em> works, but it could use some improvement
|
|
|
|
that it will hopefully get over time. I just wanted to get it out there and
|
|
|
|
get people using it. I'm also trying to keep everything as simple as possible.
|
|
|
|
Here are some of the issues. </p>
|
|
|
|
<ul>
|
|
|
|
<li>You can't change the model after the Searcher is constructed. </li>
|
|
|
|
<li>The search model decorators <em>do</em> update when the decorated model
|
|
|
|
is updated, but not in a very efficient way. The whole search model is reindexed
|
|
|
|
when anything changes. This is a definite scaling issue. </li>
|
|
|
|
<li>The indexing and searching logic needs to be generally more configurable
|
|
|
|
to allow custom tailoring of searched and indexing. </li>
|
|
|
|
<li>The TableSearcher uses column names to index column values. This could be
|
|
|
|
an issue with multiple word column names. </li>
|
|
|
|
<li>The ListSearcher uses MultiFieldQueryParser even though its not really indexing
|
|
|
|
multiple fields. </li>
|
|
|
|
</ul>
|
|
|
|
<p> </p>
|
|
|
|
<p> </p>
|
|
|
|
</body>
|
|
|
|
</html>
|