Index: solr/src/test/org/apache/solr/schema/IndexSchemaTest.java =================================================================== --- solr/src/test/org/apache/solr/schema/IndexSchemaTest.java (revision 1061835) +++ solr/src/test/org/apache/solr/schema/IndexSchemaTest.java (working copy) @@ -27,7 +27,7 @@ import org.apache.solr.core.SolrCore; import org.apache.solr.request.LocalSolrQueryRequest; import org.apache.solr.request.SolrQueryRequest; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.junit.BeforeClass; import org.junit.Test; @@ -83,7 +83,7 @@ @Test public void testSimilarityFactory() { SolrCore core = h.getCore(); - Similarity similarity = core.getSchema().getSimilarity(); + SimilarityProvider similarity = core.getSchema().getSimilarityProvider(); assertTrue("wrong class", similarity instanceof MockConfigurableSimilarity); assertEquals("is there an echo?", ((MockConfigurableSimilarity)similarity).getPassthrough()); } Index: solr/src/test/org/apache/solr/schema/CustomSimilarityFactory.java =================================================================== --- solr/src/test/org/apache/solr/schema/CustomSimilarityFactory.java (revision 1061835) +++ solr/src/test/org/apache/solr/schema/CustomSimilarityFactory.java (working copy) @@ -16,10 +16,10 @@ */ package org.apache.solr.schema; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; public class CustomSimilarityFactory extends SimilarityFactory { - public Similarity getSimilarity() { + public SimilarityProvider getSimilarityProvider() { return new MockConfigurableSimilarity(params.get("echo")); } } Index: solr/src/java/org/apache/solr/schema/IndexSchema.java =================================================================== --- solr/src/java/org/apache/solr/schema/IndexSchema.java (revision 1061835) +++ solr/src/java/org/apache/solr/schema/IndexSchema.java (working copy) @@ -20,7 +20,8 @@ import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.document.Fieldable; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.util.Version; import org.apache.solr.common.ResourceLoader; @@ -192,7 +193,7 @@ /** * Returns the Similarity used for this index */ - public Similarity getSimilarity() { return similarityFactory.getSimilarity(); } + public SimilarityProvider getSimilarityProvider() { return similarityFactory.getSimilarityProvider(); } /** * Returns the SimilarityFactory used for this index @@ -496,8 +497,8 @@ Node node = (Node) xpath.evaluate("/schema/similarity", document, XPathConstants.NODE); if (node==null) { similarityFactory = new SimilarityFactory() { - public Similarity getSimilarity() { - return Similarity.getDefault(); + public SimilarityProvider getSimilarityProvider() { + return IndexSearcher.getDefaultSimilarityProvider(); } }; log.debug("using default similarity"); @@ -509,10 +510,10 @@ similarityFactory = (SimilarityFactory)obj; similarityFactory.init(params); } else { - // just like always, assume it's a Similarlity and get a ClassCastException - reasonable error handling + // just like always, assume it's a SimilarityProvider and get a ClassCastException - reasonable error handling similarityFactory = new SimilarityFactory() { - public Similarity getSimilarity() { - return (Similarity) obj; + public SimilarityProvider getSimilarityProvider() { + return (SimilarityProvider) obj; } }; } Index: solr/src/java/org/apache/solr/schema/SimilarityFactory.java =================================================================== --- solr/src/java/org/apache/solr/schema/SimilarityFactory.java (revision 1061835) +++ solr/src/java/org/apache/solr/schema/SimilarityFactory.java (working copy) @@ -16,7 +16,7 @@ * limitations under the License. */ -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.solr.common.params.SolrParams; public abstract class SimilarityFactory { @@ -25,5 +25,5 @@ public void init(SolrParams params) { this.params = params; } public SolrParams getParams() { return params; } - public abstract Similarity getSimilarity(); + public abstract SimilarityProvider getSimilarityProvider(); } Index: solr/src/java/org/apache/solr/update/SolrIndexConfig.java =================================================================== --- solr/src/java/org/apache/solr/update/SolrIndexConfig.java (revision 1061835) +++ solr/src/java/org/apache/solr/update/SolrIndexConfig.java (working copy) @@ -153,7 +153,7 @@ if (writeLockTimeout != -1) iwc.setWriteLockTimeout(writeLockTimeout); - iwc.setSimilarity(schema.getSimilarity()); + iwc.setSimilarityProvider(schema.getSimilarityProvider()); iwc.setMergePolicy(buildMergePolicy(schema)); iwc.setMergeScheduler(buildMergeScheduler(schema)); Index: solr/src/java/org/apache/solr/search/function/IDFValueSource.java =================================================================== --- solr/src/java/org/apache/solr/search/function/IDFValueSource.java (revision 1061835) +++ solr/src/java/org/apache/solr/search/function/IDFValueSource.java (working copy) @@ -41,7 +41,7 @@ @Override public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException { IndexSearcher searcher = (IndexSearcher)context.get("searcher"); - Similarity sim = searcher.getSimilarity(); + Similarity sim = searcher.getSimilarityProvider().get(field); // todo: we need docFreq that takes a BytesRef String strVal = ByteUtils.UTF8toUTF16(indexedBytes); int docfreq = searcher.docFreq(new Term(indexedField, strVal)); Index: solr/src/java/org/apache/solr/search/function/TFValueSource.java =================================================================== --- solr/src/java/org/apache/solr/search/function/TFValueSource.java (revision 1061835) +++ solr/src/java/org/apache/solr/search/function/TFValueSource.java (working copy) @@ -25,7 +25,7 @@ public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException { Fields fields = readerContext.reader.fields(); final Terms terms = fields.terms(field); - final Similarity similarity = ((IndexSearcher)context.get("searcher")).getSimilarity(); + final Similarity similarity = ((IndexSearcher)context.get("searcher")).getSimilarityProvider().get(field); return new FloatDocValues(this) { DocsEnum docs ; Index: solr/src/java/org/apache/solr/search/function/NormValueSource.java =================================================================== --- solr/src/java/org/apache/solr/search/function/NormValueSource.java (revision 1061835) +++ solr/src/java/org/apache/solr/search/function/NormValueSource.java (working copy) @@ -46,7 +46,7 @@ @Override public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException { IndexSearcher searcher = (IndexSearcher)context.get("searcher"); - final Similarity similarity = searcher.getSimilarity(); + final Similarity similarity = searcher.getSimilarityProvider().get(field); final byte[] norms = readerContext.reader.norms(field); if (norms == null) { return new ConstDoubleDocValues(0.0, this); Index: solr/src/java/org/apache/solr/search/SolrConstantScoreQuery.java =================================================================== --- solr/src/java/org/apache/solr/search/SolrConstantScoreQuery.java (revision 1061835) +++ solr/src/java/org/apache/solr/search/SolrConstantScoreQuery.java (working copy) @@ -55,13 +55,11 @@ } protected class ConstantWeight extends Weight { - private Similarity similarity; private float queryNorm; private float queryWeight; private Map context; public ConstantWeight(IndexSearcher searcher) throws IOException { - this.similarity = searcher.getSimilarity(); this.context = ValueSource.newContext(searcher); if (filter instanceof SolrFilter) ((SolrFilter)filter).createWeight(context, searcher); Index: solr/src/java/org/apache/solr/search/SolrIndexSearcher.java =================================================================== --- solr/src/java/org/apache/solr/search/SolrIndexSearcher.java (revision 1061835) +++ solr/src/java/org/apache/solr/search/SolrIndexSearcher.java (working copy) @@ -132,7 +132,7 @@ } this.closeReader = closeReader; - setSimilarity(schema.getSimilarity()); + setSimilarityProvider(schema.getSimilarityProvider()); SolrConfig solrConfig = core.getSolrConfig(); queryResultWindowSize = solrConfig.queryResultWindowSize; Index: lucene/src/test/org/apache/lucene/search/payloads/TestPayloadNearQuery.java =================================================================== --- lucene/src/test/org/apache/lucene/search/payloads/TestPayloadNearQuery.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/payloads/TestPayloadNearQuery.java (working copy) @@ -105,7 +105,7 @@ directory = newDirectory(); RandomIndexWriter writer = new RandomIndexWriter(random, directory, newIndexWriterConfig(TEST_VERSION_CURRENT, new PayloadAnalyzer()) - .setSimilarity(similarity)); + .setSimilarityProvider(similarity)); //writer.infoStream = System.out; for (int i = 0; i < 1000; i++) { Document doc = new Document(); @@ -118,7 +118,7 @@ writer.close(); searcher = new IndexSearcher(reader); - searcher.setSimilarity(similarity); + searcher.setSimilarityProvider(similarity); } @Override Index: lucene/src/test/org/apache/lucene/search/payloads/TestPayloadTermQuery.java =================================================================== --- lucene/src/test/org/apache/lucene/search/payloads/TestPayloadTermQuery.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/payloads/TestPayloadTermQuery.java (working copy) @@ -111,7 +111,7 @@ directory = newDirectory(); RandomIndexWriter writer = new RandomIndexWriter(random, directory, newIndexWriterConfig(TEST_VERSION_CURRENT, new PayloadAnalyzer()) - .setSimilarity(similarity)); + .setSimilarityProvider(similarity)); //writer.infoStream = System.out; for (int i = 0; i < 1000; i++) { Document doc = new Document(); @@ -126,7 +126,7 @@ writer.close(); searcher = new IndexSearcher(reader); - searcher.setSimilarity(similarity); + searcher.setSimilarityProvider(similarity); } @Override @@ -223,7 +223,7 @@ new MaxPayloadFunction(), false); IndexSearcher theSearcher = new IndexSearcher(directory, true); - theSearcher.setSimilarity(new FullSimilarity()); + theSearcher.setSimilarityProvider(new FullSimilarity()); TopDocs hits = searcher.search(query, null, 100); assertTrue("hits is null and it shouldn't be", hits != null); assertTrue("hits Size: " + hits.totalHits + " is not: " + 100, hits.totalHits == 100); Index: lucene/src/test/org/apache/lucene/search/payloads/PayloadHelper.java =================================================================== --- lucene/src/test/org/apache/lucene/search/payloads/PayloadHelper.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/payloads/PayloadHelper.java (working copy) @@ -28,7 +28,7 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.SlowMultiReaderWrapper; import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.store.Directory; import org.apache.lucene.store.MockDirectoryWrapper; import org.apache.lucene.store.RAMDirectory; @@ -112,13 +112,13 @@ * @throws IOException */ // TODO: randomize - public IndexSearcher setUp(Random random, Similarity similarity, int numDocs) throws IOException { + public IndexSearcher setUp(Random random, SimilarityProvider similarity, int numDocs) throws IOException { Directory directory = new MockDirectoryWrapper(random, new RAMDirectory()); PayloadAnalyzer analyzer = new PayloadAnalyzer(); // TODO randomize this IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig( - TEST_VERSION_CURRENT, analyzer).setSimilarity(similarity)); + TEST_VERSION_CURRENT, analyzer).setSimilarityProvider(similarity)); // writer.infoStream = System.out; for (int i = 0; i < numDocs; i++) { Document doc = new Document(); @@ -131,7 +131,7 @@ writer.close(); IndexSearcher searcher = new IndexSearcher(reader); - searcher.setSimilarity(similarity); + searcher.setSimilarityProvider(similarity); return searcher; } Index: lucene/src/test/org/apache/lucene/search/spans/TestSpans.java =================================================================== --- lucene/src/test/org/apache/lucene/search/spans/TestSpans.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/spans/TestSpans.java (working copy) @@ -20,9 +20,9 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Query; import org.apache.lucene.search.CheckHits; -import org.apache.lucene.search.Similarity; import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.Scorer; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Weight.ScorerContext; @@ -403,17 +403,17 @@ boolean ordered = true; int slop = 1; - final Similarity sim = new DefaultSimilarity() { + final SimilarityProvider sim = new DefaultSimilarity() { @Override public float sloppyFreq(int distance) { return 0.0f; } }; - final Similarity oldSim = searcher.getSimilarity(); + final SimilarityProvider oldSim = searcher.getSimilarityProvider(); Scorer spanScorer; try { - searcher.setSimilarity(sim); + searcher.setSimilarityProvider(sim); SpanNearQuery snq = new SpanNearQuery( new SpanQuery[] { makeSpanTermQuery("t1"), @@ -423,7 +423,7 @@ spanScorer = snq.weight(searcher).scorer(new AtomicReaderContext(new SlowMultiReaderWrapper(searcher.getIndexReader())), ScorerContext.def()); } finally { - searcher.setSimilarity(oldSim); + searcher.setSimilarityProvider(oldSim); } assertTrue("first doc", spanScorer.nextDoc() != DocIdSetIterator.NO_MORE_DOCS); assertEquals("first doc number", spanScorer.docID(), 11); Index: lucene/src/test/org/apache/lucene/search/spans/TestPayloadSpans.java =================================================================== --- lucene/src/test/org/apache/lucene/search/spans/TestPayloadSpans.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/spans/TestPayloadSpans.java (working copy) @@ -40,7 +40,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.payloads.PayloadHelper; @@ -51,7 +51,7 @@ public class TestPayloadSpans extends LuceneTestCase { private IndexSearcher searcher; - private Similarity similarity = new DefaultSimilarity(); + private SimilarityProvider similarity = new DefaultSimilarity(); protected IndexReader indexReader; private IndexReader closeIndexReader; private Directory directory; @@ -111,7 +111,7 @@ Directory directory = newDirectory(); RandomIndexWriter writer = new RandomIndexWriter(random, directory, - newIndexWriterConfig(TEST_VERSION_CURRENT, new PayloadAnalyzer()).setSimilarity(similarity)); + newIndexWriterConfig(TEST_VERSION_CURRENT, new PayloadAnalyzer()).setSimilarityProvider(similarity)); Document doc = new Document(); doc.add(newField(PayloadHelper.FIELD, "one two three one four three", @@ -370,7 +370,7 @@ public void testPayloadSpanUtil() throws Exception { Directory directory = newDirectory(); RandomIndexWriter writer = new RandomIndexWriter(random, directory, - newIndexWriterConfig(TEST_VERSION_CURRENT, new PayloadAnalyzer()).setSimilarity(similarity)); + newIndexWriterConfig(TEST_VERSION_CURRENT, new PayloadAnalyzer()).setSimilarityProvider(similarity)); Document doc = new Document(); doc.add(newField(PayloadHelper.FIELD,"xx rr yy mm pp", Field.Store.YES, Field.Index.ANALYZED)); @@ -430,7 +430,7 @@ directory = newDirectory(); String[] docs = new String[]{"xx rr yy mm pp","xx yy mm rr pp", "nopayload qq ss pp np", "one two three four five six seven eight nine ten eleven", "nine one two three four five six seven eight eleven ten"}; RandomIndexWriter writer = new RandomIndexWriter(random, directory, - newIndexWriterConfig(TEST_VERSION_CURRENT, new PayloadAnalyzer()).setSimilarity(similarity)); + newIndexWriterConfig(TEST_VERSION_CURRENT, new PayloadAnalyzer()).setSimilarityProvider(similarity)); Document doc = null; for(int i = 0; i < docs.length; i++) { Index: lucene/src/test/org/apache/lucene/search/TestSetNorm.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestSetNorm.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/TestSetNorm.java (working copy) @@ -51,10 +51,11 @@ // reset the boost of each instance of this document IndexReader reader = IndexReader.open(store, false); - reader.setNorm(0, "field", Similarity.getDefault().encodeNormValue(1.0f)); - reader.setNorm(1, "field", Similarity.getDefault().encodeNormValue(2.0f)); - reader.setNorm(2, "field", Similarity.getDefault().encodeNormValue(4.0f)); - reader.setNorm(3, "field", Similarity.getDefault().encodeNormValue(16.0f)); + Similarity similarity = new DefaultSimilarity().get("field"); + reader.setNorm(0, "field", similarity.encodeNormValue(1.0f)); + reader.setNorm(1, "field", similarity.encodeNormValue(2.0f)); + reader.setNorm(2, "field", similarity.encodeNormValue(4.0f)); + reader.setNorm(3, "field", similarity.encodeNormValue(16.0f)); reader.close(); // check that searches are ordered by this boost Index: lucene/src/test/org/apache/lucene/search/TestBoolean2.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestBoolean2.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/TestBoolean2.java (working copy) @@ -208,9 +208,9 @@ public void testQueries10() throws Exception { String queryText = "+w3 +xx +w2 zz"; int[] expDocNrs = {2, 3}; - Similarity oldSimilarity = searcher.getSimilarity(); + SimilarityProvider oldSimilarity = searcher.getSimilarityProvider(); try { - searcher.setSimilarity(new DefaultSimilarity(){ + searcher.setSimilarityProvider(new DefaultSimilarity(){ @Override public float coord(int overlap, int maxOverlap) { return overlap / ((float)maxOverlap - 1); @@ -218,7 +218,7 @@ }); queriesTest(queryText, expDocNrs); } finally { - searcher.setSimilarity(oldSimilarity); + searcher.setSimilarityProvider(oldSimilarity); } } Index: lucene/src/test/org/apache/lucene/search/TestConstantScoreQuery.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestConstantScoreQuery.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/TestConstantScoreQuery.java (working copy) @@ -97,7 +97,7 @@ searcher = new IndexSearcher(reader); // set a similarity that does not normalize our boost away - searcher.setSimilarity(new DefaultSimilarity() { + searcher.setSimilarityProvider(new DefaultSimilarity() { @Override public float queryNorm(float sumOfSquaredWeights) { return 1.0f; Index: lucene/src/test/org/apache/lucene/search/TestMatchAllDocsQuery.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestMatchAllDocsQuery.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/TestMatchAllDocsQuery.java (working copy) @@ -69,7 +69,7 @@ assertEquals("one", ir.document(hits[2].doc).get("key")); // change norm & retest - ir.setNorm(0, "key", Similarity.getDefault().encodeNormValue(400f)); + ir.setNorm(0, "key", is.getSimilarityProvider().get("key").encodeNormValue(400f)); normsQuery = new MatchAllDocsQuery("key"); hits = is.search(normsQuery, null, 1000).scoreDocs; assertEquals(3, hits.length); Index: lucene/src/test/org/apache/lucene/search/JustCompileSearch.java =================================================================== --- lucene/src/test/org/apache/lucene/search/JustCompileSearch.java (revision 1061944) +++ lucene/src/test/org/apache/lucene/search/JustCompileSearch.java (working copy) @@ -244,35 +244,39 @@ static final class JustCompileSimilarity extends Similarity { @Override - public float coord(int overlap, int maxOverlap) { + public float idf(int docFreq, int numDocs) { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } @Override - public float idf(int docFreq, int numDocs) { + public float computeNorm(String fieldName, FieldInvertState state) { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } @Override - public float computeNorm(String fieldName, FieldInvertState state) { + public float sloppyFreq(int distance) { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } @Override + public float tf(float freq) { + throw new UnsupportedOperationException(UNSUPPORTED_MSG); + } + } + + static final class JustCompileSimilarityProvider implements SimilarityProvider { + public float queryNorm(float sumOfSquaredWeights) { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } - - @Override - public float sloppyFreq(int distance) { + + public float coord(int overlap, int maxOverlap) { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } - - @Override - public float tf(float freq) { + + public Similarity get(String field) { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } - } static final class JustCompileSpanFilter extends SpanFilter { Index: lucene/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java (working copy) @@ -73,7 +73,7 @@ } } - public Similarity sim = new TestSimilarity(); + public SimilarityProvider sim = new TestSimilarity(); public Directory index; public IndexReader r; public IndexSearcher s; @@ -85,7 +85,7 @@ index = newDirectory(); RandomIndexWriter writer = new RandomIndexWriter(random, index, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer()) - .setSimilarity(sim)); + .setSimilarityProvider(sim)); // hed is the most important field, dek is secondary @@ -150,7 +150,7 @@ r = new SlowMultiReaderWrapper(writer.getReader()); writer.close(); s = new IndexSearcher(r); - s.setSimilarity(sim); + s.setSimilarityProvider(sim); } @Override Index: lucene/src/test/org/apache/lucene/search/TestSimilarity.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestSimilarity.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/TestSimilarity.java (working copy) @@ -39,13 +39,11 @@ */ public class TestSimilarity extends LuceneTestCase { - public static class SimpleSimilarity extends Similarity { + public static class SimpleSimilarity extends Similarity implements SimilarityProvider { @Override public float computeNorm(String field, FieldInvertState state) { return state.getBoost(); } - @Override public float queryNorm(float sumOfSquaredWeights) { return 1.0f; } @Override public float tf(float freq) { return freq; } @Override public float sloppyFreq(int distance) { return 2.0f; } @Override public float idf(int docFreq, int numDocs) { return 1.0f; } - @Override public float coord(int overlap, int maxOverlap) { return 1.0f; } @Override public IDFExplanation idfExplain(Collection terms, IndexSearcher searcher) throws IOException { return new IDFExplanation() { @Override @@ -58,13 +56,18 @@ } }; } + public float queryNorm(float sumOfSquaredWeights) { return 1.0f; } + public float coord(int overlap, int maxOverlap) { return 1.0f; } + public Similarity get(String field) { + return this; + } } public void testSimilarity() throws Exception { Directory store = newDirectory(); RandomIndexWriter writer = new RandomIndexWriter(random, store, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer()) - .setSimilarity(new SimpleSimilarity())); + .setSimilarityProvider(new SimpleSimilarity())); Document d1 = new Document(); d1.add(newField("field", "a c", Field.Store.YES, Field.Index.ANALYZED)); @@ -78,7 +81,7 @@ writer.close(); IndexSearcher searcher = new IndexSearcher(reader); - searcher.setSimilarity(new SimpleSimilarity()); + searcher.setSimilarityProvider(new SimpleSimilarity()); Term a = new Term("field", "a"); Term b = new Term("field", "b"); Index: lucene/src/test/org/apache/lucene/search/TestComplexExplanations.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestComplexExplanations.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/TestComplexExplanations.java (working copy) @@ -34,7 +34,7 @@ @Override public void setUp() throws Exception { super.setUp(); - searcher.setSimilarity(createQnorm1Similarity()); + searcher.setSimilarityProvider(createQnorm1Similarity()); } // must be static for weight serialization tests Index: lucene/src/test/org/apache/lucene/search/TestSimilarityProvider.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestSimilarityProvider.java (revision 0) +++ lucene/src/test/org/apache/lucene/search/TestSimilarityProvider.java (revision 0) @@ -0,0 +1,151 @@ +package org.apache.lucene.search; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.analysis.MockAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.index.FieldInvertState; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.MultiNorms; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.index.Term; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.LuceneTestCase; + +public class TestSimilarityProvider extends LuceneTestCase { + private Directory directory; + private IndexReader reader; + private IndexSearcher searcher; + + @Override + public void setUp() throws Exception { + super.setUp(); + directory = newDirectory(); + SimilarityProvider sim = new ExampleSimilarityProvider(); + IndexWriterConfig iwc = newIndexWriterConfig(TEST_VERSION_CURRENT, + new MockAnalyzer()).setSimilarityProvider(sim); + RandomIndexWriter iw = new RandomIndexWriter(random, directory, iwc); + Document doc = new Document(); + Field field = newField("foo", "", Field.Store.NO, Field.Index.ANALYZED); + doc.add(field); + Field field2 = newField("bar", "", Field.Store.NO, Field.Index.ANALYZED); + doc.add(field2); + + field.setValue("quick brown fox"); + field2.setValue("quick brown fox"); + iw.addDocument(doc); + field.setValue("jumps over lazy brown dog"); + field2.setValue("jumps over lazy brown dog"); + iw.addDocument(doc); + reader = iw.getReader(); + iw.close(); + searcher = new IndexSearcher(reader); + searcher.setSimilarityProvider(sim); + } + + @Override + public void tearDown() throws Exception { + searcher.close(); + reader.close(); + directory.close(); + super.tearDown(); + } + + public void testBasics() throws Exception { + // sanity check of norms writer + byte fooNorms[] = MultiNorms.norms(reader, "foo"); + byte barNorms[] = MultiNorms.norms(reader, "bar"); + for (int i = 0; i < fooNorms.length; i++) { + assertFalse(fooNorms[i] == barNorms[i]); + } + + // sanity check of searching + TopDocs foodocs = searcher.search(new TermQuery(new Term("foo", "brown")), 10); + assertTrue(foodocs.totalHits > 0); + TopDocs bardocs = searcher.search(new TermQuery(new Term("bar", "brown")), 10); + assertTrue(bardocs.totalHits > 0); + assertTrue(foodocs.scoreDocs[0].score < bardocs.scoreDocs[0].score); + } + + private class ExampleSimilarityProvider implements SimilarityProvider { + private Similarity sim1 = new Sim1(); + private Similarity sim2 = new Sim2(); + + public float coord(int overlap, int maxOverlap) { + return 1f; + } + + public float queryNorm(float sumOfSquaredWeights) { + return 1f; + } + + public Similarity get(String field) { + if (field.equals("foo")) { + return sim1; + } else { + return sim2; + } + } + } + + private class Sim1 extends Similarity { + @Override + public float computeNorm(String field, FieldInvertState state) { + return 1f; + } + + @Override + public float sloppyFreq(int distance) { + return 1f; + } + + @Override + public float tf(float freq) { + return 1f; + } + + @Override + public float idf(int docFreq, int numDocs) { + return 1f; + } + } + + private class Sim2 extends Similarity { + @Override + public float computeNorm(String field, FieldInvertState state) { + return 10f; + } + + @Override + public float sloppyFreq(int distance) { + return 10f; + } + + @Override + public float tf(float freq) { + return 10f; + } + + @Override + public float idf(int docFreq, int numDocs) { + return 10f; + } + } +} Property changes on: lucene\src\test\org\apache\lucene\search\TestSimilarityProvider.java ___________________________________________________________________ Added: svn:eol-style + native Index: lucene/src/test/org/apache/lucene/search/QueryUtils.java =================================================================== --- lucene/src/test/org/apache/lucene/search/QueryUtils.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/search/QueryUtils.java (working copy) @@ -158,7 +158,7 @@ 0 < edge ? r : IndexReader.open(makeEmptyIndex(random, 0), true)) }; IndexSearcher out = new IndexSearcher(new MultiReader(readers)); - out.setSimilarity(s.getSimilarity()); + out.setSimilarityProvider(s.getSimilarityProvider()); return out; } Index: lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java (working copy) @@ -18,6 +18,7 @@ */ import org.apache.lucene.index.SegmentReader.Norm; +import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.Similarity; import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.document.Document; @@ -272,13 +273,14 @@ * @throws Exception */ private void performDefaultTests(IndexReader r1) throws Exception { - float norm1 = Similarity.getDefault().decodeNormValue(MultiNorms.norms(r1, "field1")[4]); + Similarity sim = new DefaultSimilarity().get("field1"); + float norm1 = sim.decodeNormValue(MultiNorms.norms(r1, "field1")[4]); IndexReader pr1Clone = (IndexReader) r1.clone(); pr1Clone.deleteDocument(10); - pr1Clone.setNorm(4, "field1", Similarity.getDefault().encodeNormValue(0.5f)); - assertTrue(Similarity.getDefault().decodeNormValue(MultiNorms.norms(r1, "field1")[4]) == norm1); - assertTrue(Similarity.getDefault().decodeNormValue(MultiNorms.norms(pr1Clone, "field1")[4]) != norm1); + pr1Clone.setNorm(4, "field1", sim.encodeNormValue(0.5f)); + assertTrue(sim.decodeNormValue(MultiNorms.norms(r1, "field1")[4]) == norm1); + assertTrue(sim.decodeNormValue(MultiNorms.norms(pr1Clone, "field1")[4]) != norm1); final Bits delDocs = MultiFields.getDeletedDocs(r1); assertTrue(delDocs == null || !delDocs.get(10)); @@ -327,7 +329,8 @@ TestIndexReaderReopen.createIndex(random, dir1, false); SegmentReader origSegmentReader = getOnlySegmentReader(IndexReader.open(dir1, false)); origSegmentReader.deleteDocument(1); - origSegmentReader.setNorm(4, "field1", Similarity.getDefault().encodeNormValue(0.5f)); + Similarity sim = new DefaultSimilarity().get("field1"); + origSegmentReader.setNorm(4, "field1", sim.encodeNormValue(0.5f)); SegmentReader clonedSegmentReader = (SegmentReader) origSegmentReader .clone(); @@ -426,8 +429,9 @@ final Directory dir1 = newDirectory(); TestIndexReaderReopen.createIndex(random, dir1, false); IndexReader orig = IndexReader.open(dir1, false); - orig.setNorm(1, "field1", Similarity.getDefault().encodeNormValue(17.0f)); - final byte encoded = Similarity.getDefault().encodeNormValue(17.0f); + Similarity sim = new DefaultSimilarity().get("field1"); + orig.setNorm(1, "field1", sim.encodeNormValue(17.0f)); + final byte encoded = sim.encodeNormValue(17.0f); assertEquals(encoded, MultiNorms.norms(orig, "field1")[1]); // the cloned segmentreader should have 2 references, 1 to itself, and 1 to Index: lucene/src/test/org/apache/lucene/index/TestIndexReader.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexReader.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestIndexReader.java (working copy) @@ -39,11 +39,12 @@ import org.apache.lucene.index.IndexReader.FieldOption; import org.apache.lucene.index.codecs.CodecProvider; import org.apache.lucene.index.IndexWriterConfig.OpenMode; +import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.FieldCache; +import org.apache.lucene.search.Similarity; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.ScoreDoc; -import org.apache.lucene.search.Similarity; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.Directory; @@ -464,8 +465,9 @@ // expected } + Similarity sim = new DefaultSimilarity().get("aaa"); try { - reader.setNorm(5, "aaa", Similarity.getDefault().encodeNormValue(2.0f)); + reader.setNorm(5, "aaa", sim.encodeNormValue(2.0f)); fail("setNorm after close failed to throw IOException"); } catch (AlreadyClosedException e) { // expected @@ -504,8 +506,9 @@ // expected } + Similarity sim = new DefaultSimilarity().get("aaa"); try { - reader.setNorm(5, "aaa", Similarity.getDefault().encodeNormValue(2.0f)); + reader.setNorm(5, "aaa", sim.encodeNormValue(2.0f)); fail("setNorm should have hit LockObtainFailedException"); } catch (LockObtainFailedException e) { // expected @@ -535,7 +538,8 @@ // now open reader & set norm for doc 0 IndexReader reader = IndexReader.open(dir, false); - reader.setNorm(0, "content", Similarity.getDefault().encodeNormValue(2.0f)); + Similarity sim = new DefaultSimilarity().get("content"); + reader.setNorm(0, "content", sim.encodeNormValue(2.0f)); // we should be holding the write lock now: assertTrue("locked", IndexWriter.isLocked(dir)); @@ -549,7 +553,7 @@ IndexReader reader2 = IndexReader.open(dir, false); // set norm again for doc 0 - reader.setNorm(0, "content", Similarity.getDefault().encodeNormValue(3.0f)); + reader.setNorm(0, "content", sim.encodeNormValue(3.0f)); assertTrue("locked", IndexWriter.isLocked(dir)); reader.close(); @@ -579,15 +583,16 @@ addDoc(writer, searchTerm.text()); writer.close(); + Similarity sim = new DefaultSimilarity().get("content"); // now open reader & set norm for doc 0 (writes to // _0_1.s0) reader = IndexReader.open(dir, false); - reader.setNorm(0, "content", Similarity.getDefault().encodeNormValue(2.0f)); + reader.setNorm(0, "content", sim.encodeNormValue(2.0f)); reader.close(); // now open reader again & set norm for doc 0 (writes to _0_2.s0) reader = IndexReader.open(dir, false); - reader.setNorm(0, "content", Similarity.getDefault().encodeNormValue(2.0f)); + reader.setNorm(0, "content", sim.encodeNormValue(2.0f)); reader.close(); assertFalse("failed to remove first generation norms file on writing second generation", dir.fileExists("_0_1.s0")); @@ -966,13 +971,13 @@ dir.setMaxSizeInBytes(thisDiskFree); dir.setRandomIOExceptionRate(rate); - + Similarity sim = new DefaultSimilarity().get("content"); try { if (0 == x) { int docId = 12; for(int i=0;i<13;i++) { reader.deleteDocument(docId); - reader.setNorm(docId, "content", Similarity.getDefault().encodeNormValue(2.0f)); + reader.setNorm(docId, "content", sim.encodeNormValue(2.0f)); docId += 12; } } @@ -1130,8 +1135,9 @@ } reader = IndexReader.open(dir, false); + Similarity sim = new DefaultSimilarity().get("content"); try { - reader.setNorm(1, "content", Similarity.getDefault().encodeNormValue(2.0f)); + reader.setNorm(1, "content", sim.encodeNormValue(2.0f)); fail("did not hit exception when calling setNorm on an invalid doc number"); } catch (ArrayIndexOutOfBoundsException e) { // expected Index: lucene/src/test/org/apache/lucene/index/TestIndexFileDeleter.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexFileDeleter.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestIndexFileDeleter.java (working copy) @@ -18,6 +18,7 @@ */ import org.apache.lucene.util.LuceneTestCase; +import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.Similarity; import org.apache.lucene.store.Directory; import org.apache.lucene.store.IndexInput; @@ -67,9 +68,9 @@ Term searchTerm = new Term("id", "7"); int delCount = reader.deleteDocuments(searchTerm); assertEquals("didn't delete the right number of documents", 1, delCount); - + Similarity sim = new DefaultSimilarity().get("content"); // Set one norm so we get a .s0 file: - reader.setNorm(21, "content", Similarity.getDefault().encodeNormValue(1.5f)); + reader.setNorm(21, "content", sim.encodeNormValue(1.5f)); reader.close(); // Now, artificially create an extra .del file & extra Index: lucene/src/test/org/apache/lucene/index/TestIndexReaderCloneNorms.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexReaderCloneNorms.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestIndexReaderCloneNorms.java (working copy) @@ -32,6 +32,7 @@ import org.apache.lucene.index.SegmentReader.Norm; import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; @@ -50,7 +51,7 @@ private static final int NUM_FIELDS = 10; - private Similarity similarityOne; + private SimilarityProvider similarityOne; private Analyzer anlzr; @@ -203,19 +204,20 @@ IndexReader reader4C = (IndexReader) reader3C.clone(); SegmentReader segmentReader4C = getOnlySegmentReader(reader4C); assertEquals(4, reader3CCNorm.bytesRef().get()); - reader4C.setNorm(5, "field1", Similarity.getDefault().encodeNormValue(0.33f)); + Similarity sim = new DefaultSimilarity().get("field1"); + reader4C.setNorm(5, "field1", sim.encodeNormValue(0.33f)); // generate a cannot update exception in reader1 try { - reader3C.setNorm(1, "field1", Similarity.getDefault().encodeNormValue(0.99f)); + reader3C.setNorm(1, "field1", sim.encodeNormValue(0.99f)); fail("did not hit expected exception"); } catch (Exception ex) { // expected } // norm values should be different - assertTrue(Similarity.getDefault().decodeNormValue(segmentReader3C.norms("field1")[5]) - != Similarity.getDefault().decodeNormValue(segmentReader4C.norms("field1")[5])); + assertTrue(sim.decodeNormValue(segmentReader3C.norms("field1")[5]) + != sim.decodeNormValue(segmentReader4C.norms("field1")[5])); Norm reader4CCNorm = segmentReader4C.norms.get("field1"); assertEquals(3, reader3CCNorm.bytesRef().get()); assertEquals(1, reader4CCNorm.bytesRef().get()); @@ -223,7 +225,7 @@ IndexReader reader5C = (IndexReader) reader4C.clone(); SegmentReader segmentReader5C = getOnlySegmentReader(reader5C); Norm reader5CCNorm = segmentReader5C.norms.get("field1"); - reader5C.setNorm(5, "field1", Similarity.getDefault().encodeNormValue(0.7f)); + reader5C.setNorm(5, "field1", sim.encodeNormValue(0.7f)); assertEquals(1, reader5CCNorm.bytesRef().get()); reader5C.close(); @@ -237,7 +239,7 @@ private void createIndex(Random random, Directory dir) throws IOException { IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, anlzr).setOpenMode(OpenMode.CREATE) - .setMaxBufferedDocs(5).setSimilarity(similarityOne)); + .setMaxBufferedDocs(5).setSimilarityProvider(similarityOne)); LogMergePolicy lmp = (LogMergePolicy) iw.getConfig().getMergePolicy(); lmp.setMergeFactor(3); lmp.setUseCompoundFile(true); @@ -256,8 +258,9 @@ // System.out.println(" and: for "+k+" from "+newNorm+" to "+origNorm); modifiedNorms.set(i, Float.valueOf(newNorm)); modifiedNorms.set(k, Float.valueOf(origNorm)); - ir.setNorm(i, "f" + 1, Similarity.getDefault().encodeNormValue(newNorm)); - ir.setNorm(k, "f" + 1, Similarity.getDefault().encodeNormValue(origNorm)); + Similarity sim = new DefaultSimilarity().get("f" + 1); + ir.setNorm(i, "f" + 1, sim.encodeNormValue(newNorm)); + ir.setNorm(k, "f" + 1, sim.encodeNormValue(origNorm)); // System.out.println("setNorm i: "+i); // break; } @@ -277,7 +280,8 @@ assertEquals("number of norms mismatches", numDocNorms, b.length); ArrayList storedNorms = (i == 1 ? modifiedNorms : norms); for (int j = 0; j < b.length; j++) { - float norm = Similarity.getDefault().decodeNormValue(b[j]); + Similarity sim = new DefaultSimilarity().get(field); + float norm = sim.decodeNormValue(b[j]); float norm1 = storedNorms.get(j).floatValue(); assertEquals("stored norm value of " + field + " for doc " + j + " is " + norm + " - a mismatch!", norm, norm1, 0.000001); @@ -289,7 +293,7 @@ throws IOException { IndexWriterConfig conf = newIndexWriterConfig( TEST_VERSION_CURRENT, anlzr).setOpenMode(OpenMode.APPEND) - .setMaxBufferedDocs(5).setSimilarity(similarityOne); + .setMaxBufferedDocs(5).setSimilarityProvider(similarityOne); LogMergePolicy lmp = (LogMergePolicy) conf.getMergePolicy(); lmp.setMergeFactor(3); lmp.setUseCompoundFile(compound); @@ -316,8 +320,10 @@ private float nextNorm() { float norm = lastNorm + normDelta; do { - float norm1 = Similarity.getDefault().decodeNormValue( - Similarity.getDefault().encodeNormValue(norm)); + // bogus test, where is my field? + Similarity sim = new DefaultSimilarity().get("TODO: add field to this method"); + float norm1 = sim.decodeNormValue( + sim.encodeNormValue(norm)); if (norm1 > lastNorm) { // System.out.println(norm1+" > "+lastNorm); norm = norm1; Index: lucene/src/test/org/apache/lucene/index/TestIndexWriterConfig.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexWriterConfig.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestIndexWriterConfig.java (working copy) @@ -27,7 +27,7 @@ import org.apache.lucene.index.DocumentsWriter.IndexingChain; import org.apache.lucene.index.IndexWriterConfig.OpenMode; import org.apache.lucene.search.DefaultSimilarity; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.util.LuceneTestCase; import org.junit.Test; @@ -55,7 +55,8 @@ assertEquals(KeepOnlyLastCommitDeletionPolicy.class, conf.getIndexDeletionPolicy().getClass()); assertEquals(ConcurrentMergeScheduler.class, conf.getMergeScheduler().getClass()); assertEquals(OpenMode.CREATE_OR_APPEND, conf.getOpenMode()); - assertTrue(Similarity.getDefault() == conf.getSimilarity()); + // we don't need to assert this, it should be unspecified + assertTrue(IndexSearcher.getDefaultSimilarityProvider() == conf.getSimilarityProvider()); assertEquals(IndexWriterConfig.DEFAULT_TERM_INDEX_INTERVAL, conf.getTermIndexInterval()); assertEquals(IndexWriterConfig.getDefaultWriteLockTimeout(), conf.getWriteLockTimeout()); assertEquals(IndexWriterConfig.WRITE_LOCK_TIMEOUT, IndexWriterConfig.getDefaultWriteLockTimeout()); @@ -77,7 +78,7 @@ getters.add("getMaxFieldLength"); getters.add("getMergeScheduler"); getters.add("getOpenMode"); - getters.add("getSimilarity"); + getters.add("getSimilarityProvider"); getters.add("getTermIndexInterval"); getters.add("getWriteLockTimeout"); getters.add("getDefaultWriteLockTimeout"); @@ -173,12 +174,13 @@ conf.setMergeScheduler(null); assertEquals(ConcurrentMergeScheduler.class, conf.getMergeScheduler().getClass()); - // Test Similarity - assertTrue(Similarity.getDefault() == conf.getSimilarity()); - conf.setSimilarity(new MySimilarity()); - assertEquals(MySimilarity.class, conf.getSimilarity().getClass()); - conf.setSimilarity(null); - assertTrue(Similarity.getDefault() == conf.getSimilarity()); + // Test Similarity: + // we shouldnt assert what the default is, just that its not null. + assertTrue(IndexSearcher.getDefaultSimilarityProvider() == conf.getSimilarityProvider()); + conf.setSimilarityProvider(new MySimilarity()); + assertEquals(MySimilarity.class, conf.getSimilarityProvider().getClass()); + conf.setSimilarityProvider(null); + assertTrue(IndexSearcher.getDefaultSimilarityProvider() == conf.getSimilarityProvider()); // Test IndexingChain assertTrue(DocumentsWriter.defaultIndexingChain == conf.getIndexingChain()); Index: lucene/src/test/org/apache/lucene/index/TestMaxTermFrequency.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestMaxTermFrequency.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestMaxTermFrequency.java (working copy) @@ -46,7 +46,7 @@ dir = newDirectory(); IndexWriterConfig config = newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(MockTokenizer.SIMPLE, true)); - config.setSimilarity(new TestSimilarity()); + config.setSimilarityProvider(new TestSimilarity()); RandomIndexWriter writer = new RandomIndexWriter(random, dir, config); Document doc = new Document(); Field foo = newField("foo", "", Field.Store.NO, Field.Index.ANALYZED); Index: lucene/src/test/org/apache/lucene/index/TestOmitTf.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestOmitTf.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestOmitTf.java (working copy) @@ -35,13 +35,11 @@ public class TestOmitTf extends LuceneTestCase { - public static class SimpleSimilarity extends Similarity { + public static class SimpleSimilarity extends Similarity implements SimilarityProvider { @Override public float computeNorm(String field, FieldInvertState state) { return state.getBoost(); } - @Override public float queryNorm(float sumOfSquaredWeights) { return 1.0f; } @Override public float tf(float freq) { return freq; } @Override public float sloppyFreq(int distance) { return 2.0f; } @Override public float idf(int docFreq, int numDocs) { return 1.0f; } - @Override public float coord(int overlap, int maxOverlap) { return 1.0f; } @Override public IDFExplanation idfExplain(Collection terms, IndexSearcher searcher) throws IOException { return new IDFExplanation() { @Override @@ -54,6 +52,11 @@ } }; } + public float queryNorm(float sumOfSquaredWeights) { return 1.0f; } + public float coord(int overlap, int maxOverlap) { return 1.0f; } + public Similarity get(String field) { + return this; + } } // Tests whether the DocumentWriter correctly enable the @@ -251,7 +254,7 @@ dir, newIndexWriterConfig(TEST_VERSION_CURRENT, analyzer). setMaxBufferedDocs(2). - setSimilarity(new SimpleSimilarity()). + setSimilarityProvider(new SimpleSimilarity()). setMergePolicy(newLogMergePolicy(2)) ); @@ -281,7 +284,7 @@ * Verify the index */ IndexSearcher searcher = new IndexSearcher(dir, true); - searcher.setSimilarity(new SimpleSimilarity()); + searcher.setSimilarityProvider(new SimpleSimilarity()); Term a = new Term("noTf", term); Term b = new Term("tf", term); Index: lucene/src/test/org/apache/lucene/index/DocHelper.java =================================================================== --- lucene/src/test/org/apache/lucene/index/DocHelper.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/DocHelper.java (working copy) @@ -28,7 +28,7 @@ import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.Fieldable; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.store.Directory; import static org.apache.lucene.util.LuceneTestCase.TEST_VERSION_CURRENT; @@ -220,7 +220,7 @@ */ public static SegmentInfo writeDoc(Directory dir, Document doc) throws IOException { - return writeDoc(dir, new MockAnalyzer(MockTokenizer.WHITESPACE, false), Similarity.getDefault(), doc); + return writeDoc(dir, new MockAnalyzer(MockTokenizer.WHITESPACE, false), null, doc); } /** @@ -233,9 +233,9 @@ * @param doc * @throws IOException */ - public static SegmentInfo writeDoc(Directory dir, Analyzer analyzer, Similarity similarity, Document doc) throws IOException { + public static SegmentInfo writeDoc(Directory dir, Analyzer analyzer, SimilarityProvider similarity, Document doc) throws IOException { IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig( - TEST_VERSION_CURRENT, analyzer).setSimilarity(similarity)); + TEST_VERSION_CURRENT, analyzer).setSimilarityProvider(similarity)); //writer.setUseCompoundFile(false); writer.addDocument(doc); writer.commit(); Index: lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java (working copy) @@ -35,9 +35,11 @@ import org.apache.lucene.document.Field.Store; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriterConfig.OpenMode; +import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.Directory; @@ -615,8 +617,9 @@ IndexReader reader2 = reader1.reopen(); modifier = IndexReader.open(dir1, false); - modifier.setNorm(1, "field1", Similarity.getDefault().encodeNormValue(50f)); - modifier.setNorm(1, "field2", Similarity.getDefault().encodeNormValue(50f)); + SimilarityProvider sim = new DefaultSimilarity(); + modifier.setNorm(1, "field1", sim.get("field1").encodeNormValue(50f)); + modifier.setNorm(1, "field2", sim.get("field2").encodeNormValue(50f)); modifier.close(); IndexReader reader3 = reader2.reopen(); @@ -709,7 +712,8 @@ protected void modifyIndex(int i) throws IOException { if (i % 3 == 0) { IndexReader modifier = IndexReader.open(dir, false); - modifier.setNorm(i, "field1", Similarity.getDefault().encodeNormValue(50f)); + Similarity sim = new DefaultSimilarity().get("field1"); + modifier.setNorm(i, "field1", sim.encodeNormValue(50f)); modifier.close(); } else if (i % 3 == 1) { IndexReader modifier = IndexReader.open(dir, false); @@ -989,9 +993,10 @@ } case 1: { IndexReader reader = IndexReader.open(dir, false); - reader.setNorm(4, "field1", Similarity.getDefault().encodeNormValue(123f)); - reader.setNorm(44, "field2", Similarity.getDefault().encodeNormValue(222f)); - reader.setNorm(44, "field4", Similarity.getDefault().encodeNormValue(22f)); + SimilarityProvider sim = new DefaultSimilarity(); + reader.setNorm(4, "field1", sim.get("field1").encodeNormValue(123f)); + reader.setNorm(44, "field2", sim.get("field2").encodeNormValue(222f)); + reader.setNorm(44, "field4", sim.get("field4").encodeNormValue(22f)); reader.close(); break; } @@ -1012,8 +1017,9 @@ } case 4: { IndexReader reader = IndexReader.open(dir, false); - reader.setNorm(5, "field1", Similarity.getDefault().encodeNormValue(123f)); - reader.setNorm(55, "field2", Similarity.getDefault().encodeNormValue(222f)); + SimilarityProvider sim = new DefaultSimilarity(); + reader.setNorm(5, "field1", sim.get("field1").encodeNormValue(123f)); + reader.setNorm(55, "field2", sim.get("field2").encodeNormValue(222f)); reader.close(); break; } Index: lucene/src/test/org/apache/lucene/index/TestParallelReader.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestParallelReader.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestParallelReader.java (working copy) @@ -147,7 +147,8 @@ assertTrue(pr.isCurrent()); IndexReader modifier = IndexReader.open(dir1, false); - modifier.setNorm(0, "f1", Similarity.getDefault().encodeNormValue(100f)); + SimilarityProvider sim = new DefaultSimilarity(); + modifier.setNorm(0, "f1", sim.get("f1").encodeNormValue(100f)); modifier.close(); // one of the two IndexReaders which ParallelReader is using @@ -155,7 +156,7 @@ assertFalse(pr.isCurrent()); modifier = IndexReader.open(dir2, false); - modifier.setNorm(0, "f3", Similarity.getDefault().encodeNormValue(100f)); + modifier.setNorm(0, "f3", sim.get("f3").encodeNormValue(100f)); modifier.close(); // now both are not current anymore Index: lucene/src/test/org/apache/lucene/index/TestDeletionPolicy.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestDeletionPolicy.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestDeletionPolicy.java (working copy) @@ -30,7 +30,6 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; -import org.apache.lucene.search.Similarity; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; @@ -608,7 +607,7 @@ writer.close(); IndexReader reader = IndexReader.open(dir, policy, false); reader.deleteDocument(3*i+1); - reader.setNorm(4*i+1, "content", Similarity.getDefault().encodeNormValue(2.0F)); + reader.setNorm(4*i+1, "content", conf.getSimilarityProvider().get("content").encodeNormValue(2.0F)); IndexSearcher searcher = new IndexSearcher(reader); ScoreDoc[] hits = searcher.search(query, null, 1000).scoreDocs; assertEquals(16*(1+i), hits.length); @@ -716,7 +715,7 @@ writer.close(); IndexReader reader = IndexReader.open(dir, policy, false); reader.deleteDocument(3); - reader.setNorm(5, "content", Similarity.getDefault().encodeNormValue(2.0F)); + reader.setNorm(5, "content", conf.getSimilarityProvider().get("content").encodeNormValue(2.0F)); IndexSearcher searcher = new IndexSearcher(reader); ScoreDoc[] hits = searcher.search(query, null, 1000).scoreDocs; assertEquals(16, hits.length); Index: lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java (working copy) @@ -38,12 +38,13 @@ import org.apache.lucene.document.Fieldable; import org.apache.lucene.document.NumericField; import org.apache.lucene.index.IndexWriterConfig.OpenMode; +import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.FieldCache; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.NumericRangeQuery; import org.apache.lucene.search.ScoreDoc; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.util.Bits; @@ -424,7 +425,7 @@ Term searchTerm = new Term("id", "6"); int delCount = reader.deleteDocuments(searchTerm); assertEquals("wrong delete count", 1, delCount); - reader.setNorm(searcher.search(new TermQuery(new Term("id", "22")), 10).scoreDocs[0].doc, "content", Similarity.getDefault().encodeNormValue(2.0f)); + reader.setNorm(searcher.search(new TermQuery(new Term("id", "22")), 10).scoreDocs[0].doc, "content", searcher.getSimilarityProvider().get("content").encodeNormValue(2.0f)); reader.close(); searcher.close(); @@ -472,7 +473,7 @@ Term searchTerm = new Term("id", "6"); int delCount = reader.deleteDocuments(searchTerm); assertEquals("wrong delete count", 1, delCount); - reader.setNorm(22, "content", Similarity.getDefault().encodeNormValue(2.0f)); + reader.setNorm(22, "content", searcher.getSimilarityProvider().get("content").encodeNormValue(2.0f)); reader.close(); // make sure they "took": @@ -531,7 +532,7 @@ assertEquals("didn't delete the right number of documents", 1, delCount); // Set one norm so we get a .s0 file: - reader.setNorm(21, "content", Similarity.getDefault().encodeNormValue(1.5f)); + reader.setNorm(21, "content", conf.getSimilarityProvider().get("content").encodeNormValue(1.5f)); reader.close(); } @@ -568,7 +569,8 @@ assertEquals("didn't delete the right number of documents", 1, delCount); // Set one norm so we get a .s0 file: - reader.setNorm(21, "content", Similarity.getDefault().encodeNormValue(1.5f)); + SimilarityProvider sim = new DefaultSimilarity(); + reader.setNorm(21, "content", sim.get("content").encodeNormValue(1.5f)); reader.close(); // The numbering of fields can vary depending on which Index: lucene/src/test/org/apache/lucene/index/TestNorms.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestNorms.java (revision 1061835) +++ lucene/src/test/org/apache/lucene/index/TestNorms.java (working copy) @@ -30,6 +30,7 @@ import org.apache.lucene.index.IndexWriterConfig.OpenMode; import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; @@ -49,7 +50,7 @@ private static final int NUM_FIELDS = 10; - private Similarity similarityOne; + private SimilarityProvider similarityOne; private Analyzer anlzr; private int numDocNorms; private ArrayList norms; @@ -151,7 +152,7 @@ private void createIndex(Random random, Directory dir) throws IOException { IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, anlzr).setOpenMode(OpenMode.CREATE) - .setMaxBufferedDocs(5).setSimilarity(similarityOne)); + .setMaxBufferedDocs(5).setSimilarityProvider(similarityOne)); LogMergePolicy lmp = (LogMergePolicy) iw.getConfig().getMergePolicy(); lmp.setMergeFactor(3); lmp.setUseCompoundFile(true); @@ -169,8 +170,9 @@ //System.out.println(" and: for "+k+" from "+newNorm+" to "+origNorm); modifiedNorms.set(i, Float.valueOf(newNorm)); modifiedNorms.set(k, Float.valueOf(origNorm)); - ir.setNorm(i, "f"+1, Similarity.getDefault().encodeNormValue(newNorm)); - ir.setNorm(k, "f"+1, Similarity.getDefault().encodeNormValue(origNorm)); + Similarity sim = new DefaultSimilarity().get("f"+1); + ir.setNorm(i, "f"+1, sim.encodeNormValue(newNorm)); + ir.setNorm(k, "f"+1, sim.encodeNormValue(origNorm)); } ir.close(); } @@ -184,7 +186,7 @@ assertEquals("number of norms mismatches",numDocNorms,b.length); ArrayList storedNorms = (i==1 ? modifiedNorms : norms); for (int j = 0; j < b.length; j++) { - float norm = similarityOne.decodeNormValue(b[j]); + float norm = similarityOne.get(field).decodeNormValue(b[j]); float norm1 = storedNorms.get(j).floatValue(); assertEquals("stored norm value of "+field+" for doc "+j+" is "+norm+" - a mismatch!", norm, norm1, 0.000001); } @@ -195,7 +197,7 @@ private void addDocs(Random random, Directory dir, int ndocs, boolean compound) throws IOException { IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, anlzr).setOpenMode(OpenMode.APPEND) - .setMaxBufferedDocs(5).setSimilarity(similarityOne)); + .setMaxBufferedDocs(5).setSimilarityProvider(similarityOne)); LogMergePolicy lmp = (LogMergePolicy) iw.getConfig().getMergePolicy(); lmp.setMergeFactor(3); lmp.setUseCompoundFile(compound); @@ -221,7 +223,7 @@ private float nextNorm() { float norm = lastNorm + normDelta; do { - float norm1 = similarityOne.decodeNormValue(similarityOne.encodeNormValue(norm)); + float norm1 = similarityOne.get("bogus").decodeNormValue(similarityOne.get("bogus").encodeNormValue(norm)); if (norm1 > lastNorm) { //System.out.println(norm1+" > "+lastNorm); norm = norm1; @@ -258,7 +260,7 @@ public void testCustomEncoder() throws Exception { Directory dir = newDirectory(); IndexWriterConfig config = newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer()); - config.setSimilarity(new CustomNormEncodingSimilarity()); + config.setSimilarityProvider(new CustomNormEncodingSimilarity()); RandomIndexWriter writer = new RandomIndexWriter(random, dir, config); Document doc = new Document(); Field foo = newField("foo", "", Field.Store.NO, Field.Index.ANALYZED); Index: lucene/src/java/org/apache/lucene/search/MatchAllDocsQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/MatchAllDocsQuery.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/search/MatchAllDocsQuery.java (working copy) @@ -98,7 +98,7 @@ private float queryNorm; public MatchAllDocsWeight(IndexSearcher searcher) { - this.similarity = searcher.getSimilarity(); + this.similarity = normsField == null ? null : searcher.getSimilarityProvider().get(normsField); } @Override Index: lucene/src/java/org/apache/lucene/search/Similarity.java =================================================================== --- lucene/src/java/org/apache/lucene/search/Similarity.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/search/Similarity.java (working copy) @@ -523,39 +523,13 @@ * * * @see #setDefault(Similarity) - * @see org.apache.lucene.index.IndexWriterConfig#setSimilarity(Similarity) - * @see IndexSearcher#setSimilarity(Similarity) + * @see org.apache.lucene.index.IndexWriterConfig#setSimilarityProvider(Similarity) + * @see IndexSearcher#setSimilarityProvider(Similarity) */ public abstract class Similarity implements Serializable { - /** - * The Similarity implementation used by default. - **/ - private static Similarity defaultImpl = new DefaultSimilarity(); public static final int NO_DOC_ID_PROVIDED = -1; - /** Set the default Similarity implementation used by indexing and search - * code. - * - * @see IndexSearcher#setSimilarity(Similarity) - * @see org.apache.lucene.index.IndexWriterConfig#setSimilarity(Similarity) - */ - public static void setDefault(Similarity similarity) { - Similarity.defaultImpl = similarity; - } - - /** Return the default Similarity implementation used by indexing and search - * code. - * - *

This is initially an instance of {@link DefaultSimilarity}. - * - * @see IndexSearcher#setSimilarity(Similarity) - * @see org.apache.lucene.index.IndexWriterConfig#setSimilarity(Similarity) - */ - public static Similarity getDefault() { - return Similarity.defaultImpl; - } - /** Cache of decoded bytes. */ private static final float[] NORM_TABLE = new float[256]; @@ -632,21 +606,6 @@ throw new UnsupportedOperationException("please use computeNorm instead"); } - /** Computes the normalization value for a query given the sum of the squared - * weights of each of the query terms. This value is multiplied into the - * weight of each query term. While the classic query normalization factor is - * computed as 1/sqrt(sumOfSquaredWeights), other implementations might - * completely ignore sumOfSquaredWeights (ie return 1). - * - *

This does not affect ranking, but the default implementation does make scores - * from different queries more comparable than they would be by eliminating the - * magnitude of the Query vector as a factor in the score. - * - * @param sumOfSquaredWeights the sum of the squares of query term weights - * @return a normalization factor for query weights - */ - public abstract float queryNorm(float sumOfSquaredWeights); - /** Encodes a normalization factor for storage in an index. * *

The encoding uses a three-bit mantissa, a five-bit exponent, and @@ -816,20 +775,6 @@ */ public abstract float idf(int docFreq, int numDocs); - /** Computes a score factor based on the fraction of all query terms that a - * document contains. This value is multiplied into scores. - * - *

The presence of a large portion of the query terms indicates a better - * match with the query, so implementations of this method usually return - * larger values when the ratio between these parameters is large and smaller - * values when the ratio between them is small. - * - * @param overlap the number of query terms matched in the document - * @param maxOverlap the total number of terms in the query - * @return a score factor based on term overlap with the query - */ - public abstract float coord(int overlap, int maxOverlap); - /** * Calculate a scoring factor based on the data in the payload. Overriding implementations * are responsible for interpreting what is in the payload. Lucene makes no assumptions about Index: lucene/src/java/org/apache/lucene/search/SimilarityProvider.java =================================================================== --- lucene/src/java/org/apache/lucene/search/SimilarityProvider.java (revision 0) +++ lucene/src/java/org/apache/lucene/search/SimilarityProvider.java (revision 0) @@ -0,0 +1,66 @@ +package org.apache.lucene.search; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Expert: Scoring API. + * + * Provides top-level scoring functions that aren't specific to a field, + * and work across multi-field queries (such as {@link BooleanQuery}). + * + * Field-specific scoring is accomplished through {@link Similarity}. + * + * @lucene.experimental + */ +public interface SimilarityProvider { + + /** Computes a score factor based on the fraction of all query terms that a + * document contains. This value is multiplied into scores. + * + *

The presence of a large portion of the query terms indicates a better + * match with the query, so implementations of this method usually return + * larger values when the ratio between these parameters is large and smaller + * values when the ratio between them is small. + * + * @param overlap the number of query terms matched in the document + * @param maxOverlap the total number of terms in the query + * @return a score factor based on term overlap with the query + */ + public abstract float coord(int overlap, int maxOverlap); + + /** Computes the normalization value for a query given the sum of the squared + * weights of each of the query terms. This value is multiplied into the + * weight of each query term. While the classic query normalization factor is + * computed as 1/sqrt(sumOfSquaredWeights), other implementations might + * completely ignore sumOfSquaredWeights (ie return 1). + * + *

This does not affect ranking, but the default implementation does make scores + * from different queries more comparable than they would be by eliminating the + * magnitude of the Query vector as a factor in the score. + * + * @param sumOfSquaredWeights the sum of the squares of query term weights + * @return a normalization factor for query weights + */ + public abstract float queryNorm(float sumOfSquaredWeights); + + /** Returns a {@link Similarity} for scoring a field + * @param field field name. + * @return a field-specific Similarity. + */ + public abstract Similarity get(String field); +} Property changes on: lucene\src\java\org\apache\lucene\search\SimilarityProvider.java ___________________________________________________________________ Added: svn:eol-style + native Index: lucene/src/java/org/apache/lucene/search/spans/SpanWeight.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanWeight.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/search/spans/SpanWeight.java (working copy) @@ -42,7 +42,7 @@ public SpanWeight(SpanQuery query, IndexSearcher searcher) throws IOException { - this.similarity = searcher.getSimilarity(); + this.similarity = searcher.getSimilarityProvider().get(query.getField()); this.query = query; terms=new HashSet(); Index: lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java (working copy) @@ -137,7 +137,7 @@ public MultiPhraseWeight(IndexSearcher searcher) throws IOException { - this.similarity = searcher.getSimilarity(); + this.similarity = searcher.getSimilarityProvider().get(field); // compute idf final int maxDoc = searcher.maxDoc(); Index: lucene/src/java/org/apache/lucene/search/BooleanQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/BooleanQuery.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/search/BooleanQuery.java (working copy) @@ -162,14 +162,14 @@ */ protected class BooleanWeight extends Weight { /** The Similarity implementation. */ - protected Similarity similarity; + protected SimilarityProvider similarity; protected ArrayList weights; protected int maxCoord; // num optional + num required private final boolean disableCoord; public BooleanWeight(IndexSearcher searcher, boolean disableCoord) throws IOException { - this.similarity = searcher.getSimilarity(); + this.similarity = searcher.getSimilarityProvider(); this.disableCoord = disableCoord; weights = new ArrayList(clauses.size()); for (int i = 0 ; i < clauses.size(); i++) { Index: lucene/src/java/org/apache/lucene/search/Query.java =================================================================== --- lucene/src/java/org/apache/lucene/search/Query.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/search/Query.java (working copy) @@ -98,7 +98,7 @@ Query query = searcher.rewrite(this); Weight weight = query.createWeight(searcher); float sum = weight.sumOfSquaredWeights(); - float norm = searcher.getSimilarity().queryNorm(sum); + float norm = searcher.getSimilarityProvider().queryNorm(sum); if (Float.isInfinite(norm) || Float.isNaN(norm)) norm = 1.0f; weight.normalize(norm); Index: lucene/src/java/org/apache/lucene/search/PhraseQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/PhraseQuery.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/search/PhraseQuery.java (working copy) @@ -146,7 +146,7 @@ public PhraseWeight(IndexSearcher searcher) throws IOException { - this.similarity = searcher.getSimilarity(); + this.similarity = searcher.getSimilarityProvider().get(field); idfExp = similarity.idfExplain(terms, searcher); idf = idfExp.getIdf(); Index: lucene/src/java/org/apache/lucene/search/TermQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/TermQuery.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/search/TermQuery.java (working copy) @@ -54,7 +54,7 @@ throws IOException { assert termStates != null : "PerReaderTermState must not be null"; this.termStates = termStates; - this.similarity = searcher.getSimilarity(); + this.similarity = searcher.getSimilarityProvider().get(term.field()); if (docFreq != -1) { idfExp = similarity.idfExplain(term, searcher, docFreq); } else { Index: lucene/src/java/org/apache/lucene/search/IndexSearcher.java =================================================================== --- lucene/src/java/org/apache/lucene/search/IndexSearcher.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/search/IndexSearcher.java (working copy) @@ -70,8 +70,20 @@ private final ExecutorService executor; protected final IndexSearcher[] subSearchers; - /** The Similarity implementation used by this searcher. */ - private Similarity similarity = Similarity.getDefault(); + // the default SimilarityProvider + private static final SimilarityProvider defaultProvider = new DefaultSimilarity(); + + /** + * Expert: returns a default SimilarityProvider instance. + * In general, this should not be used. + * @lucene.internal + */ + public static SimilarityProvider getDefaultSimilarityProvider() { + return defaultProvider; + } + + /** The SimilarityProvider implementation used by this searcher. */ + private SimilarityProvider similarityProvider = defaultProvider; /** Creates a searcher searching the index in the named * directory, with readOnly=true @@ -248,16 +260,15 @@ return reader.document(docID, fieldSelector); } - /** Expert: Set the Similarity implementation used by this Searcher. + /** Expert: Set the SimilarityProvider implementation used by this Searcher. * - * @see Similarity#setDefault(Similarity) */ - public void setSimilarity(Similarity similarity) { - this.similarity = similarity; + public void setSimilarityProvider(SimilarityProvider similarityProvider) { + this.similarityProvider = similarityProvider; } - public Similarity getSimilarity() { - return similarity; + public SimilarityProvider getSimilarityProvider() { + return similarityProvider; } /** Index: lucene/src/java/org/apache/lucene/search/DefaultSimilarity.java =================================================================== --- lucene/src/java/org/apache/lucene/search/DefaultSimilarity.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/search/DefaultSimilarity.java (working copy) @@ -20,7 +20,7 @@ */ /** Expert: Default scoring implementation. */ -public class DefaultSimilarity extends Similarity { +public class DefaultSimilarity extends Similarity implements SimilarityProvider { /** Implemented as * state.getBoost()*lengthNorm(numTerms), where @@ -41,7 +41,6 @@ } /** Implemented as 1/sqrt(sumOfSquaredWeights). */ - @Override public float queryNorm(float sumOfSquaredWeights) { return (float)(1.0 / Math.sqrt(sumOfSquaredWeights)); } @@ -65,7 +64,6 @@ } /** Implemented as overlap / maxOverlap. */ - @Override public float coord(int overlap, int maxOverlap) { return overlap / (float)maxOverlap; } @@ -90,4 +88,12 @@ public boolean getDiscountOverlaps() { return discountOverlaps; } + + /** + * Returns this default implementation for all fields. + * Override this method to customize scoring on a per-field basis. + */ + public Similarity get(String field) { + return this; + } } Index: lucene/src/java/org/apache/lucene/index/NormsWriterPerField.java =================================================================== --- lucene/src/java/org/apache/lucene/index/NormsWriterPerField.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/index/NormsWriterPerField.java (working copy) @@ -17,6 +17,7 @@ * limitations under the License. */ +import org.apache.lucene.search.Similarity; import org.apache.lucene.util.ArrayUtil; /** Taps into DocInverter, as an InvertedDocEndConsumer, @@ -29,7 +30,8 @@ final NormsWriterPerThread perThread; final FieldInfo fieldInfo; final DocumentsWriter.DocState docState; - + final Similarity similarity; + // Holds all docID/norm pairs we've seen int[] docIDs = new int[1]; byte[] norms = new byte[1]; @@ -49,6 +51,7 @@ this.fieldInfo = fieldInfo; docState = perThread.docState; fieldState = docInverterPerField.fieldState; + similarity = docState.similarity.get(fieldInfo.name); } @Override @@ -71,8 +74,8 @@ assert norms.length == upto; norms = ArrayUtil.grow(norms, 1+upto); } - final float norm = docState.similarity.computeNorm(fieldInfo.name, fieldState); - norms[upto] = docState.similarity.encodeNormValue(norm); + final float norm = similarity.computeNorm(fieldInfo.name, fieldState); + norms[upto] = similarity.encodeNormValue(norm); docIDs[upto] = docState.docID; upto++; } Index: lucene/src/java/org/apache/lucene/index/DocumentsWriter.java =================================================================== --- lucene/src/java/org/apache/lucene/index/DocumentsWriter.java (revision 1061835) +++ lucene/src/java/org/apache/lucene/index/DocumentsWriter.java (working copy) @@ -30,7 +30,7 @@ import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.Document; import org.apache.lucene.search.Query; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.Directory; import org.apache.lucene.store.RAMFile; @@ -127,7 +127,7 @@ private boolean aborting; // True if an abort is pending PrintStream infoStream; - Similarity similarity; + SimilarityProvider similarity; // max # simultaneous threads; if there are more than // this, they wait for others to finish first @@ -140,7 +140,7 @@ DocumentsWriter docWriter; Analyzer analyzer; PrintStream infoStream; - Similarity similarity; + SimilarityProvider similarity; int docID; Document doc; String maxTermPrefix; @@ -284,7 +284,7 @@ DocumentsWriter(Directory directory, IndexWriter writer, IndexingChain indexingChain, int maxThreadStates, FieldInfos fieldInfos, BufferedDeletes bufferedDeletes) throws IOException { this.directory = directory; this.writer = writer; - this.similarity = writer.getConfig().getSimilarity(); + this.similarity = writer.getConfig().getSimilarityProvider(); this.maxThreadStates = maxThreadStates; this.fieldInfos = fieldInfos; this.bufferedDeletes = bufferedDeletes; @@ -357,7 +357,7 @@ } } - synchronized void setSimilarity(Similarity similarity) { + synchronized void setSimilarity(SimilarityProvider similarity) { this.similarity = similarity; for(int i=0;i * NOTE: the similarity cannot be null. If null is passed, - * the similarity will be set to the default. - * - * @see Similarity#setDefault(Similarity) + * the similarity will be set to the default implementation (unspecified). */ - public IndexWriterConfig setSimilarity(Similarity similarity) { - this.similarity = similarity == null ? Similarity.getDefault() : similarity; + public IndexWriterConfig setSimilarityProvider(SimilarityProvider similarityProvider) { + this.similarityProvider = similarityProvider == null ? IndexSearcher.getDefaultSimilarityProvider() : similarityProvider; return this; } /** - * Expert: returns the {@link Similarity} implementation used by this - * IndexWriter. This defaults to the current value of - * {@link Similarity#getDefault()}. + * Expert: returns the {@link SimilarityProvider} implementation used by this + * IndexWriter. */ - public Similarity getSimilarity() { - return similarity; + public SimilarityProvider getSimilarityProvider() { + return similarityProvider; } /** @@ -576,7 +574,7 @@ sb.append("delPolicy=").append(delPolicy.getClass().getName()).append("\n"); sb.append("commit=").append(commit == null ? "null" : commit).append("\n"); sb.append("openMode=").append(openMode).append("\n"); - sb.append("similarity=").append(similarity.getClass().getName()).append("\n"); + sb.append("similarityProvider=").append(similarityProvider.getClass().getName()).append("\n"); sb.append("termIndexInterval=").append(termIndexInterval).append("\n"); // TODO: this should be private to the codec, not settable here sb.append("mergeScheduler=").append(mergeScheduler.getClass().getName()).append("\n"); sb.append("default WRITE_LOCK_TIMEOUT=").append(WRITE_LOCK_TIMEOUT).append("\n"); Index: lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/nodes/StandardBooleanQueryNode.java =================================================================== --- lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/nodes/StandardBooleanQueryNode.java (revision 1061835) +++ lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/nodes/StandardBooleanQueryNode.java (working copy) @@ -22,7 +22,7 @@ import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; import org.apache.lucene.queryParser.core.nodes.QueryNode; import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; /** * A {@link StandardBooleanQueryNode} has the same behavior as Index: lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/builders/StandardBooleanQueryNodeBuilder.java =================================================================== --- lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/builders/StandardBooleanQueryNodeBuilder.java (revision 1061835) +++ lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/builders/StandardBooleanQueryNodeBuilder.java (working copy) @@ -31,7 +31,7 @@ import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.search.BooleanQuery.TooManyClauses; /** Index: lucene/contrib/instantiated/src/java/org/apache/lucene/store/instantiated/InstantiatedIndexWriter.java =================================================================== --- lucene/contrib/instantiated/src/java/org/apache/lucene/store/instantiated/InstantiatedIndexWriter.java (revision 1061835) +++ lucene/contrib/instantiated/src/java/org/apache/lucene/store/instantiated/InstantiatedIndexWriter.java (working copy) @@ -42,7 +42,8 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermVectorOffsetInfo; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.util.StringHelper; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.CollectionUtil; @@ -67,7 +68,7 @@ private final InstantiatedIndex index; private final Analyzer analyzer; - private Similarity similarity = Similarity.getDefault(); // how to normalize; + private SimilarityProvider similarity = IndexSearcher.getDefaultSimilarityProvider(); // how to normalize; private transient Set fieldNameBuffer; /** @@ -236,11 +237,12 @@ termsInDocument += eFieldTermDocInfoFactoriesByTermText.getValue().size(); if (eFieldTermDocInfoFactoriesByTermText.getKey().indexed && !eFieldTermDocInfoFactoriesByTermText.getKey().omitNorms) { + final String fieldName = eFieldTermDocInfoFactoriesByTermText.getKey().fieldName; final FieldInvertState invertState = new FieldInvertState(); invertState.setBoost(eFieldTermDocInfoFactoriesByTermText.getKey().boost * document.getDocument().getBoost()); invertState.setLength(eFieldTermDocInfoFactoriesByTermText.getKey().fieldLength); - final float norm = similarity.computeNorm(eFieldTermDocInfoFactoriesByTermText.getKey().fieldName, invertState); - normsByFieldNameAndDocumentNumber.get(eFieldTermDocInfoFactoriesByTermText.getKey().fieldName)[document.getDocumentNumber()] = similarity.encodeNormValue(norm); + final float norm = similarity.get(fieldName).computeNorm(fieldName, invertState); + normsByFieldNameAndDocumentNumber.get(fieldName)[document.getDocumentNumber()] = similarity.get(fieldName).encodeNormValue(norm); } else { System.currentTimeMillis(); } @@ -659,11 +661,11 @@ addDocument(doc, analyzer); } - public Similarity getSimilarity() { + public SimilarityProvider getSimilarity() { return similarity; } - public void setSimilarity(Similarity similarity) { + public void setSimilarity(SimilarityProvider similarity) { this.similarity = similarity; } Index: lucene/contrib/misc/src/test/org/apache/lucene/index/TestFieldNormModifier.java =================================================================== --- lucene/contrib/misc/src/test/org/apache/lucene/index/TestFieldNormModifier.java (revision 1061835) +++ lucene/contrib/misc/src/test/org/apache/lucene/index/TestFieldNormModifier.java (working copy) @@ -28,7 +28,7 @@ import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Scorer; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; @@ -42,7 +42,7 @@ public Directory store; /** inverts the normal notion of lengthNorm */ - public static Similarity s = new DefaultSimilarity() { + public static SimilarityProvider s = new DefaultSimilarity() { @Override public float computeNorm(String fieldName, FieldInvertState state) { return state.getBoost() * (discountOverlaps ? state.getLength() - state.getNumOverlap() : state.getLength()); Index: lucene/contrib/misc/src/test/org/apache/lucene/misc/TestLengthNormModifier.java =================================================================== --- lucene/contrib/misc/src/test/org/apache/lucene/misc/TestLengthNormModifier.java (revision 1061835) +++ lucene/contrib/misc/src/test/org/apache/lucene/misc/TestLengthNormModifier.java (working copy) @@ -33,7 +33,7 @@ import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Scorer; -import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; @@ -47,7 +47,7 @@ public Directory store; /** inverts the normal notion of lengthNorm */ - public static Similarity s = new DefaultSimilarity() { + public static SimilarityProvider s = new DefaultSimilarity() { @Override public float computeNorm(String fieldName, FieldInvertState state) { return state.getBoost() * (discountOverlaps ? state.getLength() - state.getNumOverlap() : state.getLength()); @@ -163,7 +163,7 @@ } // override the norms to be inverted - Similarity s = new DefaultSimilarity() { + SimilarityProvider s = new DefaultSimilarity() { @Override public float computeNorm(String fieldName, FieldInvertState state) { return state.getBoost() * (discountOverlaps ? state.getLength() - state.getNumOverlap() : state.getLength()); Index: lucene/contrib/misc/src/java/org/apache/lucene/index/FieldNormModifier.java =================================================================== --- lucene/contrib/misc/src/java/org/apache/lucene/index/FieldNormModifier.java (revision 1061835) +++ lucene/contrib/misc/src/java/org/apache/lucene/index/FieldNormModifier.java (working copy) @@ -24,6 +24,7 @@ import org.apache.lucene.search.DefaultSimilarity; import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.StringHelper; @@ -57,13 +58,13 @@ System.exit(1); } - Similarity s = null; + SimilarityProvider s = null; if (args[1].equals("-d")) args[1] = DefaultSimilarity.class.getName(); try { - s = Class.forName(args[1]).asSubclass(Similarity.class).newInstance(); + s = Class.forName(args[1]).asSubclass(SimilarityProvider.class).newInstance(); } catch (Exception e) { System.err.println("Couldn't instantiate similarity with empty constructor: " + args[1]); e.printStackTrace(System.err); @@ -84,7 +85,7 @@ private Directory dir; - private Similarity sim; + private SimilarityProvider sim; /** * Constructor for code that wishes to use this class programmatically @@ -93,7 +94,7 @@ * @param d the Directory to modify * @param s the Similarity to use (can be null) */ - public FieldNormModifier(Directory d, Similarity s) { + public FieldNormModifier(Directory d, SimilarityProvider s) { dir = d; sim = s; } @@ -111,7 +112,7 @@ */ public void reSetNorms(String field) throws IOException { String fieldName = StringHelper.intern(field); - + Similarity fieldSim = sim.get(field); IndexReader reader = null; try { reader = IndexReader.open(dir, false); @@ -148,7 +149,7 @@ for (int d = 0; d < termCounts.length; d++) { if (delDocs == null || !delDocs.get(d)) { invertState.setLength(termCounts[d]); - subReader.setNorm(d, fieldName, sim.encodeNormValue(sim.computeNorm(fieldName, invertState))); + subReader.setNorm(d, fieldName, fieldSim.encodeNormValue(fieldSim.computeNorm(fieldName, invertState))); } } } Index: lucene/contrib/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java =================================================================== --- lucene/contrib/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java (revision 1061835) +++ lucene/contrib/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java (working copy) @@ -57,6 +57,7 @@ import org.apache.lucene.search.Query; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.SimilarityProvider; import org.apache.lucene.store.RAMDirectory; // for javadocs import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.BytesRef; @@ -1169,9 +1170,9 @@ }; } - private Similarity getSimilarity() { - if (searcher != null) return searcher.getSimilarity(); - return Similarity.getDefault(); + private SimilarityProvider getSimilarity() { + if (searcher != null) return searcher.getSimilarityProvider(); + return IndexSearcher.getDefaultSimilarityProvider(); } private void setSearcher(IndexSearcher searcher) { @@ -1181,20 +1182,21 @@ /** performance hack: cache norms to avoid repeated expensive calculations */ private byte[] cachedNorms; private String cachedFieldName; - private Similarity cachedSimilarity; + private SimilarityProvider cachedSimilarity; @Override public byte[] norms(String fieldName) { byte[] norms = cachedNorms; - Similarity sim = getSimilarity(); + SimilarityProvider sim = getSimilarity(); if (fieldName != cachedFieldName || sim != cachedSimilarity) { // not cached? Info info = getInfo(fieldName); + Similarity fieldSim = sim.get(fieldName); int numTokens = info != null ? info.numTokens : 0; int numOverlapTokens = info != null ? info.numOverlapTokens : 0; float boost = info != null ? info.getBoost() : 1.0f; FieldInvertState invertState = new FieldInvertState(0, numTokens, numOverlapTokens, 0, boost); - float n = sim.computeNorm(fieldName, invertState); - byte norm = sim.encodeNormValue(n); + float n = fieldSim.computeNorm(fieldName, invertState); + byte norm = fieldSim.encodeNormValue(n); norms = new byte[] {norm}; // cache it for future reuse Index: lucene/MIGRATE.txt =================================================================== --- lucene/MIGRATE.txt (revision 1061835) +++ lucene/MIGRATE.txt (working copy) @@ -331,3 +331,8 @@ toString() is no longer implemented by AttributeImpl, so if you have overridden toString(), port your customization over to reflectWith(). reflectAsString() would then return what toString() did before. + +* LUCENE-2236: Similarity can now be configured on a per-field basis, this means that + IndexWriterConfig and IndexSearcher now take a SimilarityProvider. Similarity retains + only the field-specific relevance methods: coord() and queryNorm() apply to the entire + query and exist in SimilarityProvider.