org.apache.solr.search.similarities.SchemaSimilarityFactory Maven / Gradle / Ivy
Show all versions of solr-core Show documentation
/*
* 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.
*/
package org.apache.solr.search.similarities;
import org.apache.lucene.search.similarities.BM25Similarity;
import org.apache.lucene.search.similarities.PerFieldSimilarityWrapper;
import org.apache.lucene.search.similarities.Similarity;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.core.SolrCore;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.SimilarityFactory;
import org.apache.solr.util.plugin.SolrCoreAware;
/**
* SimilarityFactory
that returns a global {@link PerFieldSimilarityWrapper} that
* delegates to the field type, if it's configured. For field types that do not have a
* Similarity
explicitly configured, the global Similarity
will use per
* fieldtype defaults -- either based on an explicitly configured defaultSimFromFieldType
*
a sensible default:
*
*
* luceneMatchVersion >= 8.0
= {@link BM25Similarity}
*
*
* The defaultSimFromFieldType
option accepts the name of any fieldtype, and uses
* whatever Similarity
is explicitly configured for that fieldType as the default for
* all other field types. For example:
*
*
* <similarity class="solr.SchemaSimilarityFactory" >
* <str name="defaultSimFromFieldType">type-using-custom-dfr</str>
* </similarity>
* ...
* <fieldType name="type-using-custom-dfr" class="solr.TextField">
* ...
* <similarity class="solr.DFRSimilarityFactory">
* <str name="basicModel">I(F)</str>
* <str name="afterEffect">B</str>
* <str name="normalization">H3</str>
* <float name="mu">900</float>
* </similarity>
* </fieldType>
*
*
* In the example above, any fieldtypes that do not define their own </similarity/>
*
will use the Similarity
configured for the type-using-custom-dfr
*
.
*
*
NOTE: Users should be aware that even when this factory uses a single default
* Similarity
for some or all fields in a Query, the behavior can be inconsistent with the
* behavior of explicitly configuring that same Similarity
globally, because of
* differences in how some multi-field / multi-clause behavior is defined in
* PerFieldSimilarityWrapper
.
*
* @see FieldType#getSimilarity
*/
public class SchemaSimilarityFactory extends SimilarityFactory implements SolrCoreAware {
private static final String INIT_OPT = "defaultSimFromFieldType";
private String defaultSimFromFieldType; // set by init, if null use sensible implicit default
private volatile SolrCore core; // set by inform(SolrCore)
private volatile Similarity similarity; // lazy instantiated
@Override
public void inform(SolrCore core) {
this.core = core;
}
@Override
public void init(SolrParams args) {
defaultSimFromFieldType = args.get(INIT_OPT, null);
super.init(args);
}
@Override
public Similarity getSimilarity() {
if (null == core) {
throw new IllegalStateException(
"SchemaSimilarityFactory can not be used until SolrCoreAware.inform has been called");
}
if (null == similarity) {
// Need to instantiate lazily, can't do this in inform(SolrCore) because of chicken/egg
// circular initialization hell with core.getLatestSchema() to lookup defaultSimFromFieldType
Similarity defaultSim = null;
if (null == defaultSimFromFieldType) {
// nothing configured, choose a sensible implicit default...
defaultSim = new BM25Similarity();
} else {
FieldType defSimFT = core.getLatestSchema().getFieldTypeByName(defaultSimFromFieldType);
if (null == defSimFT) {
throw new SolrException(
ErrorCode.SERVER_ERROR,
"SchemaSimilarityFactory configured with "
+ INIT_OPT
+ "='"
+ defaultSimFromFieldType
+ "' but that does not exist");
}
defaultSim = defSimFT.getSimilarity();
if (null == defaultSim) {
throw new SolrException(
ErrorCode.SERVER_ERROR,
"SchemaSimilarityFactory configured with "
+ INIT_OPT
+ "='"
+ defaultSimFromFieldType
+ "' but that does not define a ");
}
}
similarity = new SchemaSimilarity(defaultSim);
}
return similarity;
}
private class SchemaSimilarity extends PerFieldSimilarityWrapper {
private Similarity defaultSimilarity;
public SchemaSimilarity(Similarity defaultSimilarity) {
this.defaultSimilarity = defaultSimilarity;
}
@Override
public Similarity get(String name) {
FieldType fieldType = core.getLatestSchema().getFieldTypeNoEx(name);
if (fieldType == null) {
return defaultSimilarity;
} else {
Similarity similarity = fieldType.getSimilarity();
return similarity == null ? defaultSimilarity : similarity;
}
}
@Override
public String toString() {
return "SchemaSimilarity. Default: " + ((get("") == null) ? "null" : get("").toString());
}
}
}