SOLR-4658:

- Fix class name shortening issues, for SimilarityFactory's, FieldType's, and analysis factories: persisted class names' original forms are preserved in both shortened form (e.g. 'solr.TextField') and fully qualified form (e.g. 'org.apache.solr.schema.TextField')
- luceneMatchVersion on analysis factories is now persisted only when explicitly specified in the original; previously the default value was persisted when it was absent in the original
- Add MockTokenFilterFactory

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1466720 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Steven Rowe 2013-04-10 22:36:19 +00:00
parent faf6419c2b
commit c91f22b0b0
12 changed files with 422 additions and 48 deletions

View File

@ -51,20 +51,24 @@ import java.util.regex.PatternSyntaxException;
* </ol>
*/
public abstract class AbstractAnalysisFactory {
public static final String LUCENE_MATCH_VERSION_PARAM = "luceneMatchVersion";
/** The original args, before any processing */
private final Map<String,String> originalArgs;
/** the luceneVersion arg */
protected final Version luceneMatchVersion;
/** whether the luceneMatchVersion arg is explicitly specified in the serialized schema */
private boolean isExplicitLuceneMatchVersion = false;
/**
* Initialize this factory via a set of key-value pairs.
*/
protected AbstractAnalysisFactory(Map<String,String> args) {
originalArgs = Collections.unmodifiableMap(new HashMap<String,String>(args));
String version = get(args, "luceneMatchVersion");
String version = get(args, LUCENE_MATCH_VERSION_PARAM);
luceneMatchVersion = version == null ? null : Version.parseLeniently(version);
args.remove(CLASS_NAME); // consume the class arg
}
public final Map<String,String> getOriginalArgs() {
@ -299,4 +303,28 @@ public abstract class AbstractAnalysisFactory {
return result;
}
private static final String CLASS_NAME = "class";
/**
* @return the string used to specify the concrete class name in a serialized representation: the class arg.
* If the concrete class name was not specified via a class arg, returns {@code getClass().getName()}.
*/
public String getClassArg() {
if (null != originalArgs) {
String className = originalArgs.get(CLASS_NAME);
if (null != className) {
return className;
}
}
return getClass().getName();
}
public boolean isExplicitLuceneMatchVersion() {
return isExplicitLuceneMatchVersion;
}
public void setExplicitLuceneMatchVersion(boolean isExplicitLuceneMatchVersion) {
this.isExplicitLuceneMatchVersion = isExplicitLuceneMatchVersion;
}
}

View File

@ -49,6 +49,7 @@ public abstract class AbstractSubTypeFieldType extends FieldType implements Sche
@Override
protected void init(IndexSchema schema, Map<String, String> args) {
super.init(schema, args);
this.schema = schema;
//it's not a first class citizen for the IndexSchema
SolrParams p = new MapSolrParams(args);

View File

@ -26,8 +26,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.lucene.analysis.util.AbstractAnalysisFactory.LUCENE_MATCH_VERSION_PARAM;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.Tokenizer;
@ -95,7 +95,6 @@ public abstract class FieldType extends FieldProperties {
private boolean isExplicitQueryAnalyzer;
private boolean isExplicitAnalyzer;
/** Returns true if fields of this type should be tokenized */
public boolean isTokenized() {
return (properties & TOKENIZED) != 0;
@ -152,6 +151,7 @@ public abstract class FieldType extends FieldProperties {
this.args = Collections.unmodifiableMap(args);
Map<String,String> initArgs = new HashMap<String,String>(args);
initArgs.remove(CLASS_NAME); // consume the class arg
trueProperties = FieldProperties.parseProperties(initArgs,true,false);
falseProperties = FieldProperties.parseProperties(initArgs,false,false);
@ -413,7 +413,21 @@ public abstract class FieldType extends FieldProperties {
return isExplicitAnalyzer;
}
/**
/**
* @return the string used to specify the concrete class name in a serialized representation: the class arg.
* If the concrete class name was not specified via a class arg, returns {@code getClass().getName()}.
*/
public String getClassArg() {
if (null != args) {
String className = args.get(CLASS_NAME);
if (null != className) {
return className;
}
}
return getClass().getName();
}
/**
* Default analyzer for types that only produce 1 verbatim token...
* A maximum size of chars to be read must be specified
*/
@ -752,12 +766,14 @@ public abstract class FieldType extends FieldProperties {
public SimpleOrderedMap<Object> getNamedPropertyValues(boolean showDefaults) {
SimpleOrderedMap<Object> namedPropertyValues = new SimpleOrderedMap<Object>();
namedPropertyValues.add(TYPE_NAME, getTypeName());
namedPropertyValues.add(CLASS_NAME, getShortName(getClass().getName()));
namedPropertyValues.add(CLASS_NAME, getClassArg());
if (showDefaults) {
Map<String,String> fieldTypeArgs = getNonFieldPropertyArgs();
if (null != fieldTypeArgs) {
for (String key : fieldTypeArgs.keySet()) {
namedPropertyValues.add(key, fieldTypeArgs.get(key));
if ( ! CLASS_NAME.equals(key) && ! TYPE_NAME.equals(key)) {
namedPropertyValues.add(key, fieldTypeArgs.get(key));
}
}
}
if (this instanceof TextField) {
@ -790,7 +806,7 @@ public abstract class FieldType extends FieldProperties {
for (String key : args.keySet()) {
if (fieldProperties.contains(key)) {
namedPropertyValues.add(key, StrUtils.parseBool(args.get(key)));
} else {
} else if ( ! CLASS_NAME.equals(key) && ! TYPE_NAME.equals(key)) {
namedPropertyValues.add(key, args.get(key));
}
}
@ -846,11 +862,19 @@ public abstract class FieldType extends FieldProperties {
List<SimpleOrderedMap<Object>> charFilterProps = new ArrayList<SimpleOrderedMap<Object>>();
for (CharFilterFactory charFilterFactory : charFilterFactories) {
SimpleOrderedMap<Object> props = new SimpleOrderedMap<Object>();
props.add(CLASS_NAME, getShortName(charFilterFactory.getClass().getName()));
props.add(CLASS_NAME, charFilterFactory.getClassArg());
factoryArgs = charFilterFactory.getOriginalArgs();
if (null != factoryArgs) {
for (String key : factoryArgs.keySet()) {
props.add(key, factoryArgs.get(key));
if ( ! CLASS_NAME.equals(key)) {
if (LUCENE_MATCH_VERSION_PARAM.equals(key)) {
if (charFilterFactory.isExplicitLuceneMatchVersion()) {
props.add(key, factoryArgs.get(key));
}
} else {
props.add(key, factoryArgs.get(key));
}
}
}
}
charFilterProps.add(props);
@ -860,11 +884,19 @@ public abstract class FieldType extends FieldProperties {
SimpleOrderedMap<Object> tokenizerProps = new SimpleOrderedMap<Object>();
TokenizerFactory tokenizerFactory = tokenizerChain.getTokenizerFactory();
tokenizerProps.add(CLASS_NAME, getShortName(tokenizerFactory.getClass().getName()));
tokenizerProps.add(CLASS_NAME, tokenizerFactory.getClassArg());
factoryArgs = tokenizerFactory.getOriginalArgs();
if (null != factoryArgs) {
for (String key : factoryArgs.keySet()) {
tokenizerProps.add(key, factoryArgs.get(key));
if ( ! CLASS_NAME.equals(key)) {
if (LUCENE_MATCH_VERSION_PARAM.equals(key)) {
if (tokenizerFactory.isExplicitLuceneMatchVersion()) {
tokenizerProps.add(key, factoryArgs.get(key));
}
} else {
tokenizerProps.add(key, factoryArgs.get(key));
}
}
}
}
analyzerProps.add(TOKENIZER, tokenizerProps);
@ -874,11 +906,19 @@ public abstract class FieldType extends FieldProperties {
List<SimpleOrderedMap<Object>> filterProps = new ArrayList<SimpleOrderedMap<Object>>();
for (TokenFilterFactory filterFactory : filterFactories) {
SimpleOrderedMap<Object> props = new SimpleOrderedMap<Object>();
props.add(CLASS_NAME, getShortName(filterFactory.getClass().getName()));
props.add(CLASS_NAME, filterFactory.getClassArg());
factoryArgs = filterFactory.getOriginalArgs();
if (null != factoryArgs) {
for (String key : factoryArgs.keySet()) {
props.add(key, factoryArgs.get(key));
if ( ! CLASS_NAME.equals(key)) {
if (LUCENE_MATCH_VERSION_PARAM.equals(key)) {
if (filterFactory.isExplicitLuceneMatchVersion()) {
props.add(key, factoryArgs.get(key));
}
} else {
props.add(key, factoryArgs.get(key));
}
}
}
}
filterProps.add(props);
@ -890,12 +930,4 @@ public abstract class FieldType extends FieldProperties {
}
return analyzerProps;
}
private static final Pattern SHORTENABLE_PACKAGE_PATTERN
= Pattern.compile("org\\.apache\\.(?:lucene\\.analysis(?=.).*|solr\\.(?:analysis|schema))\\.([^.]+)$");
private static String getShortName(String fullyQualifiedName) {
Matcher matcher = SHORTENABLE_PACKAGE_PATTERN.matcher(fullyQualifiedName);
return matcher.matches() ? "solr." + matcher.group(1) : fullyQualifiedName;
}
}

View File

@ -137,11 +137,10 @@ public final class FieldTypePluginLoader
@Override
protected void init(FieldType plugin, Node node) throws Exception {
Map<String,String> params = DOMUtil.toMapExcept( node.getAttributes(),
"name","class" );
plugin.setArgs(schema, params );
Map<String,String> params = DOMUtil.toMapExcept( node.getAttributes(), "name");
plugin.setArgs(schema, params);
}
@Override
protected FieldType register(String name,
FieldType plugin) throws Exception {
@ -301,10 +300,12 @@ public final class FieldTypePluginLoader
@Override
protected CharFilterFactory create(SolrResourceLoader loader, String name, String className, Node node) throws Exception {
final Map<String,String> params = DOMUtil.toMapExcept(node.getAttributes(),"class");
final Map<String,String> params = DOMUtil.toMap(node.getAttributes());
String configuredVersion = params.remove(LUCENE_MATCH_VERSION_PARAM);
params.put(LUCENE_MATCH_VERSION_PARAM, parseConfiguredVersion(configuredVersion, CharFilterFactory.class.getSimpleName()).toString());
return loader.newInstance(className, CharFilterFactory.class, getDefaultPackages(), new Class[] { Map.class }, new Object[] { params });
CharFilterFactory factory = loader.newInstance(className, CharFilterFactory.class, getDefaultPackages(), new Class[] { Map.class }, new Object[] { params });
factory.setExplicitLuceneMatchVersion(null != configuredVersion);
return factory;
}
@Override
@ -335,10 +336,12 @@ public final class FieldTypePluginLoader
@Override
protected TokenizerFactory create(SolrResourceLoader loader, String name, String className, Node node) throws Exception {
final Map<String,String> params = DOMUtil.toMapExcept(node.getAttributes(),"class");
final Map<String,String> params = DOMUtil.toMap(node.getAttributes());
String configuredVersion = params.remove(LUCENE_MATCH_VERSION_PARAM);
params.put(LUCENE_MATCH_VERSION_PARAM, parseConfiguredVersion(configuredVersion, TokenizerFactory.class.getSimpleName()).toString());
return loader.newInstance(className, TokenizerFactory.class, getDefaultPackages(), new Class[] { Map.class }, new Object[] { params });
TokenizerFactory factory = loader.newInstance(className, TokenizerFactory.class, getDefaultPackages(), new Class[] { Map.class }, new Object[] { params });
factory.setExplicitLuceneMatchVersion(null != configuredVersion);
return factory;
}
@Override
@ -373,10 +376,13 @@ public final class FieldTypePluginLoader
{
@Override
protected TokenFilterFactory create(SolrResourceLoader loader, String name, String className, Node node) throws Exception {
final Map<String,String> params = DOMUtil.toMapExcept(node.getAttributes(),"class");
final Map<String,String> params = DOMUtil.toMap(node.getAttributes());
String configuredVersion = params.remove(LUCENE_MATCH_VERSION_PARAM);
params.put(LUCENE_MATCH_VERSION_PARAM, parseConfiguredVersion(configuredVersion, TokenFilterFactory.class.getSimpleName()).toString());
return loader.newInstance(className, TokenFilterFactory.class, getDefaultPackages(), new Class[] { Map.class }, new Object[] { params });
TokenFilterFactory factory = loader.newInstance
(className, TokenFilterFactory.class, getDefaultPackages(), new Class[] { Map.class }, new Object[] { params });
factory.setExplicitLuceneMatchVersion(null != configuredVersion);
return factory;
}
@Override

View File

@ -890,10 +890,13 @@ public class IndexSchema {
return null;
} else {
SimilarityFactory similarityFactory;
final Object obj = loader.newInstance(((Element) node).getAttribute("class"), Object.class, "search.similarities.");
final String classArg = ((Element) node).getAttribute(SimilarityFactory.CLASS_NAME);
final Object obj = loader.newInstance(classArg, Object.class, "search.similarities.");
if (obj instanceof SimilarityFactory) {
// configure a factory, get a similarity back
SolrParams params = SolrParams.toSolrParams(DOMUtil.childNodesToNamedList(node));
final NamedList<Object> namedList = DOMUtil.childNodesToNamedList(node);
namedList.add(SimilarityFactory.CLASS_NAME, classArg);
SolrParams params = SolrParams.toSolrParams(namedList);
similarityFactory = (SimilarityFactory)obj;
similarityFactory.init(params);
} else {

View File

@ -40,7 +40,6 @@ import java.util.Iterator;
*/
public abstract class SimilarityFactory {
public static final String CLASS_NAME = "class";
private static final String SOLR_SIMILARITIES_PACKAGE = "org.apache.solr.search.similarities";
protected SolrParams params;
@ -52,25 +51,38 @@ public abstract class SimilarityFactory {
/** Returns a serializable description of this similarity(factory) */
public SimpleOrderedMap<Object> getNamedPropertyValues() {
String className = getClass().getName();
if (className.startsWith("org.apache.solr.schema.IndexSchema$")) {
// If this class is just a no-params wrapper around a similarity class, use the similarity class
className = getSimilarity().getClass().getName();
} else {
// Only shorten factory names
if (className.startsWith(SOLR_SIMILARITIES_PACKAGE + ".")) {
className = className.replace(SOLR_SIMILARITIES_PACKAGE, "solr");
}
}
SimpleOrderedMap<Object> props = new SimpleOrderedMap<Object>();
props.add(CLASS_NAME, className);
props.add(CLASS_NAME, getClassArg());
if (null != params) {
Iterator<String> iter = params.getParameterNamesIterator();
while (iter.hasNext()) {
String key = iter.next();
props.add(key, params.get(key));
if ( ! CLASS_NAME.equals(key)) {
props.add(key, params.get(key));
}
}
}
return props;
}
/**
* @return the string used to specify the concrete class name in a serialized representation: the class arg.
* If the concrete class name was not specified via a class arg, returns {@code getClass().getName()},
* unless this class is the anonymous similarity wrapper produced in {@link IndexSchema}, in which
* case the {@code getSimilarity().getClass().getName()} is returned.
*/
public String getClassArg() {
if (null != params) {
String className = params.get(CLASS_NAME);
if (null != className) {
return className;
}
}
String className = getClass().getName();
if (className.startsWith("org.apache.solr.schema.IndexSchema$")) {
// If this class is just a no-params wrapper around a similarity class, use the similarity class
className = getSimilarity().getClass().getName();
}
return className;
}
}

View File

@ -0,0 +1,43 @@
<?xml version="1.0" ?>
<!--
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.
-->
<schema name="test-class-name-shortening-on-serialization" version="1.5">
<types>
<fieldtype name="fullClassNames" class="org.apache.solr.schema.TextField">
<analyzer>
<charFilter class="org.apache.solr.analysis.MockCharFilterFactory" remainder="0"/>
<tokenizer class="org.apache.solr.analysis.MockTokenizerFactory"/>
<filter class="org.apache.solr.analysis.MockTokenFilterFactory" stopset="empty"/>
</analyzer>
<similarity class="org.apache.lucene.misc.SweetSpotSimilarity"/>
</fieldtype>
<fieldtype name="shortenedClassNames" class="solr.TextField">
<analyzer>
<charFilter class="solr.MockCharFilterFactory" remainder="0"/>
<tokenizer class="solr.MockTokenizerFactory"/>
<filter class="solr.MockTokenFilterFactory" stopset="empty"/>
</analyzer>
<similarity class="solr.SweetSpotSimilarityFactory"/>
</fieldtype>
<fieldtype name="string" class="solr.StrField" sortMissingLast="true"/>
</types>
<fields>
<field name="id" type="string" indexed="true" stored="true" multiValued="false" required="true"/>
<field name="signatureField" type="string" indexed="true" stored="false"/>
</fields>
<similarity class="solr.SchemaSimilarityFactory"/>
</schema>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" ?>
<!--
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.
-->
<schema name="test-class-name-shortening-on-serialization" version="1.5">
<types>
<fieldtype name="explicitLuceneMatchVersions" class="org.apache.solr.schema.TextField">
<analyzer>
<charFilter class="org.apache.solr.analysis.MockCharFilterFactory" luceneMatchVersion="LUCENE_40" remainder="0"/>
<tokenizer class="org.apache.solr.analysis.MockTokenizerFactory" luceneMatchVersion="LUCENE_40" />
<filter class="org.apache.solr.analysis.MockTokenFilterFactory" luceneMatchVersion="LUCENE_40" stopset="empty"/>
</analyzer>
</fieldtype>
<fieldtype name="noLuceneMatchVersions" class="org.apache.solr.schema.TextField">
<analyzer>
<charFilter class="org.apache.solr.analysis.MockCharFilterFactory" remainder="0"/>
<tokenizer class="org.apache.solr.analysis.MockTokenizerFactory" />
<filter class="org.apache.solr.analysis.MockTokenFilterFactory" stopset="empty"/>
</analyzer>
</fieldtype>
<fieldtype name="string" class="solr.StrField" sortMissingLast="true"/>
</types>
<fields>
<field name="id" type="string" indexed="true" stored="true" multiValued="false" required="true"/>
<field name="signatureField" type="string" indexed="true" stored="false"/>
</fields>
</schema>

View File

@ -0,0 +1,70 @@
package org.apache.solr.rest.schema;
/*
* 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.solr.util.RestTestBase;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.BeforeClass;
import org.junit.Test;
import org.restlet.ext.servlet.ServerServlet;
import java.util.SortedMap;
import java.util.TreeMap;
public class TestClassNameShortening extends RestTestBase {
@BeforeClass
public static void init() throws Exception {
final SortedMap<ServletHolder,String> extraServlets = new TreeMap<ServletHolder,String>();
final ServletHolder solrRestApi = new ServletHolder("SolrRestApi", ServerServlet.class);
solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrRestApi");
extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...'
createJettyAndHarness(TEST_HOME(), "solrconfig-minimal.xml", "schema-class-name-shortening-on-serialization.xml",
"/solr", true, extraServlets);
}
@Test
public void testClassNamesNotShortened() throws Exception {
assertQ("/schema/fieldtypes/fullClassNames?indent=on&wt=xml&showDefaults=true",
"count(/response/lst[@name='fieldType']) = 1",
"/response/lst[@name='fieldType']/str[@name='class'] = 'org.apache.solr.schema.TextField'",
"//arr[@name='charFilters']/lst/str[@name='class'] = 'org.apache.solr.analysis.MockCharFilterFactory'",
"//lst[@name='tokenizer']/str[@name='class'] = 'org.apache.solr.analysis.MockTokenizerFactory'",
"//arr[@name='filters']/lst/str[@name='class'] = 'org.apache.solr.analysis.MockTokenFilterFactory'",
"/response/lst[@name='fieldType']/lst[@name='similarity']/str[@name='class'] = 'org.apache.lucene.misc.SweetSpotSimilarity'");
}
@Test
public void testShortenedGlobalSimilarityStaysShortened() throws Exception {
assertQ("/schema/similarity?indent=on&wt=xml",
"count(/response/lst[@name='similarity']) = 1",
"/response/lst[@name='similarity']/str[@name='class'][.='solr.SchemaSimilarityFactory']");
}
@Test
public void testShortenedClassNamesStayShortened() throws Exception {
assertQ("/schema/fieldtypes/shortenedClassNames?indent=on&wt=xml&showDefaults=true",
"count(/response/lst[@name='fieldType']) = 1",
"/response/lst[@name='fieldType']/str[@name='class'] = 'solr.TextField'",
"//arr[@name='charFilters']/lst/str[@name='class'] = 'solr.MockCharFilterFactory'",
"//lst[@name='tokenizer']/str[@name='class'] = 'solr.MockTokenizerFactory'",
"//arr[@name='filters']/lst/str[@name='class'] = 'solr.MockTokenFilterFactory'",
"/response/lst[@name='fieldType']/lst[@name='similarity']/str[@name='class'] = 'solr.SweetSpotSimilarityFactory'");
}
}

View File

@ -24,7 +24,7 @@ public class TestSchemaSimilarityResource extends SolrRestletTestBase {
public void testGetSchemaSimilarity() throws Exception {
assertQ("/schema/similarity?indent=on&wt=xml",
"count(/response/lst[@name='similarity']) = 1",
"/response/lst[@name='similarity']/str[@name='class'][.='solr.DefaultSimilarityFactory']");
"/response/lst[@name='similarity']/str[@name='class'][.='org.apache.solr.search.similarities.DefaultSimilarityFactory']");
}
}

View File

@ -0,0 +1,72 @@
package org.apache.solr.rest.schema;
/*
* 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.solr.util.RestTestBase;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.BeforeClass;
import org.junit.Test;
import org.restlet.ext.servlet.ServerServlet;
import java.util.SortedMap;
import java.util.TreeMap;
public class TestSerializedLuceneMatchVersion extends RestTestBase {
@BeforeClass
public static void init() throws Exception {
final SortedMap<ServletHolder,String> extraServlets = new TreeMap<ServletHolder,String>();
final ServletHolder solrRestApi = new ServletHolder("SolrRestApi", ServerServlet.class);
solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrRestApi");
extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...'
createJettyAndHarness(TEST_HOME(), "solrconfig-minimal.xml", "schema-rest-lucene-match-version.xml",
"/solr", true, extraServlets);
}
@Test
public void testExplicitLuceneMatchVersions() throws Exception {
assertQ("/schema/fieldtypes/explicitLuceneMatchVersions?indent=on&wt=xml&showDefaults=true",
"count(/response/lst[@name='fieldType']) = 1",
"//lst[str[@name='class'][.='org.apache.solr.analysis.MockCharFilterFactory']]"
+" [str[@name='luceneMatchVersion'][.='LUCENE_40']]",
"//lst[str[@name='class'][.='org.apache.solr.analysis.MockTokenizerFactory']]"
+" [str[@name='luceneMatchVersion'][.='LUCENE_40']]",
"//lst[str[@name='class'][.='org.apache.solr.analysis.MockTokenFilterFactory']]"
+" [str[@name='luceneMatchVersion'][.='LUCENE_40']]");
}
@Test
public void testNoLuceneMatchVersions() throws Exception {
assertQ("/schema/fieldtypes/noLuceneMatchVersions?indent=on&wt=xml&showDefaults=true",
"count(/response/lst[@name='fieldType']) = 1",
"//lst[str[@name='class'][.='org.apache.solr.analysis.MockCharFilterFactory']]"
+" [not(./str[@name='luceneMatchVersion'])]",
"//lst[str[@name='class'][.='org.apache.solr.analysis.MockTokenizerFactory']]"
+" [not(./str[@name='luceneMatchVersion'])]",
"//lst[str[@name='class'][.='org.apache.solr.analysis.MockTokenFilterFactory']]"
+" [not(./str[@name='luceneMatchVersion'])]");
}
}

View File

@ -0,0 +1,67 @@
package org.apache.solr.analysis;
/*
* 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 java.util.Arrays;
import java.util.Map;
import org.apache.lucene.analysis.MockTokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.util.TokenFilterFactory;
import org.apache.lucene.util.automaton.CharacterRunAutomaton;
import org.apache.lucene.util.automaton.RegExp;
/**
* Factory for {@link MockTokenFilter} for testing purposes.
*/
public class MockTokenFilterFactory extends TokenFilterFactory {
final CharacterRunAutomaton filter;
final boolean enablePositionIncrements;
/** Creates a new MockTokenizerFactory */
public MockTokenFilterFactory(Map<String, String> args) {
super(args);
String stopset = get(args, "stopset", Arrays.asList("english", "empty"), null, false);
String stopregex = get(args, "stopregex");
if (null != stopset) {
if (null != stopregex) {
throw new IllegalArgumentException("Parameters stopset and stopregex cannot both be specified.");
}
if ("english".equalsIgnoreCase(stopset)) {
filter = MockTokenFilter.ENGLISH_STOPSET;
} else { // must be "empty"
filter = MockTokenFilter.EMPTY_STOPSET;
}
} else if (null != stopregex) {
RegExp regex = new RegExp(stopregex);
filter = new CharacterRunAutomaton(regex.toAutomaton());
} else {
throw new IllegalArgumentException
("Configuration Error: either the 'stopset' or the 'stopregex' parameter must be specified.");
}
enablePositionIncrements = getBoolean(args, "enablePositionIncrements", true);
if (!args.isEmpty()) {
throw new IllegalArgumentException("Unknown parameters: " + args);
}
}
@Override
public MockTokenFilter create(TokenStream stream) {
return new MockTokenFilter(stream, filter);
}
}