lucene-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From DM Smith <dmsmith...@gmail.com>
Subject Lucene 1.9 Field implementation
Date Sun, 13 Nov 2005 15:42:33 GMT
I was looking at how compatible 1.9 is with 1.4.3 wrt my implementation.
Turns out it works without problem. There were only three deprecations that
would need to be taken care of to migrate to 2.0.

When I looked into the changes that would need to be made to go to 2.0, I
noticed an opportunity for change. (I could make the changes with
appropriate junit tests, if the following is acceptable.)

In the implementation of Field there are several "type safe enumerations"
such as Store. While the implementation is a good way to constrain
parameters to acceptable values, I think that it could be improved a bit. In
the routines that actually care about what kind of Store was passed there is
a cascading if...then...else, which compares the passed parameter to the
known set of Store objects. For each possible match there is a block of code
that interprets the meaning of that Store. Finally, if there is no match an
exception is thrown in the final else clause.

The problem with this idiom, is that cascading if...then....else are needed
when ever a Store object is used. Further, if another kind of Store were to
be added (say, a jdbc store) then potentially a lot of code would need to be
changed.

Example:

    if (store == Store.YES){
      this.isStored = true;
      this.isCompressed = false;
    }
    else if (store == Store.COMPRESS) {
      this.isStored = true;
      this.isCompressed = true;
    }
    else if (store == Store.NO){
      this.isStored = false;
      this.isCompressed = false;
    }
    else
      throw new IllegalArgumentException("unknown store parameter " + store);



If each Store object were to have behavior, then the usage of Store could be
simplified. So the above code would look like:

    this.isStored = store.isStored();
    this.isCompressed = store.isCompressed();


And if performance and resources are not too much of an issue then rather
than copying out the values, one could use the Store object directly:

    this.store = store;


If there were more behavior that needed to be added to a Store, changes
would be minimized. Rather than locating all the cascading if...then...else
blocks, one would merely add a new Store, new behavior to all Store objects
and only add calls where needed.

The code to the Store class would look something like:
(This change should not *force* any changes elsewhere in 1.9.)

// Note: subclassing Parameter has no real value in this implementation,
//       except perhaps to house a name
// Note: This class could be abstract just as easily.
public static final class Store implements Serializable {

// Note: we are not going to serialize the name
    private transient String name;

    private Store(String name) {
      this.name <http://this.name> = name;
    }

// Note: these could be abstract just as easily.
    public boolean isStored()     { return false; }
    public boolean isCompressed() { return false; }

    /** Store the original field value in the index in a compressed
form. This is
     * useful for long documents and for binary valued fields.
     */
    public static final Store COMPRESS = new Store("COMPRESS")
    {
        public boolean isStored()     { return true;  }
        public boolean isCompressed() { return true;  }
    );

    /** Store the original field value in the index. This is useful
for short texts
     * like a document's title which should be displayed with the results. The
     * value is stored in its original form, i.e. no analyzer is used
before it is
     * stored.
     */
    public static final Store YES = new Store("YES")
    {
        public boolean isStored()     { return true;  }
        public boolean isCompressed() { return false; }
    };

    /** Do not store the field value in the index. */
    public static final Store NO = new Store("NO");
    {
        public boolean isStored()     { return false; }
        public boolean isCompressed() { return false; }
    );

// Note: the serialization in Parameter will not work:
// We have to build the correct object.
// Rather than serializing the whole object, use a number to optimize storage
    // Support for serialization
    private static int nextObj;
    private final int obj = nextObj++;
    private static final Store[] VALUES =
    {
        COMPRESS,
        YES,
        NO,
    };

    Object readResolve()
    {
        return VALUES[obj];
    }

// To deserialize from a config file allow for lookup based on name:
    /**
     * Lookup method to convert from a String
     * @throws ClassCastException if aName is not a valid Store.
     */
    public static Store fromString(String aName)
    {
        for (int i = 0; i < VALUES.length; i++)
        {
            Store store = VALUES[i];
            if (store.name.equalsIgnoreCase(aName))
            {
                return store;
            }
        }

        throw new ClassCastException("unknown Store " + aName);
    }

// Just for the sake of completeness
    /**
     * Prevent subclasses from overriding canonical identity based
Object methods
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public final boolean equals(Object o)
    {
        return super.equals(o);
    }

    /**
     * Prevent subclasses from overriding canonical identity based
Object methods
     * @see java.lang.Object#hashCode()
     */
    public final int hashCode()
    {
        return super.hashCode();
    }

    /**
     * For debugging, the string representation of the Store is its name.
     */
    public final String toString()
    {
        return name;
    }

  }

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message