Revision: 16676
          http://sourceforge.net/p/gate/code/16676
Author:   valyt
Date:     2013-05-03 15:13:55 +0000 (Fri, 03 May 2013)
Log Message:
-----------
First attempt at speeding up indexing of very large mention sets.

Background: when indexing annotations that have non-nominal features with very 
large ranges (e.g. URIs from a large knowledge base) the indexing slows down 
rapidly, presumably due to many cache misses.

Implemented solution:
- changed the caching implementation to use 3 completely independent caches for 
Level 1 IDs, Level 2 IDs, and mention IDs. This allows the single Level 2 cache 
to be significantly larger than each of the many Level 2 caches previously used.
- increased the default cache size for Level 2 to 10240.
- increased Level 3 (mention IDs) cache size to 1024*1024.
- added a public method that allows setting the size of the caches from inside 
the index template.

Other notes:
- removed the dynamic cache re-sizing, as it turned out to be ineffectual.
- changed the helper implementation to get the ID for newly inserted rows 
directly from the insert prepared statement (instead of re-running the select 
statement).
- changed the way we deal with cache misses: we now supply callables that 
retrieve the ID from the DB (or generate a new one by inserting a new row).

Modified Paths:
--------------
    mimir/trunk/plugins/db-h2/src/gate/mimir/db/AnnotationTemplateCache.java
    mimir/trunk/plugins/db-h2/src/gate/mimir/db/DBSemanticAnnotationHelper.java

Modified: 
mimir/trunk/plugins/db-h2/src/gate/mimir/db/AnnotationTemplateCache.java
===================================================================
--- mimir/trunk/plugins/db-h2/src/gate/mimir/db/AnnotationTemplateCache.java    
2013-05-03 09:41:57 UTC (rev 16675)
+++ mimir/trunk/plugins/db-h2/src/gate/mimir/db/AnnotationTemplateCache.java    
2013-05-03 15:13:55 UTC (rev 16676)
@@ -14,7 +14,6 @@
  */
 package gate.mimir.db;
 
-import gate.Annotation;
 import gate.FeatureMap;
 import gate.mimir.AbstractSemanticAnnotationHelper;
 import it.unimi.dsi.fastutil.objects.Object2ShortMap;
@@ -24,51 +23,15 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.concurrent.Callable;
 
