324 lines
12 KiB
HTML
324 lines
12 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||
<title>Implementing Key
|
||
Creators
|
||
|
||
</title>
|
||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB" />
|
||
<link rel="up" href="indexes.html" title="Chapter 10. Secondary Databases" />
|
||
<link rel="previous" href="indexes.html" title="Chapter 10. Secondary Databases" />
|
||
<link rel="next" href="secondaryProps.html" title="Secondary Database Properties" />
|
||
</head>
|
||
<body>
|
||
<div class="navheader">
|
||
<table width="100%" summary="Navigation header">
|
||
<tr>
|
||
<th colspan="3" align="center">Implementing Key
|
||
Creators
|
||
|
||
</th>
|
||
</tr>
|
||
<tr>
|
||
<td width="20%" align="left"><a accesskey="p" href="indexes.html">Prev</a> </td>
|
||
<th width="60%" align="center">Chapter 10. Secondary Databases</th>
|
||
<td width="20%" align="right"> <a accesskey="n" href="secondaryProps.html">Next</a></td>
|
||
</tr>
|
||
</table>
|
||
<hr />
|
||
</div>
|
||
<div class="sect1" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h2 class="title" style="clear: both"><a id="keyCreator"></a>Implementing Key
|
||
<span>Creators</span>
|
||
|
||
</h2>
|
||
</div>
|
||
</div>
|
||
<div></div>
|
||
</div>
|
||
<p>
|
||
You must provide every secondary database with a
|
||
<span>class</span>
|
||
|
||
that creates keys from primary records. You identify this
|
||
<span>class</span>
|
||
|
||
|
||
<span>
|
||
using the <tt class="methodname">SecondaryConfig.setKeyCreator()</tt>
|
||
method.
|
||
</span>
|
||
|
||
</p>
|
||
<p>
|
||
You can create keys using whatever data you want. Typically you will
|
||
base your key on some information found in a record's data, but you
|
||
can also use information found in the primary record's key. How you build
|
||
your keys is entirely dependent upon the nature of the index that you
|
||
want to maintain.
|
||
</p>
|
||
<p>
|
||
You implement a key creator by writing a class that implements the
|
||
<tt class="classname">SecondaryKeyCreator</tt> interface. This interface
|
||
requires you to implement the <tt class="methodname">SecondaryKeyCreator.createSecondaryKey()</tt>
|
||
method.
|
||
</p>
|
||
<p>
|
||
One thing to remember when implementing this method is that you will
|
||
need a way to extract the necessary information from the data's
|
||
<tt class="classname">DatabaseEntry</tt> and/or the key's
|
||
<tt class="classname">DatabaseEntry</tt> that are provided on calls to this
|
||
method. If you are using complex objects, then you are probably using the
|
||
Bind APIs to perform this conversion. The easiest thing to do is to
|
||
instantiate the <tt class="classname">EntryBinding</tt> or
|
||
<tt class="classname">TupleBinding</tt> that you need to perform the
|
||
conversion, and then provide this to your key creator's constructor.
|
||
The Bind APIs are introduced in <a href="bindAPI.html">Using the BIND APIs</a>.
|
||
</p>
|
||
<p>
|
||
<tt class="methodname">SecondaryKeyCreator.createSecondaryKey()</tt> returns a
|
||
boolean. A return value of <tt class="literal">false</tt> indicates that
|
||
no secondary key exists, and therefore no record should be added to the secondary database for that primary record.
|
||
If a record already exists in the secondary database, it is deleted.
|
||
</p>
|
||
<p>
|
||
For example, suppose your primary database uses the following class
|
||
for its record data:
|
||
</p>
|
||
<a id="java_index3"></a>
|
||
<pre class="programlisting">package db.GettingStarted;
|
||
|
||
public class PersonData {
|
||
private String userID;
|
||
private String surname;
|
||
private String familiarName;
|
||
|
||
public PersonData(String userID, String surname, String familiarName) {
|
||
this.userID = userID;
|
||
this.surname = surname;
|
||
this.familiarName = familiarName;
|
||
}
|
||
|
||
public String getUserID() {
|
||
return userID;
|
||
}
|
||
|
||
public String getSurname() {
|
||
return surname;
|
||
}
|
||
|
||
public String getFamiliarName() {
|
||
return familiarName;
|
||
}
|
||
} </pre>
|
||
<p>
|
||
Also, suppose that you have created a custom tuple binding,
|
||
<tt class="classname">PersonDataBinding</tt>, that you use to convert
|
||
<tt class="classname">PersonData</tt> objects to and from
|
||
<tt class="classname">DatabaseEntry</tt> objects. (Custom tuple bindings are
|
||
described in <a href="bindAPI.html#customTuple">Custom Tuple Bindings</a>.)
|
||
</p>
|
||
<p>
|
||
Finally, suppose you want a secondary database that is keyed based
|
||
on the person's full name.
|
||
</p>
|
||
<p>
|
||
Then in this case you might create a key creator as follows:
|
||
</p>
|
||
<a id="java_index4"></a>
|
||
<pre class="programlisting">package db.GettingStarted;
|
||
|
||
import com.sleepycat.bind.tuple.TupleBinding;
|
||
import com.sleepycat.db.SecondaryKeyCreator;
|
||
import com.sleepycat.db.DatabaseEntry;
|
||
import com.sleepycat.db.DatabaseException;
|
||
import com.sleepycat.db.SecondaryDatabase;
|
||
|
||
import java.io.IOException;
|
||
|
||
public class FullNameKeyCreator implements SecondaryKeyCreator {
|
||
|
||
private TupleBinding theBinding;
|
||
|
||
public FullNameKeyCreator(TupleBinding theBinding1) {
|
||
theBinding = theBinding1;
|
||
}
|
||
|
||
public boolean createSecondaryKey(SecondaryDatabase secDb,
|
||
DatabaseEntry keyEntry,
|
||
DatabaseEntry dataEntry,
|
||
DatabaseEntry resultEntry) {
|
||
|
||
try {
|
||
PersonData pd =
|
||
(PersonData) theBinding.entryToObject(dataEntry);
|
||
String fullName = pd.getFamiliarName() + " " +
|
||
pd.getSurname();
|
||
resultEntry.setData(fullName.getBytes("UTF-8"));
|
||
} catch (IOException willNeverOccur) {}
|
||
return true;
|
||
}
|
||
} </pre>
|
||
<p>Finally, you use this key creator as follows:</p>
|
||
<a id="java_index5"></a>
|
||
<pre class="programlisting">package db.GettingStarted;
|
||
|
||
import com.sleepycat.bind.tuple.TupleBinding;
|
||
|
||
import com.sleepycat.db.Database;
|
||
import com.sleepycat.db.DatabaseException;
|
||
import com.sleepycat.db.DatabaseType;
|
||
import com.sleepycat.db.SecondaryDatabase;
|
||
import com.sleepycat.db.SecondaryConfig;
|
||
|
||
import java.io.FileNotFoundException;
|
||
|
||
...
|
||
Database myDb = null;
|
||
SecondaryDatabase mySecDb = null;
|
||
try {
|
||
// Primary database open omitted for brevity
|
||
...
|
||
|
||
TupleBinding myDataBinding = new MyTupleBinding();
|
||
FullNameKeyCreator fnkc = new FullNameKeyCreator(myDataBinding);
|
||
|
||
SecondaryConfig mySecConfig = new SecondaryConfig();
|
||
mySecConfig.setKeyCreator(fnkc);
|
||
mySecConfig.setType(DatabaseType.BTREE);
|
||
|
||
//Perform the actual open
|
||
String secDbName = "mySecondaryDatabase";
|
||
mySecDb = new SecondaryDatabase(secDbName, null, myDb, mySecConfig);
|
||
} catch (DatabaseException de) {
|
||
// Exception handling goes here
|
||
} catch (FileNotFoundException fnfe) {
|
||
// Exception handling goes here
|
||
} finally {
|
||
try {
|
||
if (mySecDb != null) {
|
||
mySecDb.close();
|
||
}
|
||
|
||
if (myDb != null) {
|
||
myDb.close();
|
||
}
|
||
} catch (DatabaseException dbe) {
|
||
// Exception handling goes here
|
||
}
|
||
}</pre>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="multikeys"></a>Working with Multiple Keys</h3>
|
||
</div>
|
||
</div>
|
||
<div></div>
|
||
</div>
|
||
<p>
|
||
Until now we have only discussed indexes as if there is
|
||
a one-to-one relationship between the secondary key and
|
||
the primary database record. In fact, it is possible to
|
||
generate multiple keys for any given record, provided
|
||
that you take appropriate steps in your key creator
|
||
to do so.
|
||
</p>
|
||
<p>
|
||
For example, suppose you had a database that contained
|
||
information about books. Suppose further that you
|
||
sometimes want to look up books by author. Because
|
||
sometimes books have multiple authors, you may want to
|
||
return multiple secondary keys for every book that you
|
||
index.
|
||
</p>
|
||
<p>
|
||
To do this, you write a key creator that implements
|
||
<tt class="classname">SecondaryMultiKeyCreator</tt>
|
||
instead of
|
||
<tt class="classname">SecondaryKeyCreator</tt>. The key
|
||
difference between the two is that
|
||
<tt class="classname">SecondaryKeyCreator</tt>
|
||
uses a single <tt class="classname">DatabaseEntry</tt>
|
||
object as the result, while
|
||
<tt class="classname">SecondaryMultiKeyCreator</tt>
|
||
returns a set of <tt class="classname">DatabaseEntry</tt>
|
||
objects (using <tt class="classname">java.util.Set</tt>).
|
||
Also, you assign the
|
||
<tt class="classname">SecondaryMultiKeyCreator</tt>
|
||
implementation using
|
||
<tt class="methodname">SecondaryConfig.setMultiKeyCreator()</tt>
|
||
instead of
|
||
<tt class="methodname">SecondaryConfig.setKeyCreator()</tt>.
|
||
</p>
|
||
<p>
|
||
For example:
|
||
</p>
|
||
<pre class="programlisting">package db.GettingStarted;
|
||
|
||
import com.sleepycat.db.DatabaseEntry;
|
||
import com.sleepycat.db.DatabaseException;
|
||
import com.sleepycat.db.SecondaryDatabase;
|
||
import com.sleepycat.db.SecondaryMultiKeyCreator;
|
||
|
||
import java.util.HashSet;
|
||
import java.util.Set;
|
||
|
||
public class MyMultiKeyCreator implements SecondaryMultiKeyCreator {
|
||
|
||
// Constructor not implemented. How this is implemented depends on
|
||
// how you want to extract the data for your keys.
|
||
MyMultiKeyCreator() {
|
||
...
|
||
}
|
||
|
||
// Abstract method that we must implement
|
||
public void createSecondaryKeys(SecondaryDatabase secDb,
|
||
DatabaseEntry keyEntry, // From the primary
|
||
DatabaseEntry dataEntry, // From the primary
|
||
Set results) // Results set
|
||
throws DatabaseException {
|
||
|
||
try {
|
||
// Create your keys, adding each to the set
|
||
|
||
// Creation of key 'a' not shown
|
||
results.add(a)
|
||
|
||
// Creation of key 'b' not shown
|
||
results.add(b)
|
||
|
||
} catch (IOException willNeverOccur) {}
|
||
}
|
||
} </pre>
|
||
</div>
|
||
</div>
|
||
<div class="navfooter">
|
||
<hr />
|
||
<table width="100%" summary="Navigation footer">
|
||
<tr>
|
||
<td width="40%" align="left"><a accesskey="p" href="indexes.html">Prev</a> </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="u" href="indexes.html">Up</a>
|
||
</td>
|
||
<td width="40%" align="right"> <a accesskey="n" href="secondaryProps.html">Next</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td width="40%" align="left" valign="top">Chapter 10. Secondary Databases </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="h" href="index.html">Home</a>
|
||
</td>
|
||
<td width="40%" align="right" valign="top"> Secondary Database Properties</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</body>
|
||
</html>
|