Index: lucene/core/src/java/org/apache/lucene/codecs/lucene40/Lucene40PostingsWriter.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/codecs/lucene40/Lucene40PostingsWriter.java	(revision 1300967)
+++ lucene/core/src/java/org/apache/lucene/codecs/lucene40/Lucene40PostingsWriter.java	(working copy)
@@ -133,7 +133,7 @@
   }
 
   @Override
-  public void startTerm() {
+  public void startTerm(BytesRef text) {
     freqStart = freqOut.getFilePointer();
     //if (DEBUG) System.out.println("SPW: startTerm freqOut.fp=" + freqStart);
     if (proxOut != null) {
Index: lucene/core/src/java/org/apache/lucene/codecs/pulsing/PulsingPostingsWriter.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/codecs/pulsing/PulsingPostingsWriter.java	(revision 1300967)
+++ lucene/core/src/java/org/apache/lucene/codecs/pulsing/PulsingPostingsWriter.java	(working copy)
@@ -101,10 +101,12 @@
     wrappedPostingsWriter.start(termsOut);
   }
 
+  BytesRef term;
   @Override
-  public void startTerm() {
+  public void startTerm(BytesRef text) {
     if (DEBUG) System.out.println("PW   startTerm");
     assert pendingCount == 0;
+    term = text;
   }
 
   // TODO: -- should we NOT reuse across fields?  would
@@ -360,7 +362,7 @@
     if (DEBUG) System.out.println("PW now push @ " + pendingCount + " wrapped=" + wrappedPostingsWriter);
     assert pendingCount == pending.length;
       
-    wrappedPostingsWriter.startTerm();
+    wrappedPostingsWriter.startTerm(term);
       
     // Flush all buffered docs
     if (indexOptions.compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) >= 0) {
Index: lucene/core/src/java/org/apache/lucene/codecs/BlockTermsWriter.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/codecs/BlockTermsWriter.java	(revision 1300967)
+++ lucene/core/src/java/org/apache/lucene/codecs/BlockTermsWriter.java	(working copy)
@@ -191,7 +191,7 @@
     @Override
     public PostingsConsumer startTerm(BytesRef text) throws IOException {
       //System.out.println("BTW: startTerm term=" + fieldInfo.name + ":" + text.utf8ToString() + " " + text + " seg=" + segment);
-      postingsWriter.startTerm();
+      postingsWriter.startTerm(text);
       return postingsWriter;
     }
 
Index: lucene/core/src/java/org/apache/lucene/codecs/PostingsWriterBase.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/codecs/PostingsWriterBase.java	(revision 1300967)
+++ lucene/core/src/java/org/apache/lucene/codecs/PostingsWriterBase.java	(working copy)
@@ -21,6 +21,7 @@
 import java.io.Closeable;
 
 import org.apache.lucene.store.IndexOutput;
+import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.index.FieldInfo;
 
 /**
@@ -34,7 +35,7 @@
 
   public abstract void start(IndexOutput termsOut) throws IOException;
 
-  public abstract void startTerm() throws IOException;
+  public abstract void startTerm(BytesRef text) throws IOException;
 
   /** Flush count terms starting at start "backwards", as a
    *  block. start is a negative offset from the end of the
Index: lucene/core/src/java/org/apache/lucene/codecs/sep/SepPostingsWriter.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/codecs/sep/SepPostingsWriter.java	(revision 1300967)
+++ lucene/core/src/java/org/apache/lucene/codecs/sep/SepPostingsWriter.java	(working copy)
@@ -165,7 +165,7 @@
   }
 
   @Override
-  public void startTerm() throws IOException {
+  public void startTerm(BytesRef text) throws IOException {
     docIndex.mark();
     //System.out.println("SEPW: startTerm docIndex=" + docIndex);
 
Index: lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsWriter.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsWriter.java	(revision 1300967)
+++ lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsWriter.java	(working copy)
@@ -844,7 +844,7 @@
     @Override
     public PostingsConsumer startTerm(BytesRef text) throws IOException {
       //if (DEBUG) System.out.println("\nBTTW.startTerm term=" + fieldInfo.name + ":" + toString(text) + " seg=" + segment);
-      postingsWriter.startTerm();
+      postingsWriter.startTerm(text);
       /*
       if (fieldInfo.name.equals("id")) {
         postingsWriter.termID = Integer.parseInt(text.utf8ToString());
Index: lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java	(revision 1300967)
+++ lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java	(working copy)
@@ -174,9 +174,13 @@
     protected int maxCoord;  // num optional + num required
     private final boolean disableCoord;
     private final boolean termConjunction;
+    private final boolean maxscoreOptimizationApplicable;
 
+    public final IndexSearcher searcher;
+    
     public BooleanWeight(IndexSearcher searcher, boolean disableCoord)
       throws IOException {
+      this.searcher = searcher;
       this.similarity = searcher.getSimilarity();
       this.disableCoord = disableCoord;
       weights = new ArrayList<Weight>(clauses.size());
@@ -191,6 +195,17 @@
         if (!c.isProhibited()) maxCoord++;
       }
       this.termConjunction = termConjunction;
+      boolean maxscoreOptimizationApplicable = true;
+      for (int i=0; maxscoreOptimizationApplicable && i<clauses.size(); i++) {
+        BooleanClause c = clauses.get(i);
+        Weight        w = weights.get(i);
+        if (!((w instanceof TermWeight) && !c.isRequired() && !c.isProhibited())) {
+          // prohibited clauses not handled yet by maxscore optimization
+          maxscoreOptimizationApplicable = false; // only SHOULD terms supported
+          break;
+        }
+      }
+      this.maxscoreOptimizationApplicable = maxscoreOptimizationApplicable;
     }
 
     @Override
@@ -328,7 +343,15 @@
           optional.add(subScorer);
         }
       }
-      
+
+      // Check if we can return a MaxscoreScorer
+      if (topScorer && maxscoreOptimizationApplicable
+          // FIXME && Lucene40Maxscore is codec of index segment
+          //       && similarity.equals( similarity for which maxscores are available)
+          && required.size() == 0 && prohibited.size() == 0 && optional.size() >= 2) {
+        return new MaxscoreScorer(this, disableCoord, context, minNrShouldMatch, required, prohibited, optional, maxCoord);
+      }
+
       // Check if we can return a BooleanScorer
       if (!scoreDocsInOrder && topScorer && required.size() == 0) {
         return new BooleanScorer(this, disableCoord, minNrShouldMatch, optional, prohibited, maxCoord);
Index: lucene/core/src/java/org/apache/lucene/search/TermQuery.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/search/TermQuery.java	(revision 1300967)
+++ lucene/core/src/java/org/apache/lucene/search/TermQuery.java	(working copy)
@@ -40,14 +40,15 @@
   */
 public class TermQuery extends Query {
   private final Term term;
-  private final int docFreq;
+  public final int docFreq;
   private final TermContext perReaderTermState;
 
   final class TermWeight extends Weight {
-    private final Similarity similarity;
+    final Similarity similarity;
     private final Similarity.SimWeight stats;
     private final TermContext termStates;
-
+    public TermState ts;
+    
     public TermWeight(IndexSearcher searcher, TermContext termStates)
       throws IOException {
       assert termStates != null : "TermContext must not be null";
@@ -83,6 +84,7 @@
       if (termsEnum == null) {
         return null;
       }
+      ts = termsEnum.termState();
       DocsEnum docs = termsEnum.docs(acceptDocs, null, true);
       if (docs != null) {
         return new TermScorer(this, docs, createDocScorer(context));
Index: lucene/core/src/resources/META-INF/services/org.apache.lucene.codecs.Codec
===================================================================
--- lucene/core/src/resources/META-INF/services/org.apache.lucene.codecs.Codec	(revision 1300967)
+++ lucene/core/src/resources/META-INF/services/org.apache.lucene.codecs.Codec	(working copy)
@@ -17,3 +17,5 @@
 org.apache.lucene.codecs.lucene3x.Lucene3xCodec
 org.apache.lucene.codecs.simpletext.SimpleTextCodec
 org.apache.lucene.codecs.appending.AppendingCodec
+
+org.apache.lucene.codecs.maxscore.Lucene40MaxscoreCodec
Index: lucene/core/src/resources/META-INF/services/org.apache.lucene.codecs.PostingsFormat
===================================================================
--- lucene/core/src/resources/META-INF/services/org.apache.lucene.codecs.PostingsFormat	(revision 1300967)
+++ lucene/core/src/resources/META-INF/services/org.apache.lucene.codecs.PostingsFormat	(working copy)
@@ -17,3 +17,5 @@
 org.apache.lucene.codecs.pulsing.Pulsing40PostingsFormat
 org.apache.lucene.codecs.simpletext.SimpleTextPostingsFormat
 org.apache.lucene.codecs.memory.MemoryPostingsFormat
+
+org.apache.lucene.codecs.maxscore.Lucene40MaxscorePostingsFormat
Index: lucene/build.xml
===================================================================
--- lucene/build.xml	(revision 1300967)
+++ lucene/build.xml	(working copy)
@@ -23,6 +23,7 @@
   <import file="common-build.xml"/>
 
   <path id="classpath">
+    <pathelement location="${common.dir}/build/contrib/maxscore/classes/java"/>
     <pathelement location="${common.dir}/build/core/classes/java"/>
   </path>
 
Index: lucene/contrib/contrib-build.xml
===================================================================
--- lucene/contrib/contrib-build.xml	(revision 1300967)
+++ lucene/contrib/contrib-build.xml	(working copy)
@@ -249,4 +249,16 @@
     </ant>
     <property name="suggest.uptodate" value="true"/>
   </target>
+
+  <property name="maxscore.jar" value="${common.dir}/build/contrib/maxscore/lucene-maxscore-${version}.jar"/>
+  <target name="check-maxscore-uptodate" unless="maxscore.uptodate">
+    <contrib-uptodate name="maxscore" jarfile="${maxscore.jar}" property="maxscore.uptodate"/>
+  </target>
+  <target name="jar-maxscore" unless="maxscore.uptodate" depends="check-maxscore-uptodate">
+    <ant dir="${common.dir}/contrib/maxscore" target="jar-core" inheritall="false">
+      <propertyset refid="uptodate.and.compiled.properties"/>
+    </ant>
+    <property name="maxscore.uptodate" value="true"/>
+  </target>
+
 </project>