-import org.apache.log4j.Logger;
-
 public class AnnotationTemplateCache {
-  /**
-   * Interface for the types of values returned by this cache. All Tags have a
-   * long ID (if the value is -1, then the ID is not yet set). They may also
-   * hold some other data used internally by the cache.
-   */
-  public static interface Tag {
-    /**
-     * Value for a Tag's ID when no ID as been set yet.
-     */
-    public static final long NO_ID = -1;
 
-    /**
-     * Value for a Tag's ID when no ID exists (i.e. an alternative 
-     * representation for when the Tag value should be null).
-     */
-    public static final long NULL_ID = -2;
-    
-    /**
-     * Gets the ID associated with this tag. If the values returned is -1, then
-     * the has no ID.
-     * 
-     * @return
-     */
-    long getId();
-
-    /**
-     * Sets the ID that this tag should have. When a cache miss occurs, a new
-     * tag is created and returned. Such a tag has no ID (the id value is
-     * {@link #NO_ID}). Client code can then set the ID to whatever desired
-     * value.
-     * 
-     * @param newId
-     */
-    void setId(long newId);
-  }
-
   /**
    * The key that goes into the level 1 cache map.
    */
-  protected class NominalFeatures {
-    public NominalFeatures(FeatureMap annFeats) {
+  protected class Level1Key {
+    public Level1Key(FeatureMap annFeats) {
       // nominalValues is guaranteed to be non-null and to have the same size
       // as owner.getNominalFeatureNames() (i.e. 0, if no nominal features)
       features = new short[nominalvalues.length];
@@ -92,7 +55,7 @@
 
     @Override
     public boolean equals(Object obj) {
-      return Arrays.equals(features, ((NominalFeatures)obj).features);
+      return Arrays.equals(features, ((Level1Key)obj).features);
     }
 
     private short[] features;
@@ -108,8 +71,9 @@
   /**
    * The type of keys that go into the level2 cache.
    */
-  protected class NonNominalFeatures {
-    public NonNominalFeatures(FeatureMap annFeats) {
+  protected class Level2Key {
+    public Level2Key(long level1id, FeatureMap annFeats) {
+      this.level1id = level1id;
       int length = 0;
       if(owner.getIntegerFeatures() != null)
         length += owner.getIntegerFeatures().length;
@@ -119,7 +83,7 @@
         length += owner.getTextFeatures().length;
       if(owner.getUriFeatures() != null)
         length += owner.getUriFeatures().length;
-      values = new Object[length];
+      values = new Object[length + 1];
       int i = 0;
       if(owner.getIntegerFeatures() != null) {
         for(String aFeature : owner.getIntegerFeatures()) {
@@ -141,12 +105,15 @@
           values[i++] = annFeats.get(aFeature);
         }
       }
+      values[i] = level1id;
       // cache the hash code.
       hashcode = Arrays.hashCode(values);
     }
 
-    Object[] values;
+    private Object[] values;
 
+    long level1id;
+    
     @Override
     public int hashCode() {
       return hashcode;
@@ -154,66 +121,19 @@
 
     @Override
     public boolean equals(Object obj) {
-      return Arrays.equals(values, ((NonNominalFeatures)obj).values);
+      return Arrays.equals(values, ((Level2Key)obj).values);
     }
 
     int hashcode;
   }
 
   /**
-   * Type of values that go in the the Level1 cache
-   */
-  protected class Level2Cache implements Tag {
-    public Level2Cache() {
-      this.id = NO_ID;
-      level2Cache = new LinkedHashMap<NonNominalFeatures, LongTag>() {
-        @Override
-        protected boolean removeEldestEntry(
-                Entry<NonNominalFeatures, LongTag> eldest) {
-          return size() > l2CacheSize;
-        }
-      };
-    }
-
-    long id;
-
-    Map<NonNominalFeatures, LongTag> level2Cache;
-
-    public long getId() {
-      return id;
-    }
-
-    public void setId(long newId) {
-      this.id = newId;
-    }
-  }
-
-  /**
-   * Type for value going in the level 2 cache (a simple wrapper for a long).
-   */
-  protected static class LongTag implements Tag {
-    public LongTag() {
-      this.id = NO_ID;
-    }
-
-    public long getId() {
-      return id;
-    }
-
-    public void setId(long newId) {
-      this.id = newId;
-    }
-
-    long id;
-  }
-
-  /**
    * Type for keys going in the level 3 cache
    */
-  protected class MentionKey {
-    public MentionKey(long l1Id, long l2id, int mentionLength) {
-      this.level1Id = l1Id;
-      this.level2Id = l2id;
+  protected class Level3Key {
+    public Level3Key(long level1Id, long level2Id, int mentionLength) {
+      this.level1Id = level1Id;
+      this.level2Id = level2Id;
       this.mentionLength = mentionLength;
       this.hashcode = Arrays.hashCode(new long[]{level1Id, level2Id, 
mentionLength});
     }
@@ -225,7 +145,7 @@
 
     @Override
     public boolean equals(Object obj) {
-      MentionKey other = (MentionKey)obj;
+      Level3Key other = (Level3Key)obj;
       return other != null && 
              level1Id == other.level1Id && 
              level2Id == other.level2Id && 
@@ -241,18 +161,23 @@
     int hashcode;
   }
 
+  /**
+   * Value for a Tag's ID when no ID as been set yet.
+   */
+  public static final long NO_ID = -1;
+  
+  /**
+   * Value for a Tag's ID when no ID exists (i.e. an alternative 
+   * representation for when the Tag value should be null).
+   */
+  public static final long NULL_ID = -2;
+  
   private static final int DEFAULT_L1_SIZE = 512;
 
-  private static final int DEFAULT_L2_SIZE = 64;
+  private static final int DEFAULT_L2_SIZE = 10240;
 
-  private static Logger logger = Logger
-          .getLogger(AnnotationTemplateCache.class);
+  private static final int DEFAULT_L3_SIZE = 1024 * 1024;
 
-  /**
-   * There is only one L3 cache, so we can have it quite large.
-   */
-  private static final int DEFAULT_L3_SIZE = 100000;
-
   private static final short NULL = -1;
 
   public AnnotationTemplateCache(AbstractSemanticAnnotationHelper owner) {
@@ -268,20 +193,35 @@
       nominalvalues[i] = new Object2ShortOpenHashMap<String>();
       nominalvalues[i].defaultReturnValue(NULL);
     }
-    level1Cache =
-            new LinkedHashMap<AnnotationTemplateCache.NominalFeatures, 
AnnotationTemplateCache.Level2Cache>() {
-              @Override
-              protected boolean removeEldestEntry(
-                      Entry<NominalFeatures, Level2Cache> eldest) {
-                return size() > l1CacheSize;
-              }
-            };
-    level3Cache = new LinkedHashMap<AnnotationTemplateCache.MentionKey, Tag>() 
{
+    level1Cache = new LinkedHashMap<Level1Key, Long> (){
+      private static final long serialVersionUID = -7450031094311786000L;
+
       @Override
-      protected boolean removeEldestEntry(Entry<MentionKey, Tag> eldest) {
+      protected boolean removeEldestEntry(
+              Entry<Level1Key, Long> eldest) {
+        return size() > l1CacheSize;
+      }
+    };
+            
+    level2Cache = new LinkedHashMap<Level2Key, Long> (){
+      private static final long serialVersionUID = -4387458661647300503L;
+
+      @Override
+      protected boolean removeEldestEntry(
+              Entry<Level2Key, Long> eldest) {
+        return size() > l2CacheSize;
+      }
+    };
+    
+    level3Cache = new LinkedHashMap<Level3Key, Long>() {
+      private static final long serialVersionUID = -1341690439603138038L;
+
+      @Override
+      protected boolean removeEldestEntry(Entry<Level3Key, Long> eldest) {
         return size() > l3CacheSize;
       }
     };
+    
     l1CacheHits = 0;
     l1CacheMisses = 0;
     l2CacheHits = 0;
@@ -290,9 +230,11 @@
     l3CacheMisses = 0;
   }
 
-  protected Map<NominalFeatures, Level2Cache> level1Cache;
+  protected Map<Level1Key, Long> level1Cache;
+  
+  protected Map<Level2Key, Long> level2Cache;
 
-  protected Map<MentionKey, Tag> level3Cache;
+  protected Map<Level3Key, Long> level3Cache;
 
   /**
    * The helper using this cache.
@@ -323,42 +265,42 @@
   private long l3CacheHits;
 
   private long l3CacheMisses;
-
+  
   /**
-   * Given an annotation, obtain the associated Level-1 {@link Tag}, from which
-   * the ID can be retrieved. If a cache miss occurs, the returned tag will 
have
-   * an ID value of {@link #NO_ID} - it is the responsibility of the client 
code
-   * to obtain the correct ID and set it on the tag.
+   * Given an annotation, obtain the associated Level-1 ID. If a cache miss 
+   * occurs, the provided callable will be called to obtain a new ID, which 
will
+   * then be stored in the cache, and returned.
+   * @throws Exception if the provided callable generates an exception. 
    */
-  public Tag getLevel1Tag(FeatureMap annFeats) {
+  public long getLevel1Id(FeatureMap annFeats, Callable<Long> idGenerator) 
throws Exception {
     // build the nominal features value
-    NominalFeatures nomFeats = new NominalFeatures(annFeats);
-    Level2Cache l1tag = level1Cache.get(nomFeats);
-    if(l1tag == null) {
+    Level1Key l1key = new Level1Key(annFeats);
+    Long l1Id = level1Cache.get(l1key);
+    if(l1Id == null) {
       l1CacheMisses++;
-      l1tag = new Level2Cache();
-      level1Cache.put(nomFeats, l1tag);
+      l1Id = idGenerator.call();
+      level1Cache.put(l1key, l1Id);
     } else {
       l1CacheHits++;
     }
-    return l1tag;
+    return l1Id;
   }
-
+  
   /**
-   * Given an annotation and the level-1 Tag obtained previously, obtain the
-   * associated level-2 {@link Tag}, from which the ID can be retrieved. If a
-   * cache miss occurs, the returned tag will have an ID value of {@link 
#NO_ID}
-   * - it is the responsibility of the client code to obtain the correct ID and
-   * set it on the tag.
+   * Given an annotation and the level-1 ID obtained previously, obtain the
+   * associated level-2 ID. If a cache miss occurs, the provided callable will
+   * be used to generate a new ID, which is then stored in the cache and 
+   * returned. 
+   * @throws Exception if the provided callable generates an exception. 
    */
-  public Tag getLevel2Tag(FeatureMap annFeats, Tag level1Tag) {
-    Level2Cache l1Value = (Level2Cache)level1Tag;
-    NonNominalFeatures nonNonFeats = new NonNominalFeatures(annFeats);
-    LongTag level2Tag = (LongTag)l1Value.level2Cache.get(nonNonFeats);
+  public Long getLevel2Id(Long level1Tag, FeatureMap annFeats, 
+                          Callable<Long> idGenerator) throws Exception {
+    Level2Key nonNonFeats = new Level2Key(level1Tag, annFeats);
+    Long level2Tag = level2Cache.get(nonNonFeats);
     if(level2Tag == null) {
       l2CacheMisses++;
-      level2Tag = new LongTag();
-      l1Value.level2Cache.put(nonNonFeats, level2Tag);
+      level2Tag = idGenerator.call();
+      level2Cache.put(nonNonFeats, level2Tag);
     } else {
       l2CacheHits++;
     }
@@ -366,21 +308,21 @@
   }
 
   /**
-   * Given a Level-1 or Level-2 tag, and a mention length, obtain the Level-3
-   * tag associated with the desired mention (the ID of the mention can be
-   * obtained from the returned tag). If a cache miss occurs, the returned tag
-   * will have an ID value of {@link #NO_ID} - it is the responsibility of the
-   * client code to obtain the correct ID and set it on the tag.
+   * Given a Level-1, (optionally) a Level-2 ID, and a mention length, obtain 
+   * the Level-3 ID associated with the desired mention. If a cache miss 
occurs,
+   * the provided callable will be used to generate a new ID, which is then 
+   * stored in the cache and returned.
+   *  
+   * @throws Exception if the provided callable generates an exception. 
    */
-  public Tag getLevel3Tag(Tag level1tag, Tag level2tag, int length) {
-    MentionKey key = new MentionKey(
-        level1tag == null ? Tag.NULL_ID : level1tag.getId(),
-        level2tag == null ? Tag.NULL_ID : level2tag.getId(),
-        length);
-    LongTag l3Tag = (LongTag)level3Cache.get(key);
+  public Long getLevel3Id(Long level1tag, Long level2tag, int length, 
+                          Callable<Long> idGenerator) throws Exception {
+    Level3Key key = new Level3Key(
+        level1tag, (level2tag == null ? NULL_ID : level2tag), length);
+    Long l3Tag = level3Cache.get(key);
     if(l3Tag == null) {
       l3CacheMisses++;
-      l3Tag = new LongTag();
+      l3Tag = idGenerator.call();
       level3Cache.put(key, l3Tag);
     } else {
       l3CacheHits++;
@@ -389,34 +331,6 @@
   }
 
   /**
-   * Optimises the sizes used for level 1 and level 2 caches.
-   */
-  protected void adjustCacheSizes() {
-    double l1hit = getL1CacheHitRatio();
-    double l2hit = getL2CacheHitRatio();
-    if(l1hit - l2hit > 0.2) {
-      // L1 better than L2, by more than 20% -> increase L2
-      if(l1CacheSize >= (level1Cache.size() * 2)) {
-        // L1 at less than 50% capacity
-        l1CacheSize = l1CacheSize / 2;
-        l2CacheSize = l2CacheSize * 2;
-        logger.info("Decreasing L1 cache size to " + l1CacheSize
-                + "; Increasing L2 cache size to " + l2CacheSize + ".");
-      }
-    } else if(l2hit - l1hit > 0.2) {
-      // L2 better than L1, by more than 20% -> increase L1
-      if((l1CacheSize * 2) > level1Cache.size()) {
-        l1CacheSize = l1CacheSize * 2;
-        l2CacheSize = l2CacheSize / 2;
-        logger.info("Increasing L1 cache size to " + l1CacheSize
-                + "; Decreasing L2 cache size to " + l2CacheSize + ".");
-      }
-    } else {
-      // nothing to adjust
-    }
-  }
-
-  /**
    * Returns the current size of the Level1 cache.
    * 
    * @return an int value.
@@ -487,4 +401,47 @@
       return (double)l3CacheHits / (l3CacheHits + l3CacheMisses);
     }
   }
+
+  /**
+   * @return the l1CacheSize
+   */
+  public int getL1CacheSize() {
+    return l1CacheSize;
+  }
+
+  /**
+   * @param l1CacheSize the l1CacheSize to set
+   */
+  public void setL1CacheSize(int l1CacheSize) {
+    this.l1CacheSize = l1CacheSize > 0 ? l1CacheSize : DEFAULT_L1_SIZE;
+  }
+
+  /**
+   * @return the l2CacheSize
+   */
+  public int getL2CacheSize() {
+    return l2CacheSize;
+  }
+
+  /**
+   * @param l2CacheSize the l2CacheSize to set
+   */
+  public void setL2CacheSize(int l2CacheSize) {
+    this.l2CacheSize = l2CacheSize > 0 ? l2CacheSize : DEFAULT_L2_SIZE;
+  }
+
+  /**
+   * @return the l3CacheSize
+   */
+  public int getL3CacheSize() {
+    return l3CacheSize;
+  }
+
+  /**
+   * @param l3CacheSize the l3CacheSize to set
+   */
+  public void setL3CacheSize(int l3CacheSize) {
+    this.l3CacheSize = l3CacheSize > 0 ? l3CacheSize : DEFAULT_L3_SIZE;
+  }
+  
 }

Modified: 
mimir/trunk/plugins/db-h2/src/gate/mimir/db/DBSemanticAnnotationHelper.java
===================================================================
--- mimir/trunk/plugins/db-h2/src/gate/mimir/db/DBSemanticAnnotationHelper.java 
2013-05-03 09:41:57 UTC (rev 16675)
+++ mimir/trunk/plugins/db-h2/src/gate/mimir/db/DBSemanticAnnotationHelper.java 
2013-05-03 15:13:55 UTC (rev 16676)
@@ -14,7 +14,6 @@
  */
 package gate.mimir.db;
 
-import static gate.mimir.db.AnnotationTemplateCache.Tag.NO_ID;
 import gate.Annotation;
 import gate.Document;
 import gate.FeatureMap;
@@ -23,7 +22,6 @@
 import gate.mimir.ConstraintType;
 import gate.mimir.IndexConfig;
 import gate.mimir.SemanticAnnotationHelper;
-import gate.mimir.db.AnnotationTemplateCache.Tag;
 import gate.mimir.index.Indexer;
 import gate.mimir.index.Mention;
 import gate.mimir.search.QueryEngine;
@@ -43,6 +41,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Callable;
 
 import org.apache.log4j.Logger;
 
@@ -52,6 +51,183 @@
  */
 public class DBSemanticAnnotationHelper extends 
AbstractSemanticAnnotationHelper{
 
+  /**
+   * A callable that generates Level 1 IDs given a set of features.
+   */
+  protected class Level1IdGenerator implements Callable<Long> {
+    
+    public Level1IdGenerator(FeatureMap features) {
+      this.features = features;
+    }
+
+    protected FeatureMap features;
+    
+    /**
+     * Retrieves the level1 ID for the given set of features. If no ID can be 
+     * found (i.e. this combination of features has not been seen before), it 
+     * inserts a new row in the level 1 table, and returns the ID for it.  
+     * @see java.util.concurrent.Callable#call()
+     */
+    @Override
+    public Long call() throws Exception {
+      setStatementParameters(level1SelectStmt, features);
+      ResultSet res = level1SelectStmt.executeQuery();
+      if(!res.next()) {
+        // no results found -> insert the new row
+        setStatementParameters(level1InsertStmt, features);
+        if(level1InsertStmt.executeUpdate() != 1) {
+          // the update failed
+          throw new RuntimeException("Error while inserting into database. 
Annotation was lost!");
+        }
+        res = level1InsertStmt.getGeneratedKeys();
+        if(!res.next()) throw new RuntimeException(
+          "Could not insert new Level 1 row for features: " + features);
+      }
+      
+      // we have found the level 1 ID
+      Long level1id = res.getLong(1);
+      // sanity check
+      if(res.next()) throw new RuntimeException(
+              "Multiple Unique IDs foud in Level 1 table for features: " + 
+              features.toString());      
+      return level1id;
+    }
+  }
+  
+  /**
+   * A callable that generates Level 2 IDs given a set of features.
+   */
+  protected class Level2IdGenerator implements Callable<Long> {
+    
+    private Long level1Id;
+    
+    public Level2IdGenerator(Long level1Id, FeatureMap features) {
+      this.level1Id = level1Id;
+      this.features = features;
+    }
+
+    protected FeatureMap features;
+    
+    /**
+     * Retrieves the level2 ID for the given set of features. If no ID can be 
+     * found (i.e. this combination of features has not been seen before), it 
+     * inserts a new row in the level 2 table, and returns the ID for it.  
+     * @see java.util.concurrent.Callable#call()
+     */
+    @Override
+    public Long call() throws Exception {
+      level2SelectStmt.setLong(1, level1Id);
+      setStatementParameters(level2SelectStmt, features);
+      ResultSet res = level2SelectStmt.executeQuery();
+      if(!res.next()) {
+        // no results -> insert new row
+        level2InsertStmt.setLong(1, level1Id);
+        setStatementParameters(level2InsertStmt, features);
+        if(level2InsertStmt.executeUpdate() != 1) {
+          // the update failed
+          throw new RuntimeException(
+            "Could not insert new Level 2 row for Level 1 ID: \"" + level1Id + 
+            "\" and features: " + features);
+        }
+        res = level2InsertStmt.getGeneratedKeys();
+        if(!res.next()) throw new RuntimeException(
+          "Could not insert new Level 2 row for Level 1 ID: \"" + level1Id + 
+          "\" and features: " + features);
+      }
+      
+      // we have found the level 2 ID
+      Long level2Id = res.getLong(1);
+      // sanity check
+      if(res.next()) {
+        throw new RuntimeException(
+          "Multiple Unique IDs found in Level 2 table for  Level 1 ID: \"" + 
+          level1Id + "\" and features: " + features);
+      }
+      return level2Id;
+    }
+  }
+  
+  /**
+   * A callable that generates Level 3 IDs (i.e. mention IDs) given a Level 1 
+   * ID and/or a Level 2 ID, and a mention length.
+   */
+  protected class Level3IdGenerator implements Callable<Long> {
+
+    private Long level1Id;
+    
+    private Long level2Id;
+    
+    private int mentionLength;
+    
+    public Level3IdGenerator(Long level1Id, Long level2Id, int mentionLength) {
+      super();
+      this.level1Id = level1Id;
+      this.level2Id = level2Id;
+      this.mentionLength = mentionLength;
+    }
+
+
+    /* (non-Javadoc)
+     * @see java.util.concurrent.Callable#call()
+     */
+    @Override
+    public Long call() throws Exception {
+      mentionsSelectStmt.setLong(1, level1Id);
+      if(level2Used) {
+        if(level2Id != null) {
+          mentionsSelectStmt.setLong(2, level1Id);  
+        } else {
+          mentionsSelectStmt.setNull(2, Types.BIGINT);
+        }
+        mentionsSelectStmt.setInt(3, mentionLength);        
+      } else {
+        mentionsSelectStmt.setInt(2, mentionLength);
+      }
+
+      ResultSet res = mentionsSelectStmt.executeQuery(); 
+      if(!res.next()) {
+        // no results -> insert new row
+        mentionsInsertStmt.setLong(1, level1Id);
+        if(level2Used) {
+          if(level2Id != null) {
+            mentionsInsertStmt.setLong(2, level2Id);  
+          } else {
+            mentionsInsertStmt.setNull(2, Types.BIGINT);
+          } 
+          mentionsInsertStmt.setInt(3, mentionLength);          
+        } else {
+          mentionsInsertStmt.setInt(2, mentionLength);          
+        }
+
+        if(mentionsInsertStmt.executeUpdate() != 1) {
+          // the update failed
+          throw new RuntimeException(
+            "Could not insert new mention ID for Level 1 ID: " + level1Id + 
+            ", Level 2 ID: " + level2Id + ", and mention length: " + 
+            mentionLength);
+        }
+        res = mentionsInsertStmt.getGeneratedKeys();
+        if(!res.next()) {
+          throw new RuntimeException(
+            "Could not insert new mention ID for Level 1 ID: " + level1Id + 
+            ", Level 2 ID: " + level2Id + ", and mention length: " + 
+            mentionLength);
+        }
+      }
+      
+      // we have found the level 3 (mention) ID
+      Long mentionId = res.getLong(1);
+      // sanity check
+      if(res.next()){ 
+        throw new RuntimeException(
+            "Multiple Unique IDs foud in mentions table for  Level 1 ID: " + 
+             level1Id +  ", Level 2 ID: " + level2Id + 
+             ", and mention length: " + mentionLength);
+      }
+      return mentionId;
+    }
+  }
+  
   private static final long serialVersionUID = 2734946594117068194L;
 
   /**
@@ -574,133 +750,34 @@
     
     try {
       // find the level 1 ID
-      Tag level1Tag = cache.getLevel1Tag(featuresToIndex);
-      while(level1Tag.getId() == NO_ID){
-        setStatementParameters(level1SelectStmt, featuresToIndex);
-        ResultSet res = level1SelectStmt.executeQuery();
-        if(res.next()) {
-          // we have found the level 1 ID
-          level1Tag.setId(res.getLong(1));
-          // sanity check
-          if(res.next()) throw new RuntimeException(
-                  "Multiple Unique IDs foud in level 1 table for annotation " 
+ 
-                  ann.toString());
-        } else {
-          // insert the new row
-          setStatementParameters(level1InsertStmt, featuresToIndex);
-          if(level1InsertStmt.executeUpdate() != 1) {
-            // the update failed
-            logger.error("Error while inserting into database. Annotation was 
lost!");
-            return new String[]{};
-          }
-          dbConnection.commit();
-        }
-      }
+      Long level1Tag = cache.getLevel1Id(featuresToIndex, 
+          new Level1IdGenerator(featuresToIndex));
       
       // find the Level-1 Mention ID (ignoring the L2 values)
-      Tag mentionL1Tag = cache.getLevel3Tag(level1Tag, null, length);
-      Tag mentionL2Tag = null;
-      while(mentionL1Tag.getId() == NO_ID){
-        mentionsSelectStmt.setLong(1, level1Tag.getId());
-        if(level2Used) {
-          mentionsSelectStmt.setNull(2, Types.BIGINT);
-          mentionsSelectStmt.setInt(3,length);
-        } else {
-          mentionsSelectStmt.setInt(2,length);
-        }
-        ResultSet res = mentionsSelectStmt.executeQuery(); 
-        if(res.next()) {
-          // we have found the level 2 ID
-          mentionL1Tag.setId(res.getLong(1));
-          // sanity check
-          if(res.next()) throw new RuntimeException(
-                  "Multiple Unique IDs foud in mentions table for annotation " 
+ 
-                  "(of length "+ length + "):\n" +ann.toString());
-        } else {
-          // insert the new row
-          mentionsInsertStmt.setLong(1, level1Tag.getId());
-          if(level2Used) {
-            mentionsInsertStmt.setNull(2, Types.BIGINT);
-            mentionsInsertStmt.setInt(3,length);
-          } else {
-            mentionsInsertStmt.setInt(2,length);
-          }   
-          if(mentionsInsertStmt.executeUpdate() != 1) {
-            // the update failed
-            logger.error("Error while inserting into database. Annotation was 
lost!");
-            return new String[]{};
-          }
-          dbConnection.commit();
-        }
-      }
+      Long mentionL1Tag = cache.getLevel3Id(level1Tag, null, length, 
+          new Level3IdGenerator(level1Tag, null, length));
       
+      Long mentionL2Tag = null;
       if(level2Used){
         // find the level 2 ID
-        Tag level2Tag = cache.getLevel2Tag(featuresToIndex, level1Tag);
-        while(level2Tag.getId() == NO_ID){
-          level2SelectStmt.setLong(1, level1Tag.getId());
-          setStatementParameters(level2SelectStmt, featuresToIndex);
-
-          ResultSet res = level2SelectStmt.executeQuery();
-          if(res.next()) {
-            // we have found the level 2 ID
-            level2Tag.setId(res.getLong(1));
-            // sanity check
-            if(res.next()) throw new RuntimeException(
-                    "Multiple Unique IDs found in level 2 table for annotation 
" + 
-                    ann.toString());
-          } else {
-            // insert the new row
-            level2InsertStmt.setLong(1, level1Tag.getId());
-            setStatementParameters(level2InsertStmt, featuresToIndex);
-            if(level2InsertStmt.executeUpdate() != 1) {
-              // the update failed
-              logger.error("Error while inserting into database. Annotation 
was lost!");
-              return new String[]{};
-            }
-            dbConnection.commit();
-          }
-        }
+        Long level2Tag = cache.getLevel2Id(level1Tag, featuresToIndex, 
+            new Level2IdGenerator(level1Tag, featuresToIndex));
+        
         // find the Level-2 Mention ID
-        mentionL2Tag = cache.getLevel3Tag(level1Tag, level2Tag, length);
-        while(mentionL2Tag.getId() == NO_ID){
-          mentionsSelectStmt.setLong(1,level1Tag.getId());
-          mentionsSelectStmt.setLong(2, level2Tag.getId());
-          mentionsSelectStmt.setInt(3,length);
-
-          ResultSet res = mentionsSelectStmt.executeQuery();
-          if(res.next()) {
-            // we have found the level 2 ID
-            mentionL2Tag.setId(res.getLong(1));
-            // sanity check
-            if(res.next()) throw new RuntimeException(
-                    "Multiple Unique IDs foud in mentions table for annotation 
" + 
-                    "(of length "+ length + "):\n" +ann.toString());
-          } else {
-            // insert the new row
-            mentionsInsertStmt.setLong(1, level1Tag.getId());
-            mentionsInsertStmt.setLong(2, level2Tag.getId());
-            mentionsInsertStmt.setInt(3,length);
-            if(mentionsInsertStmt.executeUpdate() != 1) {
-              // the update failed
-              logger.error("Error while inserting into database. Annotation 
was lost!");
-              return new String[]{};
-            }
-            dbConnection.commit();
-          }
-        }
+        mentionL2Tag = cache.getLevel3Id(level1Tag, level2Tag, length,
+            new Level3IdGenerator(level1Tag, level2Tag, length));
       }
       
       // now we finally have the mention ID
       if(level2Used) {
         return new String[] {
-                annotationType + ":" + mentionL1Tag.getId(), 
-                annotationType + ":" + mentionL2Tag.getId()};
+                annotationType + ":" + mentionL1Tag, 
+                annotationType + ":" + mentionL2Tag};
       } else {
         return new String[] {
-                annotationType + ":" + mentionL1Tag.getId()};
+                annotationType + ":" + mentionL1Tag};
       }
-    } catch(SQLException e) {
+    } catch(Exception e) {
       // something went bad: we can't fix it :(
       logger.error("Error while interogating database. Annotation was lost!", 
e);
       return new String[]{};
@@ -1168,10 +1245,6 @@
               + ", "
               + (Double.isNaN(l3ratio) ? "N/A" : 
percentFormat.format(l3ratio)));
       docsSoFar++;
-      if(docsSoFar % 200 == 0) {
-        // every 200 docs, adjust the cache sizes
-        cache.adjustCacheSizes();
-      }
     } else {
       logger.debug("Cache size(" + annotationType + "): null");
     }
@@ -1221,4 +1294,26 @@
   
     return null;
   }
+  
+  /**
+   * Sets the size for the three level caches used by this helper.
+   * 
+   * A negative value for each cache size sets the cache size to its default
+   * value.
+   * 
+   * @param level1 the size for the Level 1 cache. The Level 1 cache stores 
+   * previously seen combinations of nominal feature values.
+   *  
+   * @param level2 the size for the Level 2 cache. The Level 2 cache stores 
+   * previously seen combinations of non-nominal feature values.
+   * 
+   * @param level3 the size for the Level 3 cache. The Level 1 cache stores 
+   * previously seen mention IDs.
+   */
+  public void setCacheSizes(int level1, int level2, int level3) {
+    cache.setL1CacheSize(level1);
+    cache.setL2CacheSize(level2);
+    cache.setL3CacheSize(level3);
+  }
+  
 }

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Get 100% visibility into Java/.NET code with AppDynamics Lite
It's a free troubleshooting tool designed for production
Get down to code-level detail for bottlenecks, with <2% overhead.
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap2
_______________________________________________
GATE-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gate-cvs

Reply via email to