Using Comparators

Writing Comparators
Setting Comparators

Internally, JE databases are organized as BTrees. This means that most database operations (inserts, deletes, reads, and so forth) involve BTree node comparisons. This comparison most frequently occurs based on database keys, but if your database supports duplicate records then comparisons can also occur based on the database data.

By default, JE performs all such comparisons using a byte-by-byte lexicographic comparison. This mechanism works well for most data. However, in some cases you may need to specify your own comparison routine. One frequent reason for this is to perform a language sensitive lexical ordering of string keys.

Writing Comparators

You override the default comparison function by providing a Java Comparator class to the database. The Java Comparator interface requires you to implement the Comparator.compare() method (see http://java.sun.com/j2se/1.4.2/docs/api/java/util/Comparator.html for details).

JE passes your Comparator.compare() method the byte arrays that you stored in the database. If you know how your data is organized in the byte array, then you can write a comparison routine that directly examines the contents of the arrays. Otherwise, you have to reconstruct your original objects, and then perform the comparison.

For example, suppose you want to perform unicode lexical comparisons instead of UTF-8 byte-by-byte comparisons. Then you could provide a comparator that uses String.compareTo(), which performs a Unicode comparison of two strings (note that for single-byte roman characters, Unicode comparison and UTF-8 byte-by-byte comparisons are identical – this is something you would only want to do if you were using multibyte unicode characters with JE). In this case, your comparator would look like the following:

package je.gettingStarted;

import java.util.Comparator;

public class MyDataComparator implements Comparator {

    public MyDataComparator() {}

    public int compare(Object d1, Object d2) {

        byte[] b1 = (byte[])d1;
        byte[] b2 = (byte[])d2;

        String s1 = new String(b1, "UTF-8");
        String s2 = new String(b2, "UTF-8");
        return s1.compareTo(s2);
    }
} 

Setting Comparators

You specify a Comparator using the following methods. Note that by default these methods can only be used at database creation time, and they are ignored for normal database opens. Also, note that JE uses the no-argument constructor for these comparators. Further, it is not allowable for there to be a mutable state in these comparators or else unpredictable results will occur.

  • DatabaseConfig.setBtreeComparator()

    Sets the Java Comparator class used to compare two keys in the database.

  • DatabaseConfig.setDuplicateComparator()

    Sets the Java Comparator class used to compare the data on two duplicate records in the database. This comparator is used only if the database supports duplicate records.

You can use the above methods to set a database's comparator after database creation time if you explicitly indicate that the comparator is to be overridden. You do this by using the following methods:

Note

If you override your comparator, the new comparator must preserve the sort order implemented by your original comparator. That is, the new comparator and the old comparator must return the same value for the comparison of any two valid objects. Failure to observe this constraint will cause unpredictable results for your application.

If you want to change the fundamental sort order for your database, back up the contents of the database, delete the database, recreate it, and then reload its data.

  • DatabaseConfig.setOverrideBtreeComparator()

    If set to true, causes the database's Btree comparator to be overridden with the Comparator specified on DatabaseConfig.setBtreeComparator(). This method can be used to change the comparator post-environment creation.

  • DatabaseConfig.setOverrideDuplicateComparator()

    If set to true, causes the database's duplicates comparator to be overridden with the Comparator specified on DatabaseConfig.setDuplicateComparator().

For example, to use the Comparator described in the previous section:

package je.gettingStarted;

import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseException;

import java.util.Comparator;    

...


// Environment open omitted for brevity

try {
    // Get the database configuration object
    DatabaseConfig myDbConfig = new DatabaseConfig();
    myDbConfig.setAllowCreate(true);

    // Set the duplicate comparator class
    myDbConfig.setDuplicateComparator(MyDataComparator.class);

    // Open the database that you will use to store your data
    myDbConfig.setSortedDuplicates(true);
    Database myDatabase = myDbEnv.openDatabase(null, "myDb", myDbConfig); 
} catch (DatabaseException dbe) {
    // Exception handling goes here
}