You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mi...@apache.org on 2015/06/26 18:01:17 UTC

svn commit: r1687792 - in /lucene/dev/branches/branch_5x: ./ lucene/ lucene/CHANGES.txt lucene/core/ lucene/core/src/java/org/apache/lucene/index/FieldInfos.java

Author: mikemccand
Date: Fri Jun 26 16:01:17 2015
New Revision: 1687792

URL: http://svn.apache.org/r1687792
Log:
LUCENE-6325: use array for number -> FieldInfo lookup, except in very sparse cases

Modified:
    lucene/dev/branches/branch_5x/   (props changed)
    lucene/dev/branches/branch_5x/lucene/   (props changed)
    lucene/dev/branches/branch_5x/lucene/CHANGES.txt   (contents, props changed)
    lucene/dev/branches/branch_5x/lucene/core/   (props changed)
    lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/index/FieldInfos.java

Modified: lucene/dev/branches/branch_5x/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/CHANGES.txt?rev=1687792&r1=1687791&r2=1687792&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/CHANGES.txt (original)
+++ lucene/dev/branches/branch_5x/lucene/CHANGES.txt Fri Jun 26 16:01:17 2015
@@ -189,6 +189,10 @@ Optimizations
   with a filter of "baz" will internally leapfrog foo,bar,baz as one
   conjunction. (Ryan Ernst, Robert Muir, Adrien Grande)
 
+* LUCENE-6325: Reduce RAM usage of FieldInfos, and speed up lookup by
+  number, by using an array instead of TreeMap except in very sparse
+  cases (Robert Muir, Mike McCandless)
+
 Build
 
 * LUCENE-6518: Don't report false thread leaks from IBM J9

Modified: lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/index/FieldInfos.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/index/FieldInfos.java?rev=1687792&r1=1687791&r2=1687792&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/index/FieldInfos.java (original)
+++ lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/index/FieldInfos.java Fri Jun 26 16:01:17 2015
@@ -25,6 +25,8 @@ import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
+import org.apache.lucene.util.ArrayUtil;
+
 /** 
  * Collection of {@link FieldInfo}s (accessible by number or by name).
  *  @lucene.experimental
@@ -38,7 +40,10 @@ public class FieldInfos implements Itera
   private final boolean hasNorms;
   private final boolean hasDocValues;
   
-  private final SortedMap<Integer,FieldInfo> byNumber = new TreeMap<>();
+  // used only by fieldInfo(int)
+  private final FieldInfo[] byNumberTable; // contiguous
+  private final SortedMap<Integer,FieldInfo> byNumberMap; // sparse
+  
   private final HashMap<String,FieldInfo> byName = new HashMap<>();
   private final Collection<FieldInfo> values; // for an unmodifiable iterator
   
@@ -54,6 +59,7 @@ public class FieldInfos implements Itera
     boolean hasNorms = false;
     boolean hasDocValues = false;
     
+    TreeMap<Integer, FieldInfo> byNumber = new TreeMap<>();
     for (FieldInfo info : infos) {
       if (info.number < 0) {
         throw new IllegalArgumentException("illegal field number: " + info.number + " for field " + info.name);
@@ -84,6 +90,22 @@ public class FieldInfos implements Itera
     this.hasNorms = hasNorms;
     this.hasDocValues = hasDocValues;
     this.values = Collections.unmodifiableCollection(byNumber.values());
+    Integer max = byNumber.isEmpty() ? null : Collections.max(byNumber.keySet());
+    
+    // Only usee TreeMap in the very sparse case (< 1/16th of the numbers are used),
+    // because TreeMap uses ~ 64 (32 bit JVM) or 120 (64 bit JVM w/o compressed oops)
+    // overall bytes per entry, but array uses 4 (32 bit JMV) or 8
+    // (64 bit JVM w/o compressed oops):
+    if (max != null && max < ArrayUtil.MAX_ARRAY_LENGTH && max < 16L*byNumber.size()) {
+      byNumberMap = null;
+      byNumberTable = new FieldInfo[max+1];
+      for (Map.Entry<Integer,FieldInfo> entry : byNumber.entrySet()) {
+        byNumberTable[entry.getKey()] = entry.getValue();
+      }
+    } else {
+      byNumberMap = byNumber;
+      byNumberTable = null;
+    }
   }
   
   /** Returns true if any fields have freqs */
@@ -123,8 +145,7 @@ public class FieldInfos implements Itera
   
   /** Returns the number of fields */
   public int size() {
-    assert byNumber.size() == byName.size();
-    return byNumber.size();
+    return byName.size();
   }
   
   /**
@@ -157,7 +178,14 @@ public class FieldInfos implements Itera
     if (fieldNumber < 0) {
       throw new IllegalArgumentException("Illegal field number: " + fieldNumber);
     }
-    return byNumber.get(fieldNumber);
+    if (byNumberTable != null) {
+      if (fieldNumber >= byNumberTable.length) {
+        return null;
+      }
+      return byNumberTable[fieldNumber];
+    } else {
+      return byNumberMap.get(fieldNumber);
+    }
   }
   
   static final class FieldNumbers {