mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-17 01:26:25 +00:00
456 lines
17 KiB
HTML
456 lines
17 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>Chapter 3. Using Secondary Indices</title>
|
|||
|
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
|||
|
<meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
|
|||
|
<link rel="start" href="index.html" title="Berkeley DB Collections Tutorial" />
|
|||
|
<link rel="up" href="index.html" title="Berkeley DB Collections Tutorial" />
|
|||
|
<link rel="prev" href="handlingexceptions.html" title="Handling Exceptions" />
|
|||
|
<link rel="next" href="openingforeignkeys.html" title="More Secondary Key Indices" />
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
<div xmlns="" class="navheader">
|
|||
|
<div class="libver">
|
|||
|
<p>Library Version 11.2.5.2</p>
|
|||
|
</div>
|
|||
|
<table width="100%" summary="Navigation header">
|
|||
|
<tr>
|
|||
|
<th colspan="3" align="center">Chapter 3.
|
|||
|
Using Secondary Indices
|
|||
|
</th>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td width="20%" align="left"><a accesskey="p" href="handlingexceptions.html">Prev</a> </td>
|
|||
|
<th width="60%" align="center"> </th>
|
|||
|
<td width="20%" align="right"> <a accesskey="n" href="openingforeignkeys.html">Next</a></td>
|
|||
|
</tr>
|
|||
|
</table>
|
|||
|
<hr />
|
|||
|
</div>
|
|||
|
<div class="chapter" lang="en" xml:lang="en">
|
|||
|
<div class="titlepage">
|
|||
|
<div>
|
|||
|
<div>
|
|||
|
<h2 class="title"><a id="UsingSecondaries"></a>Chapter 3.
|
|||
|
Using Secondary Indices
|
|||
|
</h2>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="toc">
|
|||
|
<p>
|
|||
|
<b>Table of Contents</b>
|
|||
|
</p>
|
|||
|
<dl>
|
|||
|
<dt>
|
|||
|
<span class="sect1">
|
|||
|
<a href="UsingSecondaries.html#opensecondaryindices">
|
|||
|
Opening Secondary Key Indices
|
|||
|
</a>
|
|||
|
</span>
|
|||
|
</dt>
|
|||
|
<dt>
|
|||
|
<span class="sect1">
|
|||
|
<a href="openingforeignkeys.html">
|
|||
|
|
|||
|
<span>More Secondary Key Indices</span>
|
|||
|
</a>
|
|||
|
</span>
|
|||
|
</dt>
|
|||
|
<dt>
|
|||
|
<span class="sect1">
|
|||
|
<a href="indexedcollections.html">
|
|||
|
Creating Indexed Collections
|
|||
|
</a>
|
|||
|
</span>
|
|||
|
</dt>
|
|||
|
<dt>
|
|||
|
<span class="sect1">
|
|||
|
<a href="retrievingbyindexkey.html">
|
|||
|
Retrieving Items by Index Key
|
|||
|
</a>
|
|||
|
</span>
|
|||
|
</dt>
|
|||
|
</dl>
|
|||
|
</div>
|
|||
|
<p>
|
|||
|
In the Basic example, each store has a single <span class="emphasis"><em>primary
|
|||
|
key</em></span>. The Index example extends the Basic example to add the use of
|
|||
|
<span class="emphasis"><em>secondary keys</em></span>.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
The complete source of the final version of the example program
|
|||
|
is included in the Berkeley DB distribution.
|
|||
|
</p>
|
|||
|
<div class="sect1" lang="en" xml:lang="en">
|
|||
|
<div class="titlepage">
|
|||
|
<div>
|
|||
|
<div>
|
|||
|
<h2 class="title" style="clear: both"><a id="opensecondaryindices"></a>
|
|||
|
Opening Secondary Key Indices
|
|||
|
</h2>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<p>
|
|||
|
<span class="emphasis"><em>Secondary indices</em></span> or <span class="emphasis"><em>secondary databases</em></span> are used
|
|||
|
to access a primary database by a key other than the primary key.
|
|||
|
Recall that the Supplier Number field is the primary key of the
|
|||
|
Supplier database. In this section, the Supplier City field will be
|
|||
|
used as a secondary lookup key. Given a city value, we would like
|
|||
|
to be able to find the Suppliers in that city. Note that more than
|
|||
|
one Supplier may be in the same city.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
Both primary and secondary databases contain key-value records.
|
|||
|
The key of an index record is the secondary key, and its value is
|
|||
|
the key of the associated record in the primary database. When lookups by
|
|||
|
secondary key are performed, the associated record in the primary
|
|||
|
database is transparently retrieved by its primary key and returned
|
|||
|
to the caller.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
Secondary indices are maintained automatically when index key
|
|||
|
fields (the City field in this case) are added, modified or removed
|
|||
|
in the records of the primary database. However, the application
|
|||
|
must implement a
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryKeyCreator.html" target="_top">SecondaryKeyCreator</a>
|
|||
|
|
|||
|
that extracts the index key from the database record.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
It is useful to contrast opening an secondary index with opening
|
|||
|
a primary database (as described earlier in
|
|||
|
<a class="xref" href="opendatabases.html" title="Opening and Closing Databases">
|
|||
|
Opening and Closing Databases
|
|||
|
</a>.
|
|||
|
</p>
|
|||
|
<div class="itemizedlist">
|
|||
|
<ul type="disc">
|
|||
|
<li>
|
|||
|
<p>
|
|||
|
A primary database may be associated with one or more secondary
|
|||
|
indices. A secondary index is always associated with exactly one
|
|||
|
primary database.
|
|||
|
</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>
|
|||
|
For a secondary index, a
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryKeyCreator.html" target="_top">SecondaryKeyCreator</a>
|
|||
|
|
|||
|
must be implemented by the application to extract the index key
|
|||
|
from the record of its associated primary database.
|
|||
|
</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>
|
|||
|
A primary database is represented by a
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/Database.html" target="_top">Database</a>
|
|||
|
|
|||
|
object and a secondary index is represented by a
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryDatabase.html" target="_top">SecondaryDatabase</a>
|
|||
|
|
|||
|
object. The
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryDatabase.html" target="_top">SecondaryDatabase</a>
|
|||
|
|
|||
|
class extends the
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/Database.html" target="_top">Database</a>
|
|||
|
|
|||
|
class.
|
|||
|
</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>
|
|||
|
When a
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryDatabase.html" target="_top">SecondaryDatabase</a>
|
|||
|
|
|||
|
is created it is associated with a primary
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/Database.html" target="_top">Database</a>
|
|||
|
|
|||
|
object and a
|
|||
|
|
|||
|
<span>
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryKeyCreator.html" target="_top">SecondaryKeyCreator</a>.
|
|||
|
</span>
|
|||
|
</p>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
</div>
|
|||
|
<p>
|
|||
|
The <code class="classname">SampleDatabase</code> class is extended to open the
|
|||
|
Supplier-by-City secondary key index.
|
|||
|
</p>
|
|||
|
<a id="index_java_sampledatabase"></a>
|
|||
|
<pre class="programlisting"><strong class="userinput"><code>import com.sleepycat.bind.serial.SerialSerialKeyCreator;
|
|||
|
import com.sleepycat.db.SecondaryConfig;
|
|||
|
import com.sleepycat.db.SecondaryDatabase;</code></strong>
|
|||
|
...
|
|||
|
public class SampleDatabase
|
|||
|
{
|
|||
|
...
|
|||
|
<strong class="userinput"><code> private static final String SUPPLIER_CITY_INDEX =
|
|||
|
"supplier_city_index";
|
|||
|
...
|
|||
|
private SecondaryDatabase supplierByCityDb;
|
|||
|
...</code></strong>
|
|||
|
public SampleDatabase(String homeDirectory)
|
|||
|
throws DatabaseException, FileNotFoundException
|
|||
|
{
|
|||
|
...
|
|||
|
<strong class="userinput"><code> SecondaryConfig secConfig = new SecondaryConfig();
|
|||
|
secConfig.setTransactional(true);
|
|||
|
secConfig.setAllowCreate(true);
|
|||
|
secConfig.setType(DatabaseType.BTREE);
|
|||
|
secConfig.setSortedDuplicates(true);
|
|||
|
|
|||
|
secConfig.setKeyCreator(
|
|||
|
new SupplierByCityKeyCreator(javaCatalog,
|
|||
|
SupplierKey.class,
|
|||
|
SupplierData.class,
|
|||
|
String.class));
|
|||
|
|
|||
|
supplierByCityDb = env.openSecondaryDatabase(null,
|
|||
|
SUPPLIER_CITY_INDEX,
|
|||
|
null,
|
|||
|
supplierDb,
|
|||
|
secConfig);</code></strong>
|
|||
|
...
|
|||
|
}
|
|||
|
} </pre>
|
|||
|
<p>
|
|||
|
A
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryConfig.html" target="_top">SecondaryConfig</a>
|
|||
|
|
|||
|
object is used to configure the secondary database. The
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryConfig.html" target="_top">SecondaryConfig</a>
|
|||
|
|
|||
|
class extends the
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/DatabaseConfig.html" target="_top">DatabaseConfig</a>
|
|||
|
|
|||
|
class, and most steps for configuring a secondary database are the
|
|||
|
same as for configuring a primary database. The main difference in
|
|||
|
the example above is that the
|
|||
|
<code class="methodname">SecondaryConfig.setSortedDuplicates()</code> method is called to
|
|||
|
allow duplicate index keys. This is how more than one Supplier may
|
|||
|
be in the same City. If this property is not specified, the default is
|
|||
|
that the index keys of all records must be unique.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
For a primary database, duplicate keys are not normally used
|
|||
|
since a primary database with duplicate keys may not have any
|
|||
|
associated secondary indices. If primary database keys are not
|
|||
|
unique, there is no way for a secondary key to reference a specific
|
|||
|
record in the primary database.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
Note that <code class="methodname">setSortedDuplicates()</code> and not
|
|||
|
<code class="methodname">setUnsortedDuplicates()</code> was called. Sorted
|
|||
|
duplicates are always used for indices rather than unsorted duplicates,
|
|||
|
since sorting enables optimized equality joins.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
Opening a secondary key index requires creating a
|
|||
|
|
|||
|
<span>
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryKeyCreator.html" target="_top">SecondaryKeyCreator</a>.
|
|||
|
</span>
|
|||
|
The <code class="classname">SupplierByCityKeyCreator</code> class implements the
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryKeyCreator.html" target="_top">SecondaryKeyCreator</a>
|
|||
|
|
|||
|
interface and will be defined below.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
The
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryDatabase.html" target="_top">SecondaryDatabase</a>
|
|||
|
|
|||
|
object is opened last. If you compare the
|
|||
|
<code class="methodname">openSecondaryDatabase()</code> and <code class="methodname">openDatabase()</code> methods you'll
|
|||
|
notice only two differences:
|
|||
|
</p>
|
|||
|
<div class="itemizedlist">
|
|||
|
<ul type="disc">
|
|||
|
<li>
|
|||
|
<p>
|
|||
|
<code class="methodname">openSecondaryDatabase()</code> has an extra parameter for
|
|||
|
specifying the associated primary database. The primary database is
|
|||
|
<code class="literal">supplierDb</code> in this case.
|
|||
|
</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>
|
|||
|
The last parameter of <code class="methodname">openSecondaryDatabase()</code> is a
|
|||
|
<code class="literal">SecondaryConfig</code> instead of a <code class="literal">DatabaseConfig</code>.
|
|||
|
</p>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
</div>
|
|||
|
<p>
|
|||
|
How to use the secondary index to access records will be shown
|
|||
|
in a later section.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
The application-defined <code class="classname">SupplierByCityKeyCreator</code> class is
|
|||
|
shown below. It was used above to configure the secondary
|
|||
|
database.
|
|||
|
</p>
|
|||
|
<a id="index_supplierbycitykeycreator"></a>
|
|||
|
<pre class="programlisting">public class SampleDatabase
|
|||
|
{
|
|||
|
...
|
|||
|
<strong class="userinput"><code> private static class SupplierByCityKeyCreator
|
|||
|
extends SerialSerialKeyCreator
|
|||
|
{
|
|||
|
private SupplierByCityKeyCreator(ClassCatalog catalog,
|
|||
|
Class primaryKeyClass,
|
|||
|
Class valueClass,
|
|||
|
Class indexKeyClass)
|
|||
|
{
|
|||
|
super(catalog, primaryKeyClass, valueClass, indexKeyClass);
|
|||
|
}
|
|||
|
|
|||
|
public Object createSecondaryKey(Object primaryKeyInput,
|
|||
|
Object valueInput)
|
|||
|
{
|
|||
|
SupplierData supplierData = (SupplierData) valueInput;
|
|||
|
return supplierData.getCity();
|
|||
|
}
|
|||
|
}</code></strong>
|
|||
|
...
|
|||
|
} </pre>
|
|||
|
<p>
|
|||
|
In general, a key creator class must implement the
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryKeyCreator.html" target="_top">SecondaryKeyCreator</a>
|
|||
|
|
|||
|
interface. This interface has methods that operate on the record
|
|||
|
data as raw bytes. In practice, it is easiest to use an abstract
|
|||
|
base class that performs the conversion of record data to and from
|
|||
|
the format defined for the database's key and value. The base class
|
|||
|
implements the
|
|||
|
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/db/SecondaryKeyCreator.html" target="_top">SecondaryKeyCreator</a>
|
|||
|
|
|||
|
interface and has abstract methods that must be implemented in turn
|
|||
|
by the application.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
In this example the
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/bind/serial/SerialSerialKeyCreator.html" target="_top">SerialSerialKeyCreator</a>
|
|||
|
|
|||
|
base class is used because the database record uses the serial
|
|||
|
format for both its key and its value. The abstract methods of this
|
|||
|
class have key and value parameters of type
|
|||
|
<a class="ulink" href="http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html" target="_top">Object</a>
|
|||
|
|
|||
|
which are automatically converted to and from the raw record data
|
|||
|
by the base class.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
To perform the conversions properly, the key creator must be
|
|||
|
aware of all three formats involved: the key format of the primary
|
|||
|
database record, the value format of the primary database record,
|
|||
|
and the key format of the index record. The
|
|||
|
<a class="ulink" href="../../java/com/sleepycat/bind/serial/SerialSerialKeyCreator.html" target="_top">SerialSerialKeyCreator</a>
|
|||
|
|
|||
|
constructor is given the base classes for these three formats as
|
|||
|
parameters.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
The <code class="methodname">SerialSerialKeyCreator.createSecondaryKey</code> method is
|
|||
|
given the key and value of the primary database record as
|
|||
|
parameters, and it returns the key of the index record. In this
|
|||
|
example, the index key is a field in the primary database record
|
|||
|
value. Since the record value is known to be a <code class="classname">SupplierData</code>
|
|||
|
object, it is cast to that class and the city field is
|
|||
|
returned.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
Note that the <code class="literal">primaryKeyInput</code> parameter is not used in
|
|||
|
the example. This parameter is needed only when an index key is
|
|||
|
derived from the key of the primary database record. Normally an
|
|||
|
index key is derived only from the primary database record value,
|
|||
|
but it may be derived from the key, value or both.
|
|||
|
</p>
|
|||
|
<p>
|
|||
|
The following getter methods return the secondary database
|
|||
|
object for use by other classes in the example program. The
|
|||
|
secondary database object is used to create Java collections for
|
|||
|
accessing records via their secondary keys.
|
|||
|
</p>
|
|||
|
<a id="index_getsupplierbycitydatabase"></a>
|
|||
|
<pre class="programlisting">public class SampleDatabase
|
|||
|
{
|
|||
|
...
|
|||
|
<strong class="userinput"><code> public final SecondaryDatabase getSupplierByCityDatabase()
|
|||
|
{
|
|||
|
return supplierByCityDb;
|
|||
|
}</code></strong>
|
|||
|
...
|
|||
|
} </pre>
|
|||
|
<p>
|
|||
|
The following statement closes the secondary database.
|
|||
|
</p>
|
|||
|
<a id="index_close"></a>
|
|||
|
<pre class="programlisting">public class SampleDatabase
|
|||
|
{
|
|||
|
...
|
|||
|
public void close()
|
|||
|
throws DatabaseException {
|
|||
|
|
|||
|
<strong class="userinput"><code> supplierByCityDb.close();</code></strong>
|
|||
|
partDb.close();
|
|||
|
supplierDb.close();
|
|||
|
shipmentDb.close();
|
|||
|
javaCatalog.close();
|
|||
|
env.close();
|
|||
|
}
|
|||
|
...
|
|||
|
} </pre>
|
|||
|
<p>
|
|||
|
Secondary databases must be closed before closing their
|
|||
|
associated primary database.
|
|||
|
</p>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="navfooter">
|
|||
|
<hr />
|
|||
|
<table width="100%" summary="Navigation footer">
|
|||
|
<tr>
|
|||
|
<td width="40%" align="left"><a accesskey="p" href="handlingexceptions.html">Prev</a> </td>
|
|||
|
<td width="20%" align="center"> </td>
|
|||
|
<td width="40%" align="right"> <a accesskey="n" href="openingforeignkeys.html">Next</a></td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td width="40%" align="left" valign="top">
|
|||
|
Handling Exceptions
|
|||
|
</td>
|
|||
|
<td width="20%" align="center">
|
|||
|
<a accesskey="h" href="index.html">Home</a>
|
|||
|
</td>
|
|||
|
<td width="40%" align="right" valign="top">
|
|||
|
|
|||
|
<span>More Secondary Key Indices</span>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
</table>
|
|||
|
</div>
|
|||
|
</body>
|
|||
|
</html>
|