UsingSecondaries.html   [plain text]


<?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.62.4" />
    <link rel="home" href="index.html" title="Berkeley DB Collections Tutorial" />
    <link rel="up" href="index.html" title="Berkeley DB Collections Tutorial" />
    <link rel="previous" href="handlingexceptions.html" title="&#10;&#9;&#9;Handling Exceptions&#10;&#9;" />
    <link rel="next" href="openingforeignkeys.html" title="&#10;&#9;&#9;&#10;&#9;&#9;More Secondary Key Indices&#10;&#9;" />
  </head>
  <body>
    <div class="navheader">
      <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>
      </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">
		
		More Secondary Key Indices
	</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></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 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 href="opendatabases.html">
		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 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 href="../../java/com/sleepycat/db/Database.html" target="_top">Database</a>
            
            object and a secondary index is represented by a 
            
            <a href="../../java/com/sleepycat/db/SecondaryDatabase.html" target="_top">SecondaryDatabase</a>
            
            object. The 
            
            <a href="../../java/com/sleepycat/db/SecondaryDatabase.html" target="_top">SecondaryDatabase</a>
            
            class extends the 
            
            <a href="../../java/com/sleepycat/db/Database.html" target="_top">Database</a>
            
            class.
        </p>
            </li>
            <li>
              <p>
            When a 
            
            <a href="../../java/com/sleepycat/db/SecondaryDatabase.html" target="_top">SecondaryDatabase</a>
            
            is created it is associated with a primary 
            
            <a href="../../java/com/sleepycat/db/Database.html" target="_top">Database</a>
            
            object and a 
            
            <span>
                <a href="../../java/com/sleepycat/db/SecondaryKeyCreator.html" target="_top">SecondaryKeyCreator</a>.
            </span>
        </p>
            </li>
          </ul>
        </div>
        <p>
    The <tt class="classname">SampleDatabase</tt> class is extended to open the
	Supplier-by-City secondary key index.
</p>
        <a id="index_java_sampledatabase"></a>
        <pre class="programlisting"><b class="userinput"><tt>import com.sleepycat.bind.serial.SerialSerialKeyCreator;
import com.sleepycat.db.SecondaryConfig;
import com.sleepycat.db.SecondaryDatabase;</tt></b>
...
public class SampleDatabase
{
    ...
<b class="userinput"><tt>    private static final String SUPPLIER_CITY_INDEX = "supplier_city_index";
    ...
    private SecondaryDatabase supplierByCityDb;
    ...</tt></b>
    public SampleDatabase(String homeDirectory)
        throws DatabaseException, FileNotFoundException
    {
        ...
<b class="userinput"><tt>        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);</tt></b>
    ...
    }
} </pre>
        <p>
    A 
    
    <a href="../../java/com/sleepycat/db/SecondaryConfig.html" target="_top">SecondaryConfig</a>
    
	object is used to configure the secondary database. The 
    
    <a href="../../java/com/sleepycat/db/SecondaryConfig.html" target="_top">SecondaryConfig</a>
    
	class extends the 
    
    <a 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
	<tt class="methodname">SecondaryConfig.setSortedDuplicates()</tt> 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 <tt class="methodname">setSortedDuplicates()</tt> and not
    <tt class="methodname">setUnsortedDuplicates()</tt> 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 href="../../java/com/sleepycat/db/SecondaryKeyCreator.html" target="_top">SecondaryKeyCreator</a>.
    </span>
	The <tt class="classname">SupplierByCityKeyCreator</tt> class implements the 
    
    <a href="../../java/com/sleepycat/db/SecondaryKeyCreator.html" target="_top">SecondaryKeyCreator</a>
    
	interface and will be defined below.
</p>
        <p>
    The 
    
    <a href="../../java/com/sleepycat/db/SecondaryDatabase.html" target="_top">SecondaryDatabase</a>
    
	object is opened last. If you compare the
	<tt class="methodname">openSecondaryDatabase()</tt> and <tt class="methodname">openDatabase()</tt> methods you'll
	notice only two differences:
</p>
        <div class="itemizedlist">
          <ul type="disc">
            <li>
              <p>
            <tt class="methodname">openSecondaryDatabase()</tt> has an extra parameter for
            specifying the associated primary database. The primary database is
            <tt class="literal">supplierDb</tt> in this case.
        </p>
            </li>
            <li>
              <p>
            The last parameter of <tt class="methodname">openSecondaryDatabase()</tt> is a
            <tt class="literal">SecondaryConfig</tt> instead of a <tt class="literal">DatabaseConfig</tt>.
        </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 <tt class="classname">SupplierByCityKeyCreator</tt> 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
{
...
<b class="userinput"><tt>    private static class SupplierByCityKeyCreator
        extends SerialSerialKeyCreator
    {
        private SupplierByCityKeyCreator(StoredClassCatalog 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();
        }
    }</tt></b>
...
} </pre>
        <p>
    In general, a key creator class must implement the 
    
    <a 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 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 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 href="http://java.sun.com/j2se/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 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 <tt class="methodname">SerialSerialKeyCreator.createSecondaryKey</tt> 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 <tt class="classname">SupplierData</tt>
	object, it is cast to that class and the city field is
	returned.
</p>
        <p>
    Note that the <tt class="literal">primaryKeyInput</tt> 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
{
    ...
<b class="userinput"><tt>    public final SecondaryDatabase getSupplierByCityDatabase()
    {
        return supplierByCityDb;
    }</tt></b>
    ...
} </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 {

<b class="userinput"><tt>        supplierByCityDb.close();</tt></b>
        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">
            <a accesskey="u" href="index.html">Up</a>
          </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"> 
		
		More Secondary Key Indices
	</td>
        </tr>
      </table>
    </div>
  </body>
</html>