SOLR-4623: Provide REST API read access to all elements of the live schema. Add a REST API request to return the entire live schema, in JSON, XML, and schema.xml formats. Move REST API methods from package org.apache.solr.rest to org.apache.solr.rest.schema, and rename base functionality REST API classes to remove the current schema focus, to prepare for other non-schema REST APIs. Change output path for copyFields and dynamicFields from "copyfields" and "dynamicfields" (all lowercase) to "copyFields" and "dynamicFields", respectively, to align with all other schema REST API outputs, which use camelCase.

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1460519 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Steven Rowe 2013-03-25 04:29:33 +00:00
parent a7a799c403
commit 5c7ca6aa48
51 changed files with 2266 additions and 625 deletions

View File

@ -51,7 +51,11 @@ Apache ZooKeeper 3.4.5
Upgrading from Solr 4.2.0
----------------------
(No upgrade instructions yet)
* SOLR-4623: The output path for copyFields and dynamicFields has been changed
from all lowercase "copyfields" and "dynamicfields" to camelCase "copyFields"
and "dynamicFields", respectively, to align with all other schema REST API
outputs, which use camelCase. The URL format remains the same: all resource
names are lowercase. (Steve Rowe)
Detailed Change List
----------------------
@ -71,6 +75,17 @@ New Features
See the discussion on the wiki page titled "Core Discovery (4.3 and beyond)" for
the formats of both solr.properties and the individual core.properties files
(Erick Erickson)
* SOLR-4623: Provide REST API read access to all elements of the live schema.
Add a REST API request to return the entire live schema, in JSON, XML, and
schema.xml formats. Move REST API methods from package org.apache.solr.rest
to org.apache.solr.rest.schema, and rename base functionality REST API
classes to remove the current schema focus, to prepare for other non-schema
REST APIs. Change output path for copyFields and dynamicFields from
"copyfields" and "dynamicfields" (all lowercase) to "copyFields" and
"dynamicFields", respectively, to align with all other REST API outputs, which
use camelCase.
(Steve Rowe)
Bug Fixes
----------------------

View File

@ -90,6 +90,7 @@ import org.apache.solr.response.PythonResponseWriter;
import org.apache.solr.response.QueryResponseWriter;
import org.apache.solr.response.RawResponseWriter;
import org.apache.solr.response.RubyResponseWriter;
import org.apache.solr.response.SchemaXmlResponseWriter;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.response.XMLResponseWriter;
import org.apache.solr.response.transform.TransformerFactory;
@ -1901,6 +1902,7 @@ public final class SolrCore implements SolrInfoMBean {
m.put("raw", new RawResponseWriter());
m.put("javabin", new BinaryResponseWriter());
m.put("csv", new CSVResponseWriter());
m.put("schema.xml", new SchemaXmlResponseWriter());
DEFAULT_RESPONSE_WRITERS = Collections.unmodifiableMap(m);
}

View File

@ -0,0 +1,49 @@
/*
* 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.response;
import java.io.Writer;
import java.io.IOException;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
/**
*
*/
public class SchemaXmlResponseWriter implements QueryResponseWriter {
@Override
public void init(NamedList n) {
/* NOOP */
}
@Override
public void write(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
SchemaXmlWriter w = new SchemaXmlWriter(writer, req, rsp);
try {
w.writeResponse();
} finally {
w.close();
}
}
@Override
public String getContentType(SolrQueryRequest request, SolrQueryResponse response) {
return CONTENT_TYPE_XML_UTF8;
}
}

View File

@ -0,0 +1,482 @@
package org.apache.solr.response;
/*
* 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.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.common.util.XML;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SimilarityFactory;
import org.apache.solr.search.ReturnFields;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @lucene.internal
*/
public class SchemaXmlWriter extends TextResponseWriter {
final static Logger log = LoggerFactory.getLogger(SchemaXmlWriter.class);
private static final char[] XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>".toCharArray();
public static void writeResponse(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
SchemaXmlWriter schemaXmlWriter = null;
try {
schemaXmlWriter = new SchemaXmlWriter(writer, req, rsp);
schemaXmlWriter.writeResponse();
} finally {
if (null != schemaXmlWriter) {
schemaXmlWriter.close();
}
}
}
public SchemaXmlWriter(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) {
super(writer, req, rsp);
}
public void writeResponse() throws IOException {
writer.write(XML_DECLARATION);
@SuppressWarnings("unchecked") SimpleOrderedMap<Object> schemaProperties
= (SimpleOrderedMap<Object>)rsp.getValues().get(IndexSchema.SCHEMA);
openStartTag(IndexSchema.SCHEMA);
writeAttr(IndexSchema.NAME, schemaProperties.get(IndexSchema.NAME).toString());
writeAttr(IndexSchema.VERSION, schemaProperties.get(IndexSchema.VERSION).toString());
closeStartTag(false);
incLevel();
for (int schemaPropNum = 0 ; schemaPropNum < schemaProperties.size() ; ++schemaPropNum) {
String schemaPropName = schemaProperties.getName(schemaPropNum);
if (schemaPropName.equals(IndexSchema.NAME) || schemaPropName.equals(IndexSchema.VERSION)) {
continue;
}
if (schemaPropName.equals(IndexSchema.UNIQUE_KEY)) {
openStartTag(IndexSchema.UNIQUE_KEY);
closeStartTag(false);
writer.write(schemaProperties.getVal(schemaPropNum).toString());
endTag(IndexSchema.UNIQUE_KEY, false);
} else if (schemaPropName.equals(IndexSchema.DEFAULT_SEARCH_FIELD)) {
openStartTag(IndexSchema.DEFAULT_SEARCH_FIELD);
closeStartTag(false);
writer.write(schemaProperties.getVal(schemaPropNum).toString());
endTag(IndexSchema.DEFAULT_SEARCH_FIELD, false);
} else if (schemaPropName.equals(IndexSchema.SOLR_QUERY_PARSER)) {
openStartTag(IndexSchema.SOLR_QUERY_PARSER);
@SuppressWarnings("unchecked") SimpleOrderedMap<Object> solrQueryParserProperties
= (SimpleOrderedMap<Object>)schemaProperties.getVal(schemaPropNum);
writeAttr(IndexSchema.DEFAULT_OPERATOR, solrQueryParserProperties.get(IndexSchema.DEFAULT_OPERATOR).toString());
closeStartTag(true);
} else if (schemaPropName.equals(IndexSchema.SIMILARITY)) {
writeSimilarity((SimpleOrderedMap<Object>) schemaProperties.getVal(schemaPropNum));
} else if (schemaPropName.equals(IndexSchema.FIELD_TYPES)) {
writeFieldTypes((List<SimpleOrderedMap<Object>>)schemaProperties.getVal(schemaPropNum));
} else if (schemaPropName.equals(IndexSchema.FIELDS)) {
openStartTag(IndexSchema.FIELDS);
closeStartTag(false);
incLevel();
@SuppressWarnings("unchecked") List<SimpleOrderedMap<Object>> fieldPropertiesList
= (List<SimpleOrderedMap<Object>>)schemaProperties.getVal(schemaPropNum);
for (SimpleOrderedMap<Object> fieldProperties : fieldPropertiesList) {
openStartTag(IndexSchema.FIELD);
for (int fieldPropNum = 0 ; fieldPropNum < fieldProperties.size() ; ++fieldPropNum) {
writeAttr(fieldProperties.getName(fieldPropNum), fieldProperties.getVal(fieldPropNum).toString());
}
closeStartTag(true);
}
} else if (schemaPropName.equals(IndexSchema.DYNAMIC_FIELDS)) {
@SuppressWarnings("unchecked") List<SimpleOrderedMap<Object>> dynamicFieldPropertiesList
= (List<SimpleOrderedMap<Object>>)schemaProperties.getVal(schemaPropNum);
for (SimpleOrderedMap<Object> dynamicFieldProperties : dynamicFieldPropertiesList) {
openStartTag(IndexSchema.DYNAMIC_FIELD);
for (int dynamicFieldPropNum = 0 ; dynamicFieldPropNum < dynamicFieldProperties.size() ; ++dynamicFieldPropNum) {
writeAttr(dynamicFieldProperties.getName(dynamicFieldPropNum),
dynamicFieldProperties.getVal(dynamicFieldPropNum).toString());
}
closeStartTag(true);
}
decLevel();
endTag(IndexSchema.FIELDS);
} else if (schemaPropName.equals(IndexSchema.COPY_FIELDS)) {
@SuppressWarnings("unchecked") List<SimpleOrderedMap<Object>> copyFieldPropertiesList
= (List<SimpleOrderedMap<Object>>)schemaProperties.getVal(schemaPropNum);
for (SimpleOrderedMap<Object> copyFieldProperties : copyFieldPropertiesList) {
openStartTag(IndexSchema.COPY_FIELD);
for (int copyFieldPropNum = 0 ; copyFieldPropNum < copyFieldProperties.size() ; ++ copyFieldPropNum) {
writeAttr(copyFieldProperties.getName(copyFieldPropNum),
copyFieldProperties.getVal(copyFieldPropNum).toString());
}
closeStartTag(true);
}
} else {
log.warn("Unknown schema component '" + schemaPropName + "'");
}
}
decLevel();
endTag(IndexSchema.SCHEMA);
}
private void writeFieldTypes(List<SimpleOrderedMap<Object>> fieldTypePropertiesList) throws IOException {
openStartTag(IndexSchema.TYPES);
closeStartTag(false);
incLevel();
for (SimpleOrderedMap<Object> fieldTypeProperties : fieldTypePropertiesList) {
SimpleOrderedMap<Object> analyzerProperties = null;
SimpleOrderedMap<Object> indexAnalyzerProperties = null;
SimpleOrderedMap<Object> queryAnalyzerProperties = null;
SimpleOrderedMap<Object> multiTermAnalyzerProperties = null;
SimpleOrderedMap<Object> perFieldSimilarityProperties = null;
openStartTag(IndexSchema.FIELD_TYPE);
for (int fieldTypePropNum = 0 ; fieldTypePropNum < fieldTypeProperties.size() ; ++fieldTypePropNum) {
String fieldTypePropName = fieldTypeProperties.getName(fieldTypePropNum);
if (fieldTypePropName.equals(FieldType.ANALYZER)) {
analyzerProperties = (SimpleOrderedMap<Object>)fieldTypeProperties.getVal(fieldTypePropNum);
} else if (fieldTypePropName.equals(FieldType.INDEX_ANALYZER)) {
indexAnalyzerProperties = (SimpleOrderedMap<Object>)fieldTypeProperties.getVal(fieldTypePropNum);
} else if (fieldTypePropName.equals(FieldType.QUERY_ANALYZER)) {
queryAnalyzerProperties = (SimpleOrderedMap<Object>)fieldTypeProperties.getVal(fieldTypePropNum);
} else if (fieldTypePropName.equals(FieldType.MULTI_TERM_ANALYZER)) {
multiTermAnalyzerProperties = (SimpleOrderedMap<Object>)fieldTypeProperties.getVal(fieldTypePropNum);
} else if (fieldTypePropName.equals(FieldType.SIMILARITY)) {
perFieldSimilarityProperties = (SimpleOrderedMap<Object>)fieldTypeProperties.getVal(fieldTypePropNum);
} else {
writeAttr(fieldTypePropName, fieldTypeProperties.getVal(fieldTypePropNum).toString());
}
}
boolean isEmptyTag = null == analyzerProperties && null == indexAnalyzerProperties
&& null == queryAnalyzerProperties && null == multiTermAnalyzerProperties
&& null == perFieldSimilarityProperties;
if (isEmptyTag) {
closeStartTag(true);
} else {
closeStartTag(false);
incLevel();
if (null != analyzerProperties) writeAnalyzer(analyzerProperties, null);
if (null != indexAnalyzerProperties) writeAnalyzer(indexAnalyzerProperties, FieldType.INDEX);
if (null != queryAnalyzerProperties) writeAnalyzer(queryAnalyzerProperties, FieldType.QUERY);
if (null != multiTermAnalyzerProperties) writeAnalyzer(multiTermAnalyzerProperties, FieldType.MULTI_TERM);
if (null != perFieldSimilarityProperties) writeSimilarity(perFieldSimilarityProperties);
decLevel();
endTag(IndexSchema.FIELD_TYPE);
}
}
decLevel();
endTag(IndexSchema.TYPES);
}
private void writeSimilarity(SimpleOrderedMap<Object> similarityProperties) throws IOException {
openStartTag(IndexSchema.SIMILARITY);
writeAttr(SimilarityFactory.CLASS_NAME, similarityProperties.get(SimilarityFactory.CLASS_NAME).toString());
if (similarityProperties.size() > 1) {
closeStartTag(false);
incLevel();
writeNamedList(null, similarityProperties);
decLevel();
endTag(IndexSchema.SIMILARITY);
} else {
closeStartTag(true);
}
}
private void writeAnalyzer(SimpleOrderedMap<Object> analyzerProperties, String analyzerType) throws IOException {
openStartTag(FieldType.ANALYZER);
if (null != analyzerType) {
writeAttr(FieldType.TYPE, analyzerType);
}
List<SimpleOrderedMap<Object>> charFilterPropertiesList = null;
SimpleOrderedMap<Object> tokenizerProperties = null;
List<SimpleOrderedMap<Object>> filterPropertiesList = null;
for (int i = 0 ; i < analyzerProperties.size() ; ++i) {
String name = analyzerProperties.getName(i);
if (name.equals(FieldType.CHAR_FILTERS)) {
charFilterPropertiesList = (List<SimpleOrderedMap<Object>>)analyzerProperties.getVal(i);
} else if (name.equals(FieldType.TOKENIZER)) {
tokenizerProperties = (SimpleOrderedMap<Object>)analyzerProperties.getVal(i);
} else if (name.equals(FieldType.FILTERS)) {
filterPropertiesList = (List<SimpleOrderedMap<Object>>)analyzerProperties.getVal(i);
} else if (name.equals(FieldType.CLASS_NAME)) {
if ( ! "solr.TokenizerChain".equals(analyzerProperties.getVal(i))) {
writeAttr(name, analyzerProperties.getVal(i).toString());
}
}
}
boolean isEmptyTag
= null == charFilterPropertiesList && null == tokenizerProperties && null == filterPropertiesList;
if (isEmptyTag) {
closeStartTag(true);
} else {
closeStartTag(false);
incLevel();
if (null != charFilterPropertiesList) {
for (SimpleOrderedMap<Object> charFilterProperties : charFilterPropertiesList) {
openStartTag(FieldType.CHAR_FILTER);
for (int i = 0 ; i < charFilterProperties.size() ; ++i) {
writeAttr(charFilterProperties.getName(i), charFilterProperties.getVal(i).toString());
}
closeStartTag(true);
}
}
if (null != tokenizerProperties) {
openStartTag(FieldType.TOKENIZER);
for (int i = 0 ; i < tokenizerProperties.size() ; ++i) {
writeAttr(tokenizerProperties.getName(i), tokenizerProperties.getVal(i).toString());
}
closeStartTag(true);
}
if (null != filterPropertiesList) {
for (SimpleOrderedMap<Object> filterProperties : filterPropertiesList) {
openStartTag(FieldType.FILTER);
for (int i = 0 ; i < filterProperties.size() ; ++i) {
writeAttr(filterProperties.getName(i), filterProperties.getVal(i).toString());
}
closeStartTag(true);
}
}
decLevel();
endTag(FieldType.ANALYZER);
}
}
void openStartTag(String tag) throws IOException {
if (doIndent) indent();
writer.write('<');
writer.write(tag);
}
void closeStartTag(boolean isEmptyTag) throws IOException {
if (isEmptyTag) writer.write('/');
writer.write('>');
}
void endTag(String tag) throws IOException {
endTag(tag, true);
}
void endTag(String tag, boolean indentThisTag) throws IOException {
if (doIndent && indentThisTag) indent();
writer.write('<');
writer.write('/');
writer.write(tag);
writer.write('>');
}
/** Writes the XML attribute name/val. A null val means that the attribute is missing. */
private void writeAttr(String name, String val) throws IOException {
writeAttr(name, val, true);
}
public void writeAttr(String name, String val, boolean escape) throws IOException{
if (val != null) {
writer.write(' ');
writer.write(name);
writer.write("=\"");
if (escape){
XML.escapeAttributeValue(val, writer);
} else {
writer.write(val);
}
writer.write('"');
}
}
@Override
public void writeNamedList(String name, NamedList val) throws IOException {
// name is ignored - this method is only used for SimilarityFactory
int sz = val.size();
for (int i=0; i<sz; i++) {
String valName = val.getName(i);
if ( ! valName.equals(SimilarityFactory.CLASS_NAME)) {
writeVal(valName, val.getVal(i));
}
}
}
void startTag(String tag, String name, boolean closeTag) throws IOException {
if (doIndent) indent();
writer.write('<');
writer.write(tag);
if (name!=null) {
writeAttr("name", name);
if (closeTag) {
writer.write("/>");
} else {
writer.write(">");
}
} else {
if (closeTag) {
writer.write("/>");
} else {
writer.write('>');
}
}
}
@Override
public void writeMap(String name, Map map, boolean excludeOuter, boolean isFirstVal) throws IOException {
int sz = map.size();
if (!excludeOuter) {
startTag("lst", name, sz<=0);
incLevel();
}
for (Map.Entry entry : (Set<Map.Entry>)map.entrySet()) {
Object k = entry.getKey();
Object v = entry.getValue();
// if (sz<indentThreshold) indent();
writeVal( null == k ? null : k.toString(), v);
}
if (!excludeOuter) {
decLevel();
if (sz > 0) {
if (doIndent) indent();
writer.write("</lst>");
}
}
}
@Override
public void writeArray(String name, Object[] val) throws IOException {
writeArray(name, Arrays.asList(val).iterator());
}
@Override
public void writeArray(String name, Iterator iter) throws IOException {
if( iter.hasNext() ) {
startTag("arr", name, false );
incLevel();
while( iter.hasNext() ) {
writeVal(null, iter.next());
}
decLevel();
if (doIndent) indent();
writer.write("</arr>");
}
else {
startTag("arr", name, true );
}
}
//
// Primitive types
//
@Override
public void writeNull(String name) throws IOException {
writePrim("null",name,"",false);
}
@Override
public void writeStr(String name, String val, boolean escape) throws IOException {
writePrim("str",name,val,escape);
}
@Override
public void writeInt(String name, String val) throws IOException {
writePrim("int",name,val,false);
}
@Override
public void writeLong(String name, String val) throws IOException {
writePrim("long",name,val,false);
}
@Override
public void writeBool(String name, String val) throws IOException {
writePrim("bool",name,val,false);
}
@Override
public void writeFloat(String name, String val) throws IOException {
writePrim("float",name,val,false);
}
@Override
public void writeFloat(String name, float val) throws IOException {
writeFloat(name,Float.toString(val));
}
@Override
public void writeDouble(String name, String val) throws IOException {
writePrim("double",name,val,false);
}
@Override
public void writeDouble(String name, double val) throws IOException {
writeDouble(name,Double.toString(val));
}
@Override
public void writeDate(String name, String val) throws IOException {
writePrim("date",name,val,false);
}
//
// OPT - specific writeInt, writeFloat, methods might be faster since
// there would be less write calls (write("<int name=\"" + name + ... + </int>)
//
private void writePrim(String tag, String name, String val, boolean escape) throws IOException {
int contentLen = val==null ? 0 : val.length();
startTag(tag, name, contentLen==0);
if (contentLen==0) return;
if (escape) {
XML.escapeCharData(val,writer);
} else {
writer.write(val,0,contentLen);
}
writer.write('<');
writer.write('/');
writer.write(tag);
writer.write('>');
}
@Override
public void writeStartDocumentList(String name, long start, int size, long numFound, Float maxScore) throws IOException {
// no-op
}
@Override
public void writeSolrDocument(String name, SolrDocument doc, ReturnFields returnFields, int idx) throws IOException {
// no-op
}
@Override
public void writeEndDocumentList() throws IOException {
// no-op
}
}

View File

@ -1,175 +0,0 @@
package org.apache.solr.rest;
/*
* 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.common.params.CommonParams;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.schema.CopyField;
import org.apache.solr.schema.IndexSchema;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
/**
* This class responds to requests at /solr/(corename)/schema/copyfields
*
* <p/>
*
* To restrict the set of copyFields in the response, specify one or both
* of the following as query parameters, with values as space and/or comma
* separated dynamic or explicit field names:
*
* <ul>
* <li>dest.fl: include copyFields that have one of these as a destination</li>
* <li>source.fl: include copyFields that have one of these as a source</li>
* </ul>
*
* If both dest.fl and source.fl are given as query parameters, the copyfields
* in the response will be restricted to those that match any of the destinations
* in dest.fl and also match any of the sources in source.fl.
*/
public class CopyFieldCollectionResource extends BaseFieldResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(CopyFieldCollectionResource.class);
private static final String SOURCE = "source";
private static final String DESTINATION = "dest";
private static final String SOURCE_FIELD_LIST = SOURCE + "." + CommonParams.FL;
private static final String DESTINATION_FIELD_LIST = DESTINATION + "." + CommonParams.FL;
private static final String MAX_CHARS = "maxChars";
private static final String SOURCE_DYNAMIC_BASE = "sourceDynamicBase";
private static final String DESTINATION_DYNAMIC_BASE = "destDynamicBase";
private static final String SOURCE_EXPLICIT_FIELDS = "sourceExplicitFields";
private Set<String> requestedSourceFields;
private Set<String> requestedDestinationFields;
public CopyFieldCollectionResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
if (isExisting()) {
String sourceFieldListParam = getSolrRequest().getParams().get(SOURCE_FIELD_LIST);
if (null != sourceFieldListParam) {
String[] fields = sourceFieldListParam.trim().split("[,\\s]+");
if (fields.length > 0) {
requestedSourceFields = new HashSet<String>(Arrays.asList(fields));
requestedSourceFields.remove(""); // Remove empty values, if any
}
}
String destinationFieldListParam = getSolrRequest().getParams().get(DESTINATION_FIELD_LIST);
if (null != destinationFieldListParam) {
String[] fields = destinationFieldListParam.trim().split("[,\\s]+");
if (fields.length > 0) {
requestedDestinationFields = new HashSet<String>(Arrays.asList(fields));
requestedDestinationFields.remove(""); // Remove empty values, if any
}
}
}
}
@Override
public Representation get() {
try {
final List<SimpleOrderedMap<Object>> props = new ArrayList<SimpleOrderedMap<Object>>();
SortedMap<String,List<CopyField>> sortedCopyFields = new TreeMap<String, List<CopyField>>(getSchema().getCopyFieldsMap());
for (List<CopyField> copyFields : sortedCopyFields.values()) {
Collections.sort(copyFields, new Comparator<CopyField>() {
@Override
public int compare(CopyField cf1, CopyField cf2) {
// source should all be the same => already sorted
return cf1.getDestination().getName().compareTo(cf2.getDestination().getName());
}
});
for (CopyField copyField : copyFields) {
final String source = copyField.getSource().getName();
final String destination = copyField.getDestination().getName();
if ( (null == requestedSourceFields || requestedSourceFields.contains(source))
&& (null == requestedDestinationFields || requestedDestinationFields.contains(destination))) {
SimpleOrderedMap<Object> copyFieldProps = new SimpleOrderedMap<Object>();
copyFieldProps.add(SOURCE, source);
copyFieldProps.add(DESTINATION, destination);
if (0 != copyField.getMaxChars()) {
copyFieldProps.add(MAX_CHARS, copyField.getMaxChars());
}
props.add(copyFieldProps);
}
}
}
for (IndexSchema.DynamicCopy dynamicCopy : getSchema().getDynamicCopyFields()) {
final String source = dynamicCopy.getRegex();
final String destination = dynamicCopy.getDestFieldName();
if ( (null == requestedSourceFields || requestedSourceFields.contains(source))
&& (null == requestedDestinationFields || requestedDestinationFields.contains(destination))) {
SimpleOrderedMap<Object> dynamicCopyProps = new SimpleOrderedMap<Object>();
dynamicCopyProps.add(SOURCE, dynamicCopy.getRegex());
IndexSchema.DynamicField sourceDynamicBase = dynamicCopy.getSourceDynamicBase();
if (null != sourceDynamicBase) {
dynamicCopyProps.add(SOURCE_DYNAMIC_BASE, sourceDynamicBase.getRegex());
} else if (source.contains("*")) {
List<String> sourceExplicitFields = new ArrayList<String>();
Pattern pattern = Pattern.compile(source.replace("*", ".*")); // glob->regex
for (String field : getSchema().getFields().keySet()) {
if (pattern.matcher(field).matches()) {
sourceExplicitFields.add(field);
}
}
if (sourceExplicitFields.size() > 0) {
Collections.sort(sourceExplicitFields);
dynamicCopyProps.add(SOURCE_EXPLICIT_FIELDS, sourceExplicitFields);
}
}
dynamicCopyProps.add(DESTINATION, dynamicCopy.getDestFieldName());
IndexSchema.DynamicField destDynamicBase = dynamicCopy.getDestDynamicBase();
if (null != destDynamicBase) {
dynamicCopyProps.add(DESTINATION_DYNAMIC_BASE, destDynamicBase.getRegex());
}
if (0 != dynamicCopy.getMaxChars()) {
dynamicCopyProps.add(MAX_CHARS, dynamicCopy.getMaxChars());
}
props.add(dynamicCopyProps);
}
}
getSolrResponse().add(SchemaRestApi.COPY_FIELDS, props);
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}

View File

@ -1,84 +0,0 @@
package org.apache.solr.rest;
/*
* 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.restlet.Application;
import org.restlet.Restlet;
import org.restlet.routing.Router;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SchemaRestApi extends Application {
public static final Logger log = LoggerFactory.getLogger(SchemaRestApi.class);
public static final String FIELDS = "fields";
public static final String FIELDS_PATH = "/" + FIELDS;
public static final String DYNAMIC_FIELDS = "dynamicfields";
public static final String DYNAMIC_FIELDS_PATH = "/" + DYNAMIC_FIELDS;
public static final String FIELDTYPES = "fieldtypes";
public static final String FIELDTYPES_PATH = "/" + FIELDTYPES;
public static final String NAME_VARIABLE = "name";
public static final String NAME_SEGMENT = "/{" + NAME_VARIABLE + "}";
public static final String COPY_FIELDS = "copyfields";
public static final String COPY_FIELDS_PATH = "/" + COPY_FIELDS;
private Router router;
public SchemaRestApi() {
router = new Router(getContext());
}
@Override
public void stop() throws Exception {
if (router != null) {
router.stop();
}
}
/**
* Bind URL paths to the appropriate ServerResource subclass.
*/
@Override
public synchronized Restlet createInboundRoot() {
log.info("createInboundRoot started");
router.attachDefault(DefaultSchemaResource.class);
router.attach(FIELDS_PATH, FieldCollectionResource.class);
// Allow a trailing slash on collection requests
router.attach(FIELDS_PATH + "/", FieldCollectionResource.class);
router.attach(FIELDS_PATH + NAME_SEGMENT, FieldResource.class);
router.attach(DYNAMIC_FIELDS_PATH, DynamicFieldCollectionResource.class);
// Allow a trailing slash on collection requests
router.attach(DYNAMIC_FIELDS_PATH + "/", DynamicFieldCollectionResource.class);
router.attach(DYNAMIC_FIELDS_PATH + NAME_SEGMENT, DynamicFieldResource.class);
router.attach(FIELDTYPES_PATH, FieldTypeCollectionResource.class);
// Allow a trailing slash on collection requests
router.attach(FIELDTYPES_PATH + "/", FieldTypeCollectionResource.class);
router.attach(FIELDTYPES_PATH + NAME_SEGMENT, FieldTypeResource.class);
router.attach(COPY_FIELDS_PATH, CopyFieldCollectionResource.class);
// Allow a trailing slash on collection requests
router.attach(COPY_FIELDS_PATH + "/", CopyFieldCollectionResource.class);
log.info("createInboundRoot complete");
return router;
}
}

View File

@ -0,0 +1,140 @@
package org.apache.solr.rest;
/*
* 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.rest.schema.CopyFieldCollectionResource;
import org.apache.solr.rest.schema.DefaultSchemaResource;
import org.apache.solr.rest.schema.SchemaResource;
import org.apache.solr.rest.schema.DefaultSearchFieldResource;
import org.apache.solr.rest.schema.DynamicFieldCollectionResource;
import org.apache.solr.rest.schema.DynamicFieldResource;
import org.apache.solr.rest.schema.FieldCollectionResource;
import org.apache.solr.rest.schema.FieldResource;
import org.apache.solr.rest.schema.FieldTypeCollectionResource;
import org.apache.solr.rest.schema.FieldTypeResource;
import org.apache.solr.rest.schema.SchemaNameResource;
import org.apache.solr.rest.schema.SchemaSimilarityResource;
import org.apache.solr.rest.schema.SchemaVersionResource;
import org.apache.solr.rest.schema.SolrQueryParserDefaultOperatorResource;
import org.apache.solr.rest.schema.SolrQueryParserResource;
import org.apache.solr.rest.schema.UniqueKeyFieldResource;
import org.apache.solr.schema.IndexSchema;
import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.routing.Router;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Locale;
public class SolrRestApi extends Application {
public static final Logger log = LoggerFactory.getLogger(SolrRestApi.class);
public static final String FIELDS_PATH = "/" + IndexSchema.FIELDS;
public static final String DYNAMIC_FIELDS = IndexSchema.DYNAMIC_FIELDS.toLowerCase(Locale.ROOT);
public static final String DYNAMIC_FIELDS_PATH = "/" + DYNAMIC_FIELDS;
public static final String FIELDTYPES = IndexSchema.FIELD_TYPES.toLowerCase(Locale.ROOT);
public static final String FIELDTYPES_PATH = "/" + FIELDTYPES;
public static final String NAME_PATH = "/" + IndexSchema.NAME.toLowerCase(Locale.ROOT);
public static final String NAME_SEGMENT = "/{" + IndexSchema.NAME.toLowerCase(Locale.ROOT) + "}";
public static final String COPY_FIELDS = IndexSchema.COPY_FIELDS.toLowerCase(Locale.ROOT);
public static final String COPY_FIELDS_PATH = "/" + COPY_FIELDS;
public static final String VERSION_PATH = "/" + IndexSchema.VERSION.toLowerCase(Locale.ROOT);
public static final String DEFAULT_SEARCH_FIELD = IndexSchema.DEFAULT_SEARCH_FIELD.toLowerCase(Locale.ROOT);
public static final String DEFAULT_SEARCH_FIELD_PATH = "/" + DEFAULT_SEARCH_FIELD;
public static final String SIMILARITY_PATH = "/" + IndexSchema.SIMILARITY.toLowerCase(Locale.ROOT);
public static final String SOLR_QUERY_PARSER = IndexSchema.SOLR_QUERY_PARSER.toLowerCase(Locale.ROOT);
public static final String SOLR_QUERY_PARSER_PATH = "/" + SOLR_QUERY_PARSER;
public static final String DEFAULT_OPERATOR = IndexSchema.DEFAULT_OPERATOR.toLowerCase(Locale.ROOT);
public static final String DEFAULT_OPERATOR_PATH = SOLR_QUERY_PARSER_PATH + "/" + DEFAULT_OPERATOR;
public static final String UNIQUE_KEY_FIELD = IndexSchema.UNIQUE_KEY.toLowerCase(Locale.ROOT);
public static final String UNIQUE_KEY_FIELD_PATH = "/" + UNIQUE_KEY_FIELD;
private Router router;
public SolrRestApi() {
router = new Router(getContext());
}
@Override
public void stop() throws Exception {
if (null != router) {
router.stop();
}
}
/**
* Bind URL paths to the appropriate ServerResource subclass.
*/
@Override
public synchronized Restlet createInboundRoot() {
log.info("createInboundRoot started");
router.attach("", SchemaResource.class);
// Allow a trailing slash on full-schema requests
router.attach("/", SchemaResource.class);
router.attach(FIELDS_PATH, FieldCollectionResource.class);
// Allow a trailing slash on collection requests
router.attach(FIELDS_PATH + "/", FieldCollectionResource.class);
router.attach(FIELDS_PATH + NAME_SEGMENT, FieldResource.class);
router.attach(DYNAMIC_FIELDS_PATH, DynamicFieldCollectionResource.class);
// Allow a trailing slash on collection requests
router.attach(DYNAMIC_FIELDS_PATH + "/", DynamicFieldCollectionResource.class);
router.attach(DYNAMIC_FIELDS_PATH + NAME_SEGMENT, DynamicFieldResource.class);
router.attach(FIELDTYPES_PATH, FieldTypeCollectionResource.class);
// Allow a trailing slash on collection requests
router.attach(FIELDTYPES_PATH + "/", FieldTypeCollectionResource.class);
router.attach(FIELDTYPES_PATH + NAME_SEGMENT, FieldTypeResource.class);
router.attach(COPY_FIELDS_PATH, CopyFieldCollectionResource.class);
// Allow a trailing slash on collection requests
router.attach(COPY_FIELDS_PATH + "/", CopyFieldCollectionResource.class);
router.attach(NAME_PATH, SchemaNameResource.class);
router.attach(VERSION_PATH, SchemaVersionResource.class);
router.attach(UNIQUE_KEY_FIELD_PATH, UniqueKeyFieldResource.class);
router.attach(DEFAULT_SEARCH_FIELD_PATH, DefaultSearchFieldResource.class);
router.attach(SIMILARITY_PATH, SchemaSimilarityResource.class);
// At present solrQueryParser only contains defaultOperator, but there may be more children in the future
router.attach(SOLR_QUERY_PARSER_PATH, SolrQueryParserResource.class);
router.attach(DEFAULT_OPERATOR_PATH, SolrQueryParserDefaultOperatorResource.class);
router.attachDefault(DefaultSchemaResource.class);
log.info("createInboundRoot complete");
return router;
}
}

View File

@ -1,27 +1,29 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<!--
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
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.
-->
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.
-->
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<p>
Provides RESTful API access to the Solr Schema using Restlet.
Solr RESTful APIs via Restlet.
</p>
</body>
</html>

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -18,6 +18,7 @@ package org.apache.solr.rest;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.restlet.resource.ResourceException;
@ -30,9 +31,6 @@ import java.util.LinkedHashSet;
abstract class BaseFieldResource extends BaseSchemaResource {
protected static final String INCLUDE_DYNAMIC_PARAM = "includeDynamic";
private static final String DYNAMIC_BASE = "dynamicBase";
private static final String UNIQUE_KEY = "uniqueKey";
private static final String SHOW_DEFAULTS = "showDefaults";
private LinkedHashSet<String> requestedFields;
private boolean showDefaults;
@ -95,7 +93,7 @@ abstract class BaseFieldResource extends BaseSchemaResource {
}
}
if (field == getSchema().getUniqueKeyField()) {
properties.add(UNIQUE_KEY, true);
properties.add(IndexSchema.UNIQUE_KEY, true);
}
return properties;
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
package org.apache.solr.rest.schema;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -17,21 +17,17 @@ package org.apache.solr.rest;
* limitations under the License.
*/
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.restlet.resource.ResourceException;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Base class for the FieldType resource classes.
*/
abstract class BaseFieldTypeResource extends BaseSchemaResource {
private static final String FIELDS = "fields";
private static final String DYNAMIC_FIELDS = "dynamicFields";
private boolean showDefaults;
protected BaseFieldTypeResource() {
@ -41,14 +37,16 @@ abstract class BaseFieldTypeResource extends BaseSchemaResource {
@Override
public void doInit() throws ResourceException {
super.doInit();
showDefaults = getSolrRequest().getParams().getBool(SHOW_DEFAULTS, false);
if (isExisting()) {
showDefaults = getSolrRequest().getParams().getBool(SHOW_DEFAULTS, false);
}
}
/** Used by subclasses to collect field type properties */
protected SimpleOrderedMap<Object> getFieldTypeProperties(FieldType fieldType) {
SimpleOrderedMap<Object> properties = fieldType.getNamedPropertyValues(showDefaults);
properties.add(FIELDS, getFieldsWithFieldType(fieldType));
properties.add(DYNAMIC_FIELDS, getDynamicFieldsWithFieldType(fieldType));
properties.add(IndexSchema.FIELDS, getFieldsWithFieldType(fieldType));
properties.add(IndexSchema.DYNAMIC_FIELDS, getDynamicFieldsWithFieldType(fieldType));
return properties;
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -18,7 +18,6 @@ package org.apache.solr.rest;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.ContentStreamBase;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;

View File

@ -0,0 +1,97 @@
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.common.params.CommonParams;
import org.apache.solr.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* This class responds to requests at /solr/(corename)/schema/copyfields
*
* <p/>
*
* To restrict the set of copyFields in the response, specify one or both
* of the following as query parameters, with values as space and/or comma
* separated dynamic or explicit field names:
*
* <ul>
* <li>dest.fl: include copyFields that have one of these as a destination</li>
* <li>source.fl: include copyFields that have one of these as a source</li>
* </ul>
*
* If both dest.fl and source.fl are given as query parameters, the copyfields
* in the response will be restricted to those that match any of the destinations
* in dest.fl and also match any of the sources in source.fl.
*/
public class CopyFieldCollectionResource extends BaseFieldResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(CopyFieldCollectionResource.class);
private static final String SOURCE_FIELD_LIST = IndexSchema.SOURCE + "." + CommonParams.FL;
private static final String DESTINATION_FIELD_LIST = IndexSchema.DESTINATION + "." + CommonParams.FL;
private Set<String> requestedSourceFields;
private Set<String> requestedDestinationFields;
public CopyFieldCollectionResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
if (isExisting()) {
String sourceFieldListParam = getSolrRequest().getParams().get(SOURCE_FIELD_LIST);
if (null != sourceFieldListParam) {
String[] fields = sourceFieldListParam.trim().split("[,\\s]+");
if (fields.length > 0) {
requestedSourceFields = new HashSet<String>(Arrays.asList(fields));
requestedSourceFields.remove(""); // Remove empty values, if any
}
}
String destinationFieldListParam = getSolrRequest().getParams().get(DESTINATION_FIELD_LIST);
if (null != destinationFieldListParam) {
String[] fields = destinationFieldListParam.trim().split("[,\\s]+");
if (fields.length > 0) {
requestedDestinationFields = new HashSet<String>(Arrays.asList(fields));
requestedDestinationFields.remove(""); // Remove empty values, if any
}
}
}
}
@Override
public Representation get() {
try {
getSolrResponse().add(IndexSchema.COPY_FIELDS,
getSchema().getCopyFieldProperties(true, requestedSourceFields, requestedDestinationFields));
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
package org.apache.solr.rest.schema;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -19,6 +19,7 @@ package org.apache.solr.rest;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.rest.GETable;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;

View File

@ -0,0 +1,60 @@
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.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class responds to requests at /solr/(corename)/schema/defaultsearchfield
*/
public class DefaultSearchFieldResource extends BaseSchemaResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(DefaultSearchFieldResource.class);
public DefaultSearchFieldResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
}
@Override
public Representation get() {
try {
final String defaultSearchFieldName = getSchema().getDefaultSearchFieldName();
if (null == defaultSearchFieldName) {
final String message = "undefined " + IndexSchema.DEFAULT_SEARCH_FIELD;
throw new SolrException(ErrorCode.NOT_FOUND, message);
}
getSolrResponse().add(IndexSchema.DEFAULT_SEARCH_FIELD, defaultSearchFieldName);
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -20,7 +20,7 @@ import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.schema.FieldType;
import org.apache.solr.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.restlet.representation.Representation;
@ -42,7 +42,6 @@ import java.util.Map;
*/
public class DynamicFieldCollectionResource extends BaseFieldResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(DynamicFieldCollectionResource.class);
private final static String INTERNAL_POLY_FIELD_PREFIX = "*" + FieldType.POLY_FIELD_SEPARATOR;
public DynamicFieldCollectionResource() {
super();
@ -60,7 +59,7 @@ public class DynamicFieldCollectionResource extends BaseFieldResource implements
List<SimpleOrderedMap<Object>> props = new ArrayList<SimpleOrderedMap<Object>>();
if (null == getRequestedFields()) {
for (IndexSchema.DynamicField dynamicField : getSchema().getDynamicFields()) {
if ( ! dynamicField.getRegex().startsWith(INTERNAL_POLY_FIELD_PREFIX)) { // omit internal polyfields
if ( ! dynamicField.getRegex().startsWith(IndexSchema.INTERNAL_POLY_FIELD_PREFIX)) { // omit internal polyfields
props.add(getFieldProperties(dynamicField.getPrototype()));
}
}
@ -83,7 +82,7 @@ public class DynamicFieldCollectionResource extends BaseFieldResource implements
}
}
}
getSolrResponse().add(SchemaRestApi.DYNAMIC_FIELDS, props);
getSolrResponse().add(IndexSchema.DYNAMIC_FIELDS, props);
} catch (Exception e) {
getSolrResponse().setException(e);
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -19,6 +19,8 @@ package org.apache.solr.rest;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
@ -28,14 +30,12 @@ import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
/**
* This class responds to requests at /solr/(corename)/schema/dynamicfields/pattern
* This class responds to requests at /solr/(corename)/schema/dynamicfields/(pattern)
* where pattern is a field name pattern (with an asterisk at the beginning or the end).
*/
public class DynamicFieldResource extends BaseFieldResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(DynamicFieldResource.class);
private static final String DYNAMIC_FIELD = "dynamicfield";
private String fieldNamePattern;
public DynamicFieldResource() {
@ -49,7 +49,7 @@ public class DynamicFieldResource extends BaseFieldResource implements GETable {
public void doInit() throws ResourceException {
super.doInit();
if (isExisting()) {
fieldNamePattern = (String)getRequestAttributes().get(SchemaRestApi.NAME_VARIABLE);
fieldNamePattern = (String)getRequestAttributes().get(IndexSchema.NAME);
try {
fieldNamePattern = null == fieldNamePattern ? "" : urlDecode(fieldNamePattern.trim()).trim();
} catch (UnsupportedEncodingException e) {
@ -76,7 +76,7 @@ public class DynamicFieldResource extends BaseFieldResource implements GETable {
final String message = "Dynamic field '" + fieldNamePattern + "' not found.";
throw new SolrException(ErrorCode.NOT_FOUND, message);
} else {
getSolrResponse().add(DYNAMIC_FIELD, getFieldProperties(field));
getSolrResponse().add(IndexSchema.DYNAMIC_FIELD, getFieldProperties(field));
}
}
} catch (Exception e) {

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -21,6 +21,8 @@ import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
@ -60,7 +62,9 @@ public class FieldCollectionResource extends BaseFieldResource implements GETabl
@Override
public void doInit() throws ResourceException {
super.doInit();
includeDynamic = getSolrRequest().getParams().getBool(INCLUDE_DYNAMIC_PARAM, false);
if (isExisting()) {
includeDynamic = getSolrRequest().getParams().getBool(INCLUDE_DYNAMIC_PARAM, false);
}
}
@Override
@ -92,7 +96,7 @@ public class FieldCollectionResource extends BaseFieldResource implements GETabl
}
}
}
getSolrResponse().add(SchemaRestApi.FIELDS, props);
getSolrResponse().add(IndexSchema.FIELDS, props);
} catch (Exception e) {
getSolrResponse().setException(e);
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -18,6 +18,8 @@ package org.apache.solr.rest;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
@ -27,7 +29,7 @@ import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
/**
* This class responds to requests at /solr/(corename)/schema/fields/fieldname
* This class responds to requests at /solr/(corename)/schema/fields/(fieldname)
* where "fieldname" is the name of a field.
* <p/>
* The GET method returns properties for the given fieldname.
@ -38,8 +40,6 @@ import java.io.UnsupportedEncodingException;
public class FieldResource extends BaseFieldResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(FieldResource.class);
private static final String FIELD = "field";
private boolean includeDynamic;
private String fieldName;
@ -52,7 +52,7 @@ public class FieldResource extends BaseFieldResource implements GETable {
super.doInit();
if (isExisting()) {
includeDynamic = getSolrRequest().getParams().getBool(INCLUDE_DYNAMIC_PARAM, false);
fieldName = (String)getRequestAttributes().get(SchemaRestApi.NAME_VARIABLE);
fieldName = (String)getRequestAttributes().get(IndexSchema.NAME);
try {
fieldName = null == fieldName ? "" : urlDecode(fieldName.trim()).trim();
} catch (UnsupportedEncodingException e) {
@ -78,7 +78,7 @@ public class FieldResource extends BaseFieldResource implements GETable {
final String message = "Field '" + fieldName + "' not found.";
throw new SolrException(ErrorCode.NOT_FOUND, message);
} else {
getSolrResponse().add(FIELD, getFieldProperties(field));
getSolrResponse().add(IndexSchema.FIELD, getFieldProperties(field));
}
}
} catch (Exception e) {

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -17,7 +17,9 @@ package org.apache.solr.rest;
*/
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.rest.GETable;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
@ -39,8 +41,6 @@ import java.util.TreeMap;
public class FieldTypeCollectionResource extends BaseFieldTypeResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(FieldTypeCollectionResource.class);
private static final String FIELD_TYPES = "fieldTypes";
private Map<String,List<String>> fieldsByFieldType;
private Map<String,List<String>> dynamicFieldsByFieldType;
@ -65,7 +65,7 @@ public class FieldTypeCollectionResource extends BaseFieldTypeResource implement
for (FieldType fieldType : sortedFieldTypes.values()) {
props.add(getFieldTypeProperties(fieldType));
}
getSolrResponse().add(FIELD_TYPES, props);
getSolrResponse().add(IndexSchema.FIELD_TYPES, props);
} catch (Exception e) {
getSolrResponse().setException(e);
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -18,7 +18,9 @@ package org.apache.solr.rest;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.rest.GETable;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
@ -31,14 +33,13 @@ import java.util.Collections;
import java.util.List;
/**
* This class responds to requests at /solr/(corename)/schema/fieldtype/typename
* This class responds to requests at /solr/(corename)/schema/fieldtype/(typename)
* where "typename" is the name of a field type in the schema.
*
* The GET method returns properties for the named field type.
*/
public class FieldTypeResource extends BaseFieldTypeResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(FieldTypeResource.class);
private static final String FIELD_TYPE = "fieldType";
private String typeName;
@ -50,7 +51,7 @@ public class FieldTypeResource extends BaseFieldTypeResource implements GETable
public void doInit() throws ResourceException {
super.doInit();
if (isExisting()) {
typeName = (String)getRequestAttributes().get(SchemaRestApi.NAME_VARIABLE);
typeName = (String)getRequestAttributes().get(IndexSchema.NAME);
try {
typeName = null == typeName ? "" : urlDecode(typeName.trim()).trim();
} catch (UnsupportedEncodingException e) {
@ -71,7 +72,7 @@ public class FieldTypeResource extends BaseFieldTypeResource implements GETable
final String message = "Field type '" + typeName + "' not found.";
throw new SolrException(ErrorCode.NOT_FOUND, message);
}
getSolrResponse().add(FIELD_TYPE, getFieldTypeProperties(fieldType));
getSolrResponse().add(IndexSchema.FIELD_TYPE, getFieldTypeProperties(fieldType));
}
} catch (Exception e) {
getSolrResponse().setException(e);

View File

@ -0,0 +1,59 @@
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.common.SolrException;
import org.apache.solr.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class responds to requests at /solr/(corename)/schema/name
*/
public class SchemaNameResource extends BaseSchemaResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(SchemaNameResource.class);
public SchemaNameResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
}
@Override
public Representation get() {
try {
final String schemaName = getSchema().getSchemaName();
if (null == schemaName) {
final String message = "Schema has no name";
throw new SolrException(SolrException.ErrorCode.NOT_FOUND, message);
}
getSolrResponse().add(IndexSchema.NAME, schemaName);
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}

View File

@ -0,0 +1,52 @@
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.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class responds to requests at /solr/(corename)/schema
*/
public class SchemaResource extends BaseSchemaResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(SchemaResource.class);
public SchemaResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
}
@Override
public Representation get() {
try {
getSolrResponse().add(IndexSchema.SCHEMA, getSchema().getNamedPropertyValues());
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}

View File

@ -0,0 +1,55 @@
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.rest.GETable;
import org.apache.solr.rest.SolrRestApi;
import org.apache.solr.schema.IndexSchema;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class responds to requests at /solr/(corename)/schema/similarity
*/
public class SchemaSimilarityResource extends BaseSchemaResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(SchemaSimilarityResource.class);
public SchemaSimilarityResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
}
@Override
public Representation get() {
try {
getSolrResponse().add(IndexSchema.SIMILARITY, getSchema().getSimilarityFactory().getNamedPropertyValues());
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}

View File

@ -0,0 +1,54 @@
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.rest.GETable;
import org.apache.solr.rest.SolrRestApi;
import org.apache.solr.schema.IndexSchema;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class responds to requests at /solr/(corename)/schema/version
*/
public class SchemaVersionResource extends BaseSchemaResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(SchemaVersionResource.class);
public SchemaVersionResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
}
@Override
public Representation get() {
try {
getSolrResponse().add(IndexSchema.VERSION, getSchema().getVersion());
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}

View File

@ -0,0 +1,53 @@
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.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class responds to requests at /solr/(corename)/schema/solrqueryparser/defaultoperator
*/
public class SolrQueryParserDefaultOperatorResource extends BaseSchemaResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(SolrQueryParserDefaultOperatorResource.class);
public SolrQueryParserDefaultOperatorResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
}
@Override
public Representation get() {
try {
getSolrResponse().add(IndexSchema.DEFAULT_OPERATOR, getSchema().getQueryParserDefaultOperator());
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}

View File

@ -0,0 +1,56 @@
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.common.util.SimpleOrderedMap;
import org.apache.solr.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class responds to requests at /solr/(corename)/schema/solrqueryparser
*/
public class SolrQueryParserResource extends BaseSchemaResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(SolrQueryParserResource.class);
public SolrQueryParserResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
}
@Override
public Representation get() {
try {
SimpleOrderedMap<Object> props = new SimpleOrderedMap<Object>();
props.add(IndexSchema.DEFAULT_OPERATOR, getSchema().getQueryParserDefaultOperator());
getSolrResponse().add(IndexSchema.SOLR_QUERY_PARSER, props);
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}

View File

@ -0,0 +1,53 @@
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.rest.GETable;
import org.apache.solr.schema.IndexSchema;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class responds to requests at /solr/(corename)/schema/uniquekey
*/
public class UniqueKeyFieldResource extends BaseSchemaResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(UniqueKeyFieldResource.class);
public UniqueKeyFieldResource() {
super();
}
@Override
public void doInit() throws ResourceException {
super.doInit();
}
@Override
public Representation get() {
try {
getSolrResponse().add(IndexSchema.UNIQUE_KEY, getSchema().getUniqueKeyField().getName());
} catch (Exception e) {
getSolrResponse().setException(e);
}
handlePostExecution(log);
return new SolrOutputRepresentation();
}
}

View File

@ -0,0 +1,29 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<!--
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.
-->
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<p>
Provides RESTful API access to the Solr Schema using Restlet.
</p>
</body>
</html>

View File

@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -58,7 +57,6 @@ import org.apache.solr.analysis.SolrAnalyzer;
import org.apache.solr.analysis.TokenizerChain;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.response.TextResponseWriter;
@ -722,20 +720,27 @@ public abstract class FieldType extends FieldProperties {
}
}
private static final String TYPE_NAME = "name";
private static final String CLASS_NAME = "class";
private static final String ANALYZER = "analyzer";
private static final String INDEX_ANALYZER = "indexAnalyzer";
private static final String QUERY_ANALYZER = "queryAnalyzer";
private static final String MULTI_TERM_ANALYZER = "multiTermAnalyzer";
private static final String SIMILARITY = "similarity";
public static final String TYPE = "type";
public static final String TYPE_NAME = "name";
public static final String CLASS_NAME = "class";
public static final String ANALYZER = "analyzer";
public static final String INDEX = "index";
public static final String INDEX_ANALYZER = "indexAnalyzer";
public static final String QUERY = "query";
public static final String QUERY_ANALYZER = "queryAnalyzer";
public static final String MULTI_TERM = "multiterm";
public static final String MULTI_TERM_ANALYZER = "multiTermAnalyzer";
public static final String SIMILARITY = "similarity";
public static final String CHAR_FILTER = "charFilter";
public static final String CHAR_FILTERS = "charFilters";
public static final String TOKENIZER = "tokenizer";
public static final String FILTER = "filter";
public static final String FILTERS = "filters";
private static final String POSTINGS_FORMAT = "postingsFormat";
private static final String DOC_VALUES_FORMAT = "docValuesFormat";
private static final String AUTO_GENERATE_PHRASE_QUERIES = "autoGeneratePhraseQueries";
private static final String ARGS = "args";
private static final String CHAR_FILTERS = "charFilters";
private static final String TOKENIZER = "tokenizer";
private static final String FILTERS = "filters";
private static final String POSITION_INCREMENT_GAP = "positionIncrementGap";
/**
@ -802,8 +807,8 @@ public abstract class FieldType extends FieldProperties {
namedPropertyValues.add(MULTI_TERM_ANALYZER, getAnalyzerProperties(((TextField) this).getMultiTermAnalyzer()));
}
}
if (null != getSimilarity()) {
namedPropertyValues.add(SIMILARITY, getSimilarityProperties());
if (null != getSimilarityFactory()) {
namedPropertyValues.add(SIMILARITY, getSimilarityFactory().getNamedPropertyValues());
}
if (null != getPostingsFormat()) {
namedPropertyValues.add(POSTINGS_FORMAT, getPostingsFormat());
@ -885,25 +890,8 @@ public abstract class FieldType extends FieldProperties {
private static String normalizeSPIname(String fullyQualifiedName) {
if (fullyQualifiedName.startsWith("org.apache.lucene.") || fullyQualifiedName.startsWith("org.apache.solr.")) {
return "solr" + fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf('.'));
return "solr" + fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf('.'));
}
return fullyQualifiedName;
}
/** Returns a description of this field's similarity, if any */
protected SimpleOrderedMap<Object> getSimilarityProperties() {
SimpleOrderedMap<Object> props = new SimpleOrderedMap<Object>();
if (similarity != null) {
props.add(CLASS_NAME, normalizeSPIname(similarity.getClass().getName()));
SolrParams factoryParams = similarityFactory.getParams();
if (null != factoryParams) {
Iterator<String> iter = factoryParams.getParameterNamesIterator();
while (iter.hasNext()) {
String key = iter.next();
props.add(key, factoryParams.get(key));
}
}
}
return props;
}
}

View File

@ -27,6 +27,7 @@ import org.apache.lucene.util.Version;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.util.DOMUtil;
import org.apache.solr.util.SystemIdResolver;
import org.apache.solr.core.SolrConfig;
@ -51,10 +52,17 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
/**
@ -64,8 +72,39 @@ import java.util.regex.Pattern;
*
*/
public final class IndexSchema {
public static final String COPY_FIELD = "copyField";
public static final String COPY_FIELDS = COPY_FIELD + "s";
public static final String DEFAULT_OPERATOR = "defaultOperator";
public static final String DEFAULT_SCHEMA_FILE = "schema.xml";
public static final String DEFAULT_SEARCH_FIELD = "defaultSearchField";
public static final String DESTINATION = "dest";
public static final String DYNAMIC_FIELD = "dynamicField";
public static final String DYNAMIC_FIELDS = DYNAMIC_FIELD + "s";
public static final String FIELD = "field";
public static final String FIELDS = FIELD + "s";
public static final String FIELD_TYPE = "fieldType";
public static final String FIELD_TYPES = FIELD_TYPE + "s";
public static final String INTERNAL_POLY_FIELD_PREFIX = "*" + FieldType.POLY_FIELD_SEPARATOR;
public static final String LUCENE_MATCH_VERSION_PARAM = "luceneMatchVersion";
public static final String NAME = "name";
public static final String REQUIRED = "required";
public static final String SCHEMA = "schema";
public static final String SIMILARITY = "similarity";
public static final String SOLR_QUERY_PARSER = "solrQueryParser";
public static final String SOURCE = "source";
public static final String TYPES = "types";
public static final String UNIQUE_KEY = "uniqueKey";
public static final String VERSION = "version";
private static final String AT = "@";
private static final String DESTINATION_DYNAMIC_BASE = "destDynamicBase";
private static final String MAX_CHARS = "maxChars";
private static final String SLASH = "/";
private static final String SOURCE_DYNAMIC_BASE = "sourceDynamicBase";
private static final String SOURCE_EXPLICIT_FIELDS = "sourceExplicitFields";
private static final String TEXT_FUNCTION = "text()";
private static final String TYPE = "type";
private static final String XPATH_OR = " | ";
final static Logger log = LoggerFactory.getLogger(IndexSchema.class);
private final SolrConfig solrConfig;
@ -89,6 +128,7 @@ public final class IndexSchema {
private String defaultSearchFieldName=null;
private String queryParserDefaultOperator = "OR";
private boolean isExplicitQueryParserDefaultOperator = false;
private final Map<String, List<CopyField>> copyFieldsMap = new HashMap<String, List<CopyField>>();
@ -150,7 +190,7 @@ public final class IndexSchema {
return solrConfig.luceneMatchVersion;
}
float getVersion() {
public float getVersion() {
return version;
}
@ -207,6 +247,13 @@ public final class IndexSchema {
*/
public Similarity getSimilarity() { return similarity; }
private SimilarityFactory similarityFactory;
private boolean isExplicitSimilarity = false;
/** Returns the SimilarityFactory that constructed the Similarity for this index */
public SimilarityFactory getSimilarityFactory() { return similarityFactory; }
/**
* Returns the Analyzer used when indexing documents for this index
*
@ -350,19 +397,22 @@ public final class IndexSchema {
try {
// pass the config resource loader to avoid building an empty one for no reason:
// in the current case though, the stream is valid so we wont load the resource by name
Config schemaConf = new Config(loader, "schema", is, "/schema/");
Config schemaConf = new Config(loader, SCHEMA, is, SLASH+SCHEMA+SLASH);
Document document = schemaConf.getDocument();
final XPath xpath = schemaConf.getXPath();
final List<SchemaAware> schemaAware = new ArrayList<SchemaAware>();
Node nd = (Node) xpath.evaluate("/schema/@name", document, XPathConstants.NODE);
String expression = stepsToPath(SCHEMA, AT + NAME);
Node nd = (Node) xpath.evaluate(expression, document, XPathConstants.NODE);
if (nd==null) {
log.warn("schema has no name!");
} else {
name = nd.getNodeValue();
log.info("Schema name=" + name);
log.info("Schema " + NAME + "=" + name);
}
version = schemaConf.getFloat("/schema/@version", 1.0f);
// /schema/@version
expression = stepsToPath(SCHEMA, AT + VERSION);
version = schemaConf.getFloat(expression, 1.0f);
// load the Field Types
@ -370,9 +420,10 @@ public final class IndexSchema {
final FieldTypePluginLoader typeLoader
= new FieldTypePluginLoader(this, fieldTypes, schemaAware);
String expression = "/schema/types/fieldtype | /schema/types/fieldType";
NodeList nodes = (NodeList) xpath.evaluate(expression, document,
XPathConstants.NODESET);
// /schema/types/fieldtype | /schema/types/fieldType
expression = stepsToPath(SCHEMA, TYPES, FIELD_TYPE.toLowerCase(Locale.ROOT)) // backcompat(?)
+ XPATH_OR + stepsToPath(SCHEMA, TYPES, FIELD_TYPE);
NodeList nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
typeLoader.load( loader, nodes );
// load the Fields
@ -380,7 +431,10 @@ public final class IndexSchema {
// Hang on to the fields that say if they are required -- this lets us set a reasonable default for the unique key
Map<String,Boolean> explicitRequiredProp = new HashMap<String, Boolean>();
ArrayList<DynamicField> dFields = new ArrayList<DynamicField>();
expression = "/schema/fields/field | /schema/fields/dynamicField";
// /schema/fields/field | /schema/fields/dynamicField
expression = stepsToPath(SCHEMA, FIELDS, FIELD)
+ XPATH_OR + stepsToPath(SCHEMA, FIELDS, DYNAMIC_FIELD);
nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
for (int i=0; i<nodes.getLength(); i++) {
@ -388,23 +442,24 @@ public final class IndexSchema {
NamedNodeMap attrs = node.getAttributes();
String name = DOMUtil.getAttr(attrs,"name","field definition");
String name = DOMUtil.getAttr(attrs, NAME, "field definition");
log.trace("reading field def "+name);
String type = DOMUtil.getAttr(attrs,"type","field " + name);
String type = DOMUtil.getAttr(attrs, TYPE, "field " + name);
FieldType ft = fieldTypes.get(type);
if (ft==null) {
throw new SolrException(ErrorCode.BAD_REQUEST,"Unknown fieldtype '" + type + "' specified on field " + name);
throw new SolrException
(ErrorCode.BAD_REQUEST, "Unknown " + FIELD_TYPE + " '" + type + "' specified on field " + name);
}
Map<String,String> args = DOMUtil.toMapExcept(attrs, "name", "type");
if( args.get( "required" ) != null ) {
explicitRequiredProp.put( name, Boolean.valueOf( args.get( "required" ) ) );
Map<String,String> args = DOMUtil.toMapExcept(attrs, NAME, TYPE);
if (null != args.get(REQUIRED)) {
explicitRequiredProp.put(name, Boolean.valueOf(args.get(REQUIRED)));
}
SchemaField f = SchemaField.create(name,ft,args);
if (node.getNodeName().equals("field")) {
if (node.getNodeName().equals(FIELD)) {
SchemaField old = fields.put(f.getName(),f);
if( old != null ) {
String msg = "[schema.xml] Duplicate field definition for '"
@ -420,7 +475,7 @@ public final class IndexSchema {
log.debug(name+" is required in this schema");
requiredFields.add(f);
}
} else if (node.getNodeName().equals("dynamicField")) {
} else if (node.getNodeName().equals(DYNAMIC_FIELD)) {
if (isValidFieldGlob(name)) {
// make sure nothing else has the same path
addDynamicField(dFields, f);
@ -435,144 +490,155 @@ public final class IndexSchema {
}
}
//fields with default values are by definition required
//add them to required fields, and we only have to loop once
// in DocumentBuilder.getDoc()
requiredFields.addAll(getFieldsWithDefaultValue());
//fields with default values are by definition required
//add them to required fields, and we only have to loop once
// in DocumentBuilder.getDoc()
requiredFields.addAll(getFieldsWithDefaultValue());
// OK, now sort the dynamic fields largest to smallest size so we don't get
// any false matches. We want to act like a compiler tool and try and match
// the largest string possible.
Collections.sort(dFields);
// OK, now sort the dynamic fields largest to smallest size so we don't get
// any false matches. We want to act like a compiler tool and try and match
// the largest string possible.
Collections.sort(dFields);
log.trace("Dynamic Field Ordering:" + dFields);
log.trace("Dynamic Field Ordering:" + dFields);
// stuff it in a normal array for faster access
dynamicFields = dFields.toArray(new DynamicField[dFields.size()]);
// stuff it in a normal array for faster access
dynamicFields = dFields.toArray(new DynamicField[dFields.size()]);
Node node = (Node) xpath.evaluate("/schema/similarity", document, XPathConstants.NODE);
SimilarityFactory simFactory = readSimilarity(loader, node);
if (simFactory == null) {
simFactory = new DefaultSimilarityFactory();
}
if (simFactory instanceof SchemaAware) {
((SchemaAware)simFactory).inform(this);
} else {
// if the sim facotry isn't schema aware, then we are responsible for
// erroring if a field type is trying to specify a sim.
for (FieldType ft : fieldTypes.values()) {
if (null != ft.getSimilarity()) {
String msg = "FieldType '" + ft.getTypeName() + "' is configured with a similarity, but the global similarity does not support it: " + simFactory.getClass();
expression = stepsToPath(SCHEMA, SIMILARITY); // /schema/similarity
Node node = (Node) xpath.evaluate(expression, document, XPathConstants.NODE);
similarityFactory = readSimilarity(loader, node);
if (similarityFactory == null) {
similarityFactory = new DefaultSimilarityFactory();
} else {
isExplicitSimilarity = true;
}
if (similarityFactory instanceof SchemaAware) {
((SchemaAware)similarityFactory).inform(this);
} else {
// if the sim factory isn't schema aware, then we are responsible for
// erroring if a field type is trying to specify a sim.
for (FieldType ft : fieldTypes.values()) {
if (null != ft.getSimilarity()) {
String msg = "FieldType '" + ft.getTypeName()
+ "' is configured with a similarity, but the global similarity does not support it: "
+ similarityFactory.getClass();
log.error(msg);
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
}
}
}
similarity = similarityFactory.getSimilarity();
// /schema/defaultSearchField/@text()
expression = stepsToPath(SCHEMA, DEFAULT_SEARCH_FIELD, TEXT_FUNCTION);
node = (Node) xpath.evaluate(expression, document, XPathConstants.NODE);
if (node==null) {
log.debug("no default search field specified in schema.");
} else {
defaultSearchFieldName=node.getNodeValue().trim();
// throw exception if specified, but not found or not indexed
if (defaultSearchFieldName!=null) {
SchemaField defaultSearchField = getFields().get(defaultSearchFieldName);
if ((defaultSearchField == null) || !defaultSearchField.indexed()) {
String msg = "default search field '" + defaultSearchFieldName + "' not defined or not indexed" ;
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
}
}
log.info("default search field in schema is "+defaultSearchFieldName);
}
// /schema/solrQueryParser/@defaultOperator
expression = stepsToPath(SCHEMA, SOLR_QUERY_PARSER, AT + DEFAULT_OPERATOR);
node = (Node) xpath.evaluate(expression, document, XPathConstants.NODE);
if (node==null) {
log.debug("using default query parser operator (OR)");
} else {
isExplicitQueryParserDefaultOperator = true;
queryParserDefaultOperator=node.getNodeValue().trim();
log.info("query parser default operator is "+queryParserDefaultOperator);
}
// /schema/uniqueKey/text()
expression = stepsToPath(SCHEMA, UNIQUE_KEY, TEXT_FUNCTION);
node = (Node) xpath.evaluate(expression, document, XPathConstants.NODE);
if (node==null) {
log.warn("no " + UNIQUE_KEY + " specified in schema.");
} else {
uniqueKeyField=getIndexedField(node.getNodeValue().trim());
if (null != uniqueKeyField.getDefaultValue()) {
String msg = UNIQUE_KEY + " field ("+uniqueKeyFieldName+
") can not be configured with a default value ("+
uniqueKeyField.getDefaultValue()+")";
log.error(msg);
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
}
}
}
similarity = simFactory.getSimilarity();
node = (Node) xpath.evaluate("/schema/defaultSearchField/text()", document, XPathConstants.NODE);
if (node==null) {
log.debug("no default search field specified in schema.");
} else {
defaultSearchFieldName=node.getNodeValue().trim();
// throw exception if specified, but not found or not indexed
if (defaultSearchFieldName!=null) {
SchemaField defaultSearchField = getFields().get(defaultSearchFieldName);
if ((defaultSearchField == null) || !defaultSearchField.indexed()) {
String msg = "default search field '" + defaultSearchFieldName + "' not defined or not indexed" ;
if (!uniqueKeyField.stored()) {
log.warn(UNIQUE_KEY + " is not stored - distributed search and MoreLikeThis will not work");
}
if (uniqueKeyField.multiValued()) {
String msg = UNIQUE_KEY + " field ("+uniqueKeyFieldName+
") can not be configured to be multivalued";
log.error(msg);
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
}
}
log.info("default search field in schema is "+defaultSearchFieldName);
}
node = (Node) xpath.evaluate("/schema/solrQueryParser/@defaultOperator", document, XPathConstants.NODE);
if (node==null) {
log.debug("using default query parser operator (OR)");
} else {
queryParserDefaultOperator=node.getNodeValue().trim();
log.info("query parser default operator is "+queryParserDefaultOperator);
}
node = (Node) xpath.evaluate("/schema/uniqueKey/text()", document, XPathConstants.NODE);
if (node==null) {
log.warn("no uniqueKey specified in schema.");
} else {
uniqueKeyField=getIndexedField(node.getNodeValue().trim());
if (null != uniqueKeyField.getDefaultValue()) {
String msg = "uniqueKey field ("+uniqueKeyFieldName+
") can not be configured with a default value ("+
uniqueKeyField.getDefaultValue()+")";
log.error(msg);
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
}
if (!uniqueKeyField.stored()) {
log.warn("uniqueKey is not stored - distributed search and MoreLikeThis will not work");
}
if (uniqueKeyField.multiValued()) {
String msg = "uniqueKey field ("+uniqueKeyFieldName+
") can not be configured to be multivalued";
log.error(msg);
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
}
uniqueKeyFieldName=uniqueKeyField.getName();
uniqueKeyFieldType=uniqueKeyField.getType();
log.info("unique key field: "+uniqueKeyFieldName);
uniqueKeyFieldName=uniqueKeyField.getName();
uniqueKeyFieldType=uniqueKeyField.getType();
log.info("unique key field: "+uniqueKeyFieldName);
// Unless the uniqueKeyField is marked 'required=false' then make sure it exists
if( Boolean.FALSE != explicitRequiredProp.get( uniqueKeyFieldName ) ) {
uniqueKeyField.required = true;
requiredFields.add(uniqueKeyField);
}
}
// Unless the uniqueKeyField is marked 'required=false' then make sure it exists
if( Boolean.FALSE != explicitRequiredProp.get( uniqueKeyFieldName ) ) {
uniqueKeyField.required = true;
requiredFields.add(uniqueKeyField);
}
}
/////////////// parse out copyField commands ///////////////
// Map<String,ArrayList<SchemaField>> cfields = new HashMap<String,ArrayList<SchemaField>>();
// expression = "/schema/copyField";
/////////////// parse out copyField commands ///////////////
// Map<String,ArrayList<SchemaField>> cfields = new HashMap<String,ArrayList<SchemaField>>();
// expression = "/schema/copyField";
dynamicCopyFields = new DynamicCopy[] {};
expression = "//copyField";
nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
dynamicCopyFields = new DynamicCopy[] {};
expression = "//" + COPY_FIELD;
nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
for (int i=0; i<nodes.getLength(); i++) {
node = nodes.item(i);
NamedNodeMap attrs = node.getAttributes();
String source = DOMUtil.getAttr(attrs,"source","copyField definition");
String dest = DOMUtil.getAttr(attrs,"dest", "copyField definition");
String maxChars = DOMUtil.getAttr(attrs, "maxChars");
String source = DOMUtil.getAttr(attrs, SOURCE, COPY_FIELD + " definition");
String dest = DOMUtil.getAttr(attrs, DESTINATION, COPY_FIELD + " definition");
String maxChars = DOMUtil.getAttr(attrs, MAX_CHARS);
int maxCharsInt = CopyField.UNLIMITED;
if (maxChars != null) {
try {
maxCharsInt = Integer.parseInt(maxChars);
} catch (NumberFormatException e) {
log.warn("Couldn't parse maxChars attribute for copyField from "
log.warn("Couldn't parse " + MAX_CHARS + " attribute for " + COPY_FIELD + " from "
+ source + " to " + dest + " as integer. The whole field will be copied.");
}
}
if (dest.equals(uniqueKeyFieldName)) {
String msg = "uniqueKey field ("+uniqueKeyFieldName+
") can not be the dest of a copyField (src="+source+")";
String msg = UNIQUE_KEY + " field ("+uniqueKeyFieldName+
") can not be the " + DESTINATION + " of a " + COPY_FIELD + "(" + SOURCE + "=" +source+")";
log.error(msg);
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
}
registerCopyField(source, dest, maxCharsInt);
}
}
for (Map.Entry<SchemaField, Integer> entry : copyFieldTargetCounts.entrySet()) {
for (Map.Entry<SchemaField, Integer> entry : copyFieldTargetCounts.entrySet()) {
if (entry.getValue() > 1 && !entry.getKey().multiValued()) {
log.warn("Field " + entry.getKey().name + " is not multivalued "+
"and destination for multiple copyFields ("+
entry.getValue()+")");
"and destination for multiple " + COPY_FIELDS + " ("+
entry.getValue()+")");
}
}
//Run the callbacks on SchemaAware now that everything else is done
for (SchemaAware aware : schemaAware) {
aware.inform(this);
@ -588,6 +654,17 @@ public final class IndexSchema {
refreshAnalyzers();
}
/**
* Converts a sequence of path steps into a rooted path, by inserting slashes in front of each step.
* @param steps The steps to join with slashes to form a path
* @return a rooted path: a leading slash followed by the given steps joined with slashes
*/
private String stepsToPath(String... steps) {
StringBuilder builder = new StringBuilder();
for (String step : steps) { builder.append(SLASH).append(step); }
return builder.toString();
}
/** Returns true if the given name has exactly one asterisk either at the start or end of the name */
private static boolean isValidFieldGlob(String name) {
if (name.startsWith("*") || name.endsWith("*")) {
@ -651,7 +728,8 @@ public final class IndexSchema {
* @see SolrCoreAware
*/
public void registerCopyField(String source, String dest, int maxChars) {
log.debug("copyField source='" + source + "' dest='" + dest + "' maxChars=" + maxChars);
log.debug(COPY_FIELD + " " + SOURCE + "='" + source + "' " + DESTINATION + "='" + dest
+ "' " + MAX_CHARS + "=" + maxChars);
DynamicField destDynamicField = null;
SchemaField destSchemaField = fields.get(dest);
@ -1146,4 +1224,132 @@ public final class IndexSchema {
public boolean isCopyFieldTarget( SchemaField f ) {
return copyFieldTargetCounts.containsKey( f );
}
/**
* Get a map of property name -> value for this field.
*/
public SimpleOrderedMap<Object> getNamedPropertyValues() {
SimpleOrderedMap<Object> topLevel = new SimpleOrderedMap<Object>();
topLevel.add(NAME, getSchemaName());
topLevel.add(VERSION, getVersion());
if (null != uniqueKeyFieldName) {
topLevel.add(UNIQUE_KEY, uniqueKeyFieldName);
}
if (null != defaultSearchFieldName) {
topLevel.add(DEFAULT_SEARCH_FIELD, defaultSearchFieldName);
}
if (isExplicitQueryParserDefaultOperator) {
SimpleOrderedMap<Object> solrQueryParserProperties = new SimpleOrderedMap<Object>();
solrQueryParserProperties.add(DEFAULT_OPERATOR, queryParserDefaultOperator);
topLevel.add(SOLR_QUERY_PARSER, solrQueryParserProperties);
}
if (isExplicitSimilarity) {
topLevel.add(SIMILARITY, similarityFactory.getNamedPropertyValues());
}
List<SimpleOrderedMap<Object>> fieldTypeProperties = new ArrayList<SimpleOrderedMap<Object>>();
SortedMap<String,FieldType> sortedFieldTypes = new TreeMap<String,FieldType>(fieldTypes);
for (FieldType fieldType : sortedFieldTypes.values()) {
fieldTypeProperties.add(fieldType.getNamedPropertyValues(false));
}
topLevel.add(FIELD_TYPES, fieldTypeProperties);
List<SimpleOrderedMap<Object>> fieldProperties = new ArrayList<SimpleOrderedMap<Object>>();
SortedSet<String> fieldNames = new TreeSet<String>(fields.keySet());
for (String fieldName : fieldNames) {
fieldProperties.add(fields.get(fieldName).getNamedPropertyValues(false));
}
topLevel.add(FIELDS, fieldProperties);
List<SimpleOrderedMap<Object>> dynamicFieldProperties = new ArrayList<SimpleOrderedMap<Object>>();
for (IndexSchema.DynamicField dynamicField : dynamicFields) {
if ( ! dynamicField.getRegex().startsWith(INTERNAL_POLY_FIELD_PREFIX)) { // omit internal polyfields
dynamicFieldProperties.add(dynamicField.getPrototype().getNamedPropertyValues(false));
}
}
topLevel.add(DYNAMIC_FIELDS, dynamicFieldProperties);
topLevel.add(COPY_FIELDS, getCopyFieldProperties(false, null, null));
return topLevel;
}
/**
* Returns a list of copyField directives, with optional details and optionally restricting to those
* directives that contain the requested source and/or destination field names.
*
* @param showDetails If true, source and destination dynamic bases, and explicit fields matched by source globs,
* will be added to dynamic copyField directives where appropriate
* @param requestedSourceFields If not null, output is restricted to those copyField directives
* with the requested source field names
* @param requestedDestinationFields If not null, output is restricted to those copyField directives
* with the requested destination field names
* @return a list of copyField directives
*/
public List<SimpleOrderedMap<Object>> getCopyFieldProperties
(boolean showDetails, Set<String> requestedSourceFields, Set<String> requestedDestinationFields) {
List<SimpleOrderedMap<Object>> copyFieldProperties = new ArrayList<SimpleOrderedMap<Object>>();
SortedMap<String,List<CopyField>> sortedCopyFields = new TreeMap<String,List<CopyField>>(copyFieldsMap);
for (List<CopyField> copyFields : sortedCopyFields.values()) {
Collections.sort(copyFields, new Comparator<CopyField>() {
@Override
public int compare(CopyField cf1, CopyField cf2) {
// sources are all be the same, just sorting by destination here
return cf1.getDestination().getName().compareTo(cf2.getDestination().getName());
}
});
for (CopyField copyField : copyFields) {
final String source = copyField.getSource().getName();
final String destination = copyField.getDestination().getName();
if ( (null == requestedSourceFields || requestedSourceFields.contains(source))
&& (null == requestedDestinationFields || requestedDestinationFields.contains(destination))) {
SimpleOrderedMap<Object> props = new SimpleOrderedMap<Object>();
props.add(SOURCE, source);
props.add(DESTINATION, destination);
if (0 != copyField.getMaxChars()) {
props.add(MAX_CHARS, copyField.getMaxChars());
}
copyFieldProperties.add(props);
}
}
}
for (IndexSchema.DynamicCopy dynamicCopy : dynamicCopyFields) {
final String source = dynamicCopy.getRegex();
final String destination = dynamicCopy.getDestFieldName();
if ( (null == requestedSourceFields || requestedSourceFields.contains(source))
&& (null == requestedDestinationFields || requestedDestinationFields.contains(destination))) {
SimpleOrderedMap<Object> dynamicCopyProps = new SimpleOrderedMap<Object>();
dynamicCopyProps.add(SOURCE, dynamicCopy.getRegex());
if (showDetails) {
IndexSchema.DynamicField sourceDynamicBase = dynamicCopy.getSourceDynamicBase();
if (null != sourceDynamicBase) {
dynamicCopyProps.add(SOURCE_DYNAMIC_BASE, sourceDynamicBase.getRegex());
} else if (source.contains("*")) {
List<String> sourceExplicitFields = new ArrayList<String>();
Pattern pattern = Pattern.compile(source.replace("*", ".*")); // glob->regex
for (String field : fields.keySet()) {
if (pattern.matcher(field).matches()) {
sourceExplicitFields.add(field);
}
}
if (sourceExplicitFields.size() > 0) {
Collections.sort(sourceExplicitFields);
dynamicCopyProps.add(SOURCE_EXPLICIT_FIELDS, sourceExplicitFields);
}
}
}
dynamicCopyProps.add(DESTINATION, dynamicCopy.getDestFieldName());
if (showDetails) {
IndexSchema.DynamicField destDynamicBase = dynamicCopy.getDestDynamicBase();
if (null != destDynamicBase) {
dynamicCopyProps.add(DESTINATION_DYNAMIC_BASE, destDynamicBase.getRegex());
}
}
if (0 != dynamicCopy.getMaxChars()) {
dynamicCopyProps.add(MAX_CHARS, dynamicCopy.getMaxChars());
}
copyFieldProperties.add(dynamicCopyProps);
}
}
return copyFieldProperties;
}
}

View File

@ -17,10 +17,13 @@ package org.apache.solr.schema;
*/
import org.apache.lucene.search.similarities.Similarity;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.schema.SchemaAware; // javadocs
import org.apache.solr.schema.FieldType; // javadocs
import org.apache.solr.common.params.SolrParams;
import java.util.Iterator;
/**
* A factory interface for configuring a {@link Similarity} in the Solr
@ -38,10 +41,42 @@ import org.apache.solr.common.params.SolrParams;
* @see FieldType#getSimilarity
*/
public abstract class SimilarityFactory {
public static final String CLASS_NAME = "class";
protected SolrParams params;
public void init(SolrParams params) { this.params = params; }
public SolrParams getParams() { return params; }
public abstract Similarity getSimilarity();
private static String normalizeSPIname(String fullyQualifiedName) {
if (fullyQualifiedName.startsWith("org.apache.lucene.") || fullyQualifiedName.startsWith("org.apache.solr.")) {
return "solr" + fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf('.'));
}
return fullyQualifiedName;
}
/** Returns a description of this field's similarity, if any */
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 normalize factory names
className = normalizeSPIname(className);
}
SimpleOrderedMap<Object> props = new SimpleOrderedMap<Object>();
props.add(CLASS_NAME, normalizeSPIname(className));
if (null != params) {
Iterator<String> iter = params.getParameterNamesIterator();
while (iter.hasNext()) {
String key = iter.next();
props.add(key, params.get(key));
}
}
return props;
}
}

View File

@ -623,4 +623,6 @@
<copyField source="title_*" dest="*_dest_sub_s"/>
<copyField source="title_*" dest="dest_sub_no_ast_s"/>
<solrQueryParser defaultOperator="OR"/>
</schema>

View File

@ -24,13 +24,13 @@ import org.restlet.ext.servlet.ServerServlet;
import java.util.SortedMap;
import java.util.TreeMap;
abstract public class SchemaRestletTestBase extends RestTestBase {
abstract public class SolrRestletTestBase extends RestTestBase {
@BeforeClass
public static void init() throws Exception {
final SortedMap<ServletHolder,String> extraServlets = new TreeMap<ServletHolder,String>();
final ServletHolder schemaRestApi = new ServletHolder("SchemaRestApi", ServerServlet.class);
schemaRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SchemaRestApi");
extraServlets.put(schemaRestApi, "/schema/*");
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.xml", "schema-rest.xml", "/solr", true, extraServlets);
}

View File

@ -1,70 +0,0 @@
package org.apache.solr.rest;
/*
* 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.junit.Test;
public class TestDynamicFieldResource extends SchemaRestletTestBase {
@Test
public void testGetDynamicField() throws Exception {
assertQ("/schema/dynamicfields/*_i?indent=on&wt=xml&showDefaults=on",
"count(/response/lst[@name='dynamicfield']) = 1",
"/response/lst[@name='dynamicfield']/str[@name='name'] = '*_i'",
"/response/lst[@name='dynamicfield']/str[@name='type'] = 'int'",
"/response/lst[@name='dynamicfield']/bool[@name='indexed'] = 'true'",
"/response/lst[@name='dynamicfield']/bool[@name='stored'] = 'true'",
"/response/lst[@name='dynamicfield']/bool[@name='docValues'] = 'false'",
"/response/lst[@name='dynamicfield']/bool[@name='termVectors'] = 'false'",
"/response/lst[@name='dynamicfield']/bool[@name='termPositions'] = 'false'",
"/response/lst[@name='dynamicfield']/bool[@name='termOffsets'] = 'false'",
"/response/lst[@name='dynamicfield']/bool[@name='omitNorms'] = 'true'",
"/response/lst[@name='dynamicfield']/bool[@name='omitTermFreqAndPositions'] = 'true'",
"/response/lst[@name='dynamicfield']/bool[@name='omitPositions'] = 'false'",
"/response/lst[@name='dynamicfield']/bool[@name='storeOffsetsWithPositions'] = 'false'",
"/response/lst[@name='dynamicfield']/bool[@name='multiValued'] = 'false'",
"/response/lst[@name='dynamicfield']/bool[@name='required'] = 'false'",
"/response/lst[@name='dynamicfield']/bool[@name='tokenized'] = 'false'");
}
@Test
public void testGetNotFoundDynamicField() throws Exception {
assertQ("/schema/dynamicfields/*not_in_there?indent=on&wt=xml",
"count(/response/lst[@name='dynamicfield']) = 0",
"/response/lst[@name='responseHeader']/int[@name='status'] = '404'",
"/response/lst[@name='error']/int[@name='code'] = '404'");
}
@Test
public void testJsonGetDynamicField() throws Exception {
assertJQ("/schema/dynamicfields/*_i?indent=on&showDefaults=on",
"/dynamicfield/name=='*_i'",
"/dynamicfield/type=='int'",
"/dynamicfield/indexed==true",
"/dynamicfield/stored==true",
"/dynamicfield/docValues==false",
"/dynamicfield/termVectors==false",
"/dynamicfield/termPositions==false",
"/dynamicfield/termOffsets==false",
"/dynamicfield/omitNorms==true",
"/dynamicfield/omitTermFreqAndPositions==true",
"/dynamicfield/omitPositions==false",
"/dynamicfield/storeOffsetsWithPositions==false",
"/dynamicfield/multiValued==false",
"/dynamicfield/required==false",
"/dynamicfield/tokenized==false");
}
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -16,86 +16,87 @@ package org.apache.solr.rest;
* limitations under the License.
*/
import org.apache.solr.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestCopyFieldCollectionResource extends SchemaRestletTestBase {
public class TestCopyFieldCollectionResource extends SolrRestletTestBase {
@Test
public void testGetAllCopyFields() throws Exception {
assertQ("/schema/copyfields?indent=on&wt=xml",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='title']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='title']"
+" and str[@name='dest'][.='title_stemmed']"
+" and int[@name='maxChars'][.='200']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='title']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='title']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']"
+" and str[@name='destDynamicBase'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='*_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='*_i']"
+" and str[@name='dest'][.='title']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='*_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='*_i']"
+" and str[@name='dest'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='*_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='*_i']"
+" and str[@name='dest'][.='*_dest_sub_s']"
+" and str[@name='destDynamicBase'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='*_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='*_i']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']"
+" and str[@name='destDynamicBase'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='*_src_sub_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='*_src_sub_i']"
+" and str[@name='sourceDynamicBase'][.='*_i']"
+" and str[@name='dest'][.='title']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='*_src_sub_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='*_src_sub_i']"
+" and str[@name='sourceDynamicBase'][.='*_i']"
+" and str[@name='dest'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='*_src_sub_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='*_src_sub_i']"
+" and str[@name='sourceDynamicBase'][.='*_i']"
+" and str[@name='dest'][.='*_dest_sub_s']"
+" and str[@name='destDynamicBase'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='*_src_sub_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='*_src_sub_i']"
+" and str[@name='sourceDynamicBase'][.='*_i']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']"
+" and str[@name='destDynamicBase'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
+" and str[@name='sourceDynamicBase'][.='*_i']"
+" and str[@name='dest'][.='title']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
+" and str[@name='sourceDynamicBase'][.='*_i']"
+" and str[@name='dest'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
+" and str[@name='sourceDynamicBase'][.='*_i']"
+" and str[@name='dest'][.='*_dest_sub_s']"
+" and str[@name='destDynamicBase'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
+" and str[@name='sourceDynamicBase'][.='*_i']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']"
+" and str[@name='destDynamicBase'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='title_*']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='title_*']"
+" and arr[@name='sourceExplicitFields']/str[.='title_stemmed']"
+" and arr[@name='sourceExplicitFields']/str[.='title_lettertok']"
+" and str[@name='dest'][.='text']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='title_*']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='title_*']"
+" and arr[@name='sourceExplicitFields']/str[.='title_stemmed']"
+" and arr[@name='sourceExplicitFields']/str[.='title_lettertok']"
+" and str[@name='dest'][.='*_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='title_*']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='title_*']"
+" and arr[@name='sourceExplicitFields']/str[.='title_stemmed']"
+" and arr[@name='sourceExplicitFields']/str[.='title_lettertok']"
+" and str[@name='dest'][.='*_dest_sub_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='title_*']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='title_*']"
+" and arr[@name='sourceExplicitFields']/str[.='title_stemmed']"
+" and arr[@name='sourceExplicitFields']/str[.='title_lettertok']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']]");
@ -104,57 +105,57 @@ public class TestCopyFieldCollectionResource extends SchemaRestletTestBase {
@Test
public void testJsonGetAllCopyFields() throws Exception {
assertJQ("/schema/copyfields?indent=on&wt=json",
"/copyfields/[6]=={'source':'title','dest':'dest_sub_no_ast_s','destDynamicBase':'*_s'}",
"/copyFields/[6]=={'source':'title','dest':'dest_sub_no_ast_s','destDynamicBase':'*_s'}",
"/copyfields/[7]=={'source':'*_i','dest':'title'}",
"/copyfields/[8]=={'source':'*_i','dest':'*_s'}",
"/copyfields/[9]=={'source':'*_i','dest':'*_dest_sub_s','destDynamicBase':'*_s'}",
"/copyfields/[10]=={'source':'*_i','dest':'dest_sub_no_ast_s','destDynamicBase':'*_s'}",
"/copyFields/[7]=={'source':'*_i','dest':'title'}",
"/copyFields/[8]=={'source':'*_i','dest':'*_s'}",
"/copyFields/[9]=={'source':'*_i','dest':'*_dest_sub_s','destDynamicBase':'*_s'}",
"/copyFields/[10]=={'source':'*_i','dest':'dest_sub_no_ast_s','destDynamicBase':'*_s'}",
"/copyfields/[11]=={'source':'*_src_sub_i','sourceDynamicBase':'*_i','dest':'title'}",
"/copyfields/[12]=={'source':'*_src_sub_i','sourceDynamicBase':'*_i','dest':'*_s'}",
"/copyfields/[13]=={'source':'*_src_sub_i','sourceDynamicBase':'*_i','dest':'*_dest_sub_s','destDynamicBase':'*_s'}",
"/copyfields/[14]=={'source':'*_src_sub_i','sourceDynamicBase':'*_i','dest':'dest_sub_no_ast_s','destDynamicBase':'*_s'}",
"/copyFields/[11]=={'source':'*_src_sub_i','sourceDynamicBase':'*_i','dest':'title'}",
"/copyFields/[12]=={'source':'*_src_sub_i','sourceDynamicBase':'*_i','dest':'*_s'}",
"/copyFields/[13]=={'source':'*_src_sub_i','sourceDynamicBase':'*_i','dest':'*_dest_sub_s','destDynamicBase':'*_s'}",
"/copyFields/[14]=={'source':'*_src_sub_i','sourceDynamicBase':'*_i','dest':'dest_sub_no_ast_s','destDynamicBase':'*_s'}",
"/copyfields/[15]=={'source':'src_sub_no_ast_i','sourceDynamicBase':'*_i','dest':'title'}",
"/copyfields/[16]=={'source':'src_sub_no_ast_i','sourceDynamicBase':'*_i','dest':'*_s'}",
"/copyfields/[17]=={'source':'src_sub_no_ast_i','sourceDynamicBase':'*_i','dest':'*_dest_sub_s','destDynamicBase':'*_s'}",
"/copyfields/[18]=={'source':'src_sub_no_ast_i','sourceDynamicBase':'*_i','dest':'dest_sub_no_ast_s','destDynamicBase':'*_s'}");
"/copyFields/[15]=={'source':'src_sub_no_ast_i','sourceDynamicBase':'*_i','dest':'title'}",
"/copyFields/[16]=={'source':'src_sub_no_ast_i','sourceDynamicBase':'*_i','dest':'*_s'}",
"/copyFields/[17]=={'source':'src_sub_no_ast_i','sourceDynamicBase':'*_i','dest':'*_dest_sub_s','destDynamicBase':'*_s'}",
"/copyFields/[18]=={'source':'src_sub_no_ast_i','sourceDynamicBase':'*_i','dest':'dest_sub_no_ast_s','destDynamicBase':'*_s'}");
}
@Test
public void testRestrictSource() throws Exception {
assertQ("/schema/copyfields/?indent=on&wt=xml&source.fl=title,*_i,*_src_sub_i,src_sub_no_ast_i",
"count(/response/arr[@name='copyfields']/lst) = 16", // 4 + 4 + 4 + 4
"count(/response/arr[@name='copyfields']/lst/str[@name='source'][.='title']) = 4",
"count(/response/arr[@name='copyfields']/lst/str[@name='source'][.='*_i']) = 4",
"count(/response/arr[@name='copyfields']/lst/str[@name='source'][.='*_src_sub_i']) = 4",
"count(/response/arr[@name='copyfields']/lst/str[@name='source'][.='src_sub_no_ast_i']) = 4");
"count(/response/arr[@name='copyFields']/lst) = 16", // 4 + 4 + 4 + 4
"count(/response/arr[@name='copyFields']/lst/str[@name='source'][.='title']) = 4",
"count(/response/arr[@name='copyFields']/lst/str[@name='source'][.='*_i']) = 4",
"count(/response/arr[@name='copyFields']/lst/str[@name='source'][.='*_src_sub_i']) = 4",
"count(/response/arr[@name='copyFields']/lst/str[@name='source'][.='src_sub_no_ast_i']) = 4");
}
@Test
public void testRestrictDest() throws Exception {
assertQ("/schema/copyfields/?indent=on&wt=xml&dest.fl=title,*_s,*_dest_sub_s,dest_sub_no_ast_s",
"count(/response/arr[@name='copyfields']/lst) = 16", // 3 + 4 + 4 + 5
"count(/response/arr[@name='copyfields']/lst/str[@name='dest'][.='title']) = 3",
"count(/response/arr[@name='copyfields']/lst/str[@name='dest'][.='*_s']) = 4",
"count(/response/arr[@name='copyfields']/lst/str[@name='dest'][.='*_dest_sub_s']) = 4",
"count(/response/arr[@name='copyfields']/lst/str[@name='dest'][.='dest_sub_no_ast_s']) = 5");
"count(/response/arr[@name='copyFields']/lst) = 16", // 3 + 4 + 4 + 5
"count(/response/arr[@name='copyFields']/lst/str[@name='dest'][.='title']) = 3",
"count(/response/arr[@name='copyFields']/lst/str[@name='dest'][.='*_s']) = 4",
"count(/response/arr[@name='copyFields']/lst/str[@name='dest'][.='*_dest_sub_s']) = 4",
"count(/response/arr[@name='copyFields']/lst/str[@name='dest'][.='dest_sub_no_ast_s']) = 5");
}
@Test
public void testRestrictSourceAndDest() throws Exception {
assertQ("/schema/copyfields/?indent=on&wt=xml&source.fl=title,*_i&dest.fl=title,dest_sub_no_ast_s",
"count(/response/arr[@name='copyfields']/lst) = 3",
"count(/response/arr[@name='copyFields']/lst) = 3",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='title']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='title']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='*_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='*_i']"
+" and str[@name='dest'][.='title']]",
"/response/arr[@name='copyfields']/lst[ str[@name='source'][.='*_i']"
"/response/arr[@name='copyFields']/lst[ str[@name='source'][.='*_i']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']]");
}
}

View File

@ -0,0 +1,29 @@
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.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestDefaultSearchFieldResource extends SolrRestletTestBase {
@Test
public void testGetDefaultSearchField() throws Exception {
assertQ("/schema/defaultsearchfield?indent=on&wt=xml",
"count(/response/str[@name='defaultSearchField']) = 1",
"/response/str[@name='defaultSearchField'][.='text']");
}
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -16,47 +16,47 @@ package org.apache.solr.rest;
* limitations under the License.
*/
import org.apache.solr.rest.SolrRestletTestBase;
import org.junit.Test;
import java.io.IOException;
public class TestDynamicFieldCollectionResource extends SchemaRestletTestBase {
public class TestDynamicFieldCollectionResource extends SolrRestletTestBase {
@Test
public void testGetAllDynamicFields() throws Exception {
assertQ("/schema/dynamicfields?indent=on&wt=xml",
"(/response/arr[@name='dynamicfields']/lst/str[@name='name'])[1] = '*_coordinate'",
"(/response/arr[@name='dynamicfields']/lst/str[@name='name'])[2] = 'ignored_*'",
"(/response/arr[@name='dynamicfields']/lst/str[@name='name'])[3] = '*_mfacet'",
"count(//copySources/str)=count(//copyDests/str)");
"(/response/arr[@name='dynamicFields']/lst/str[@name='name'])[1] = '*_coordinate'",
"(/response/arr[@name='dynamicFields']/lst/str[@name='name'])[2] = 'ignored_*'",
"(/response/arr[@name='dynamicFields']/lst/str[@name='name'])[3] = '*_mfacet'");
}
@Test
public void testGetTwoDynamicFields() throws IOException {
assertQ("/schema/dynamicfields?indent=on&wt=xml&fl=*_i,*_s",
"count(/response/arr[@name='dynamicfields']/lst/str[@name='name']) = 2",
"(/response/arr[@name='dynamicfields']/lst/str[@name='name'])[1] = '*_i'",
"(/response/arr[@name='dynamicfields']/lst/str[@name='name'])[2] = '*_s'");
"count(/response/arr[@name='dynamicFields']/lst/str[@name='name']) = 2",
"(/response/arr[@name='dynamicFields']/lst/str[@name='name'])[1] = '*_i'",
"(/response/arr[@name='dynamicFields']/lst/str[@name='name'])[2] = '*_s'");
}
@Test
public void testNotFoundDynamicFields() throws IOException {
assertQ("/schema/dynamicfields?indent=on&wt=xml&fl=*_not_in_there,this_one_isnt_either_*",
"count(/response/arr[@name='dynamicfields']) = 1",
"count(/response/arr[@name='dynamicfields']/lst/str[@name='name']) = 0");
"count(/response/arr[@name='dynamicFields']) = 1",
"count(/response/arr[@name='dynamicfields']/lst/str[@name='name']) = 0");
}
@Test
public void testJsonGetAllDynamicFields() throws Exception {
assertJQ("/schema/dynamicfields?indent=on",
"/dynamicfields/[0]/name=='*_coordinate'",
"/dynamicfields/[1]/name=='ignored_*'",
"/dynamicfields/[2]/name=='*_mfacet'");
"/dynamicFields/[0]/name=='*_coordinate'",
"/dynamicFields/[1]/name=='ignored_*'",
"/dynamicFields/[2]/name=='*_mfacet'");
}
@Test
public void testJsonGetTwoDynamicFields() throws Exception {
assertJQ("/schema/dynamicfields?indent=on&fl=*_i,*_s&wt=xml", // assertJQ will fix the wt param to be json
"/dynamicfields/[0]/name=='*_i'",
"/dynamicfields/[1]/name=='*_s'");
"/dynamicFields/[0]/name=='*_i'",
"/dynamicFields/[1]/name=='*_s'");
}
}

View File

@ -0,0 +1,71 @@
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.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestDynamicFieldResource extends SolrRestletTestBase {
@Test
public void testGetDynamicField() throws Exception {
assertQ("/schema/dynamicfields/*_i?indent=on&wt=xml&showDefaults=on",
"count(/response/lst[@name='dynamicField']) = 1",
"/response/lst[@name='dynamicField']/str[@name='name'] = '*_i'",
"/response/lst[@name='dynamicField']/str[@name='type'] = 'int'",
"/response/lst[@name='dynamicField']/bool[@name='indexed'] = 'true'",
"/response/lst[@name='dynamicField']/bool[@name='stored'] = 'true'",
"/response/lst[@name='dynamicField']/bool[@name='docValues'] = 'false'",
"/response/lst[@name='dynamicField']/bool[@name='termVectors'] = 'false'",
"/response/lst[@name='dynamicField']/bool[@name='termPositions'] = 'false'",
"/response/lst[@name='dynamicField']/bool[@name='termOffsets'] = 'false'",
"/response/lst[@name='dynamicField']/bool[@name='omitNorms'] = 'true'",
"/response/lst[@name='dynamicField']/bool[@name='omitTermFreqAndPositions'] = 'true'",
"/response/lst[@name='dynamicField']/bool[@name='omitPositions'] = 'false'",
"/response/lst[@name='dynamicField']/bool[@name='storeOffsetsWithPositions'] = 'false'",
"/response/lst[@name='dynamicField']/bool[@name='multiValued'] = 'false'",
"/response/lst[@name='dynamicField']/bool[@name='required'] = 'false'",
"/response/lst[@name='dynamicField']/bool[@name='tokenized'] = 'false'");
}
@Test
public void testGetNotFoundDynamicField() throws Exception {
assertQ("/schema/dynamicfields/*not_in_there?indent=on&wt=xml",
"count(/response/lst[@name='dynamicField']) = 0",
"/response/lst[@name='responseHeader']/int[@name='status'] = '404'",
"/response/lst[@name='error']/int[@name='code'] = '404'");
}
@Test
public void testJsonGetDynamicField() throws Exception {
assertJQ("/schema/dynamicfields/*_i?indent=on&showDefaults=on",
"/dynamicField/name=='*_i'",
"/dynamicField/type=='int'",
"/dynamicField/indexed==true",
"/dynamicField/stored==true",
"/dynamicField/docValues==false",
"/dynamicField/termVectors==false",
"/dynamicField/termPositions==false",
"/dynamicField/termOffsets==false",
"/dynamicField/omitNorms==true",
"/dynamicField/omitTermFreqAndPositions==true",
"/dynamicField/omitPositions==false",
"/dynamicField/storeOffsetsWithPositions==false",
"/dynamicField/multiValued==false",
"/dynamicField/required==false",
"/dynamicField/tokenized==false");
}
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -16,18 +16,18 @@ package org.apache.solr.rest;
* limitations under the License.
*/
import org.apache.solr.rest.SolrRestletTestBase;
import org.junit.Test;
import java.io.IOException;
public class TestFieldCollectionResource extends SchemaRestletTestBase {
public class TestFieldCollectionResource extends SolrRestletTestBase {
@Test
public void testGetAllFields() throws Exception {
assertQ("/schema/fields?indent=on&wt=xml",
"(/response/arr[@name='fields']/lst/str[@name='name'])[1] = 'HTMLstandardtok'",
"(/response/arr[@name='fields']/lst/str[@name='name'])[2] = 'HTMLwhitetok'",
"(/response/arr[@name='fields']/lst/str[@name='name'])[3] = '_version_'",
"count(//copySources/str) = count(//copyDests/str)");
"(/response/arr[@name='fields']/lst/str[@name='name'])[3] = '_version_'");
}
@Test

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -16,9 +16,10 @@ package org.apache.solr.rest;
* limitations under the License.
*/
import org.apache.solr.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestFieldResource extends SchemaRestletTestBase {
public class TestFieldResource extends SolrRestletTestBase {
@Test
public void testGetField() throws Exception {
assertQ("/schema/fields/test_postv?indent=on&wt=xml&showDefaults=true",

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -16,22 +16,23 @@ package org.apache.solr.rest;
* limitations under the License.
*/
import org.apache.solr.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestFieldTypeCollectionResource extends SchemaRestletTestBase {
public class TestFieldTypeCollectionResource extends SolrRestletTestBase {
@Test
public void testGetAllFieldTypes() throws Exception {
assertQ("/schema/fieldtypes?indent=on&wt=xml",
"(/response/arr[@name='fieldTypes']/lst/str[@name='name'])[1] = 'HTMLstandardtok'",
"(/response/arr[@name='fieldTypes']/lst/str[@name='name'])[2] = 'HTMLwhitetok'",
"(/response/arr[@name='fieldTypes']/lst/str[@name='name'])[3] = 'boolean'");
"(/response/arr[@name='fieldTypes']/lst/str[@name='name'])[1] = 'HTMLstandardtok'",
"(/response/arr[@name='fieldTypes']/lst/str[@name='name'])[2] = 'HTMLwhitetok'",
"(/response/arr[@name='fieldTypes']/lst/str[@name='name'])[3] = 'boolean'");
}
@Test
public void testJsonGetAllFieldTypes() throws Exception {
assertJQ("/schema/fieldtypes?indent=on",
"/fieldTypes/[0]/name=='HTMLstandardtok'",
"/fieldTypes/[1]/name=='HTMLwhitetok'",
"/fieldTypes/[2]/name=='boolean'");
"/fieldTypes/[0]/name=='HTMLstandardtok'",
"/fieldTypes/[1]/name=='HTMLwhitetok'",
"/fieldTypes/[2]/name=='boolean'");
}
}

View File

@ -1,4 +1,4 @@
package org.apache.solr.rest;
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
@ -16,9 +16,10 @@ package org.apache.solr.rest;
* limit ations under the License.
*/
import org.apache.solr.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestFieldTypeResource extends SchemaRestletTestBase {
public class TestFieldTypeResource extends SolrRestletTestBase {
@Test
public void testGetFieldType() throws Exception {
assertQ("/schema/fieldtypes/float?indent=on&wt=xml&showDefaults=true",

View File

@ -0,0 +1,29 @@
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.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestSchemaNameResource extends SolrRestletTestBase {
@Test
public void testGetSchemaName() throws Exception {
assertQ("/schema/name?indent=on&wt=xml",
"count(/response/str[@name='name']) = 1",
"/response/str[@name='name'][.='test-rest']");
}
}

View File

@ -0,0 +1,194 @@
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.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestSchemaResource extends SolrRestletTestBase {
@Test
public void testXMLResponse() throws Exception {
assertQ("/schema/?indent=on&wt=xml", // should work with or without trailing slash on '/schema/' path
"count(/response/lst[@name='schema']/str[@name='name']) = 1",
"/response/lst[@name='schema']/str[@name='name'][.='test-rest']",
"count(/response/lst[@name='schema']/float[@name='version']) = 1",
"/response/lst[@name='schema']/float[@name='version'][.='1.5']",
"count(/response/lst[@name='schema']/lst[@name='solrQueryParser']/str[@name='defaultOperator']) = 1",
"/response/lst[@name='schema']/lst[@name='solrQueryParser']/str[@name='defaultOperator'][.='OR']",
"count(/response/lst[@name='schema']/str[@name='uniqueKey']) = 1",
"/response/lst[@name='schema']/str[@name='uniqueKey'][.='id']",
"count(/response/lst[@name='schema']/str[@name='defaultSearchField']) = 1",
"/response/lst[@name='schema']/str[@name='defaultSearchField'][.='text']",
"(/response/lst[@name='schema']/arr[@name='fieldTypes']/lst/str[@name='name'])[1] = 'HTMLstandardtok'",
"(/response/lst[@name='schema']/arr[@name='fieldTypes']/lst/str[@name='name'])[2] = 'HTMLwhitetok'",
"(/response/lst[@name='schema']/arr[@name='fieldTypes']/lst/str[@name='name'])[3] = 'boolean'",
"(/response/lst[@name='schema']/arr[@name='fields']/lst/str[@name='name'])[1] = 'HTMLstandardtok'",
"(/response/lst[@name='schema']/arr[@name='fields']/lst/str[@name='name'])[2] = 'HTMLwhitetok'",
"(/response/lst[@name='schema']/arr[@name='fields']/lst/str[@name='name'])[3] = '_version_'",
"(/response/lst[@name='schema']/arr[@name='dynamicFields']/lst/str[@name='name'])[1] = '*_coordinate'",
"(/response/lst[@name='schema']/arr[@name='dynamicFields']/lst/str[@name='name'])[2] = 'ignored_*'",
"(/response/lst[@name='schema']/arr[@name='dynamicFields']/lst/str[@name='name'])[3] = '*_mfacet'",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='title']"
+" and str[@name='dest'][.='title_stemmed']"
+" and int[@name='maxChars'][.='200']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='title']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='*_i']"
+" and str[@name='dest'][.='title']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='*_i']"
+" and str[@name='dest'][.='*_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='*_i']"
+" and str[@name='dest'][.='*_dest_sub_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='*_i']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='*_src_sub_i']"
+" and str[@name='dest'][.='title']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='*_src_sub_i']"
+" and str[@name='dest'][.='*_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='*_src_sub_i']"
+" and str[@name='dest'][.='*_dest_sub_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='*_src_sub_i']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
+" and str[@name='dest'][.='title']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
+" and str[@name='dest'][.='*_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
+" and str[@name='dest'][.='*_dest_sub_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='src_sub_no_ast_i']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='title_*']"
+" and str[@name='dest'][.='text']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='title_*']"
+" and str[@name='dest'][.='*_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='title_*']"
+" and str[@name='dest'][.='*_dest_sub_s']]",
"/response/lst[@name='schema']/arr[@name='copyFields']/lst[ str[@name='source'][.='title_*']"
+" and str[@name='dest'][.='dest_sub_no_ast_s']]");
}
@Test
public void testJSONResponse() throws Exception {
assertJQ("/schema?wt=json", // Should work with or without a trailing slash
"/schema/name=='test-rest'",
"/schema/version==1.5",
"/schema/solrQueryParser/defaultOperator=='OR'",
"/schema/uniqueKey=='id'",
"/schema/defaultSearchField=='text'",
"/schema/fieldTypes/[0]/name=='HTMLstandardtok'",
"/schema/fieldTypes/[1]/name=='HTMLwhitetok'",
"/schema/fieldTypes/[2]/name=='boolean'",
"/schema/fields/[0]/name=='HTMLstandardtok'",
"/schema/fields/[1]/name=='HTMLwhitetok'",
"/schema/fields/[2]/name=='_version_'",
"/schema/dynamicFields/[0]/name=='*_coordinate'",
"/schema/dynamicFields/[1]/name=='ignored_*'",
"/schema/dynamicFields/[2]/name=='*_mfacet'",
"/schema/copyFields/[6]=={'source':'title','dest':'dest_sub_no_ast_s'}",
"/schema/copyFields/[7]=={'source':'*_i','dest':'title'}",
"/schema/copyFields/[8]=={'source':'*_i','dest':'*_s'}",
"/schema/copyFields/[9]=={'source':'*_i','dest':'*_dest_sub_s'}",
"/schema/copyFields/[10]=={'source':'*_i','dest':'dest_sub_no_ast_s'}",
"/schema/copyFields/[11]=={'source':'*_src_sub_i','dest':'title'}",
"/schema/copyFields/[12]=={'source':'*_src_sub_i','dest':'*_s'}",
"/schema/copyFields/[13]=={'source':'*_src_sub_i','dest':'*_dest_sub_s'}",
"/schema/copyFields/[14]=={'source':'*_src_sub_i','dest':'dest_sub_no_ast_s'}",
"/schema/copyFields/[15]=={'source':'src_sub_no_ast_i','dest':'title'}",
"/schema/copyFields/[16]=={'source':'src_sub_no_ast_i','dest':'*_s'}",
"/schema/copyFields/[17]=={'source':'src_sub_no_ast_i','dest':'*_dest_sub_s'}",
"/schema/copyFields/[18]=={'source':'src_sub_no_ast_i','dest':'dest_sub_no_ast_s'}");
}
@Test
public void testSchemaXmlResponse() {
assertQ("/schema?wt=schema.xml", // should work with or without trailing slash on '/schema/' path
"/schema/@name = 'test-rest'",
"/schema/@version = '1.5'",
"/schema/solrQueryParser/@defaultOperator = 'OR'",
"/schema/uniqueKey = 'id'",
"/schema/defaultSearchField = 'text'",
"(/schema/types/fieldType)[1]/@name = 'HTMLstandardtok'",
"(/schema/types/fieldType)[2]/@name = 'HTMLwhitetok'",
"(/schema/types/fieldType)[3]/@name = 'boolean'",
"(/schema/fields/field)[1]/@name = 'HTMLstandardtok'",
"(/schema/fields/field)[2]/@name = 'HTMLwhitetok'",
"(/schema/fields/field)[3]/@name = '_version_'",
"(/schema/fields/dynamicField)[1]/@name = '*_coordinate'",
"(/schema/fields/dynamicField)[2]/@name = 'ignored_*'",
"(/schema/fields/dynamicField)[3]/@name = '*_mfacet'",
"/schema/copyField[@source='title'][@dest='title_stemmed'][@maxChars='200']",
"/schema/copyField[@source='title'][@dest='dest_sub_no_ast_s']",
"/schema/copyField[@source='*_i'][@dest='title']",
"/schema/copyField[@source='*_i'][@dest='*_s']",
"/schema/copyField[@source='*_i'][@dest='*_dest_sub_s']",
"/schema/copyField[@source='*_i'][@dest='dest_sub_no_ast_s']",
"/schema/copyField[@source='*_src_sub_i'][@dest='title']",
"/schema/copyField[@source='*_src_sub_i'][@dest='*_s']",
"/schema/copyField[@source='*_src_sub_i'][@dest='*_dest_sub_s']",
"/schema/copyField[@source='*_src_sub_i'][@dest='dest_sub_no_ast_s']",
"/schema/copyField[@source='src_sub_no_ast_i'][@dest='title']",
"/schema/copyField[@source='src_sub_no_ast_i'][@dest='*_s']",
"/schema/copyField[@source='src_sub_no_ast_i'][@dest='*_dest_sub_s']",
"/schema/copyField[@source='src_sub_no_ast_i'][@dest='dest_sub_no_ast_s']",
"/schema/copyField[@source='title_*'][@dest='text']",
"/schema/copyField[@source='title_*'][@dest='*_s']",
"/schema/copyField[@source='title_*'][@dest='*_dest_sub_s']",
"/schema/copyField[@source='title_*'][@dest='dest_sub_no_ast_s']");
}
}

View File

@ -0,0 +1,30 @@
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.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestSchemaSimilarityResource extends SolrRestletTestBase {
@Test
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']");
}
}

View File

@ -0,0 +1,30 @@
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.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestSchemaVersionResource extends SolrRestletTestBase {
@Test
public void testGetSchemaVersion() throws Exception {
assertQ("/schema/version?indent=on&wt=xml",
"count(/response/float[@name='version']) = 1",
"/response/float[@name='version'][.='1.5']");
}
}

View File

@ -0,0 +1,30 @@
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.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestSolrQueryParserDefaultOperatorResource extends SolrRestletTestBase {
@Test
public void testGetDefaultOperator() throws Exception {
assertQ("/schema/solrqueryparser/defaultoperator?indent=on&wt=xml",
"count(/response/str[@name='defaultOperator']) = 1",
"/response/str[@name='defaultOperator'][.='OR']");
}
}

View File

@ -0,0 +1,31 @@
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.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestSolrQueryParserResource extends SolrRestletTestBase {
@Test
public void testGetSolrQueryParser() throws Exception {
assertQ("/schema/solrqueryparser?indent=on&wt=xml",
"count(/response/lst[@name='solrQueryParser']) = 1",
"count(/response/lst[@name='solrQueryParser']/str[@name='defaultOperator']) = 1",
"/response/lst[@name='solrQueryParser']/str[@name='defaultOperator'][.='OR']");
}
}

View File

@ -0,0 +1,31 @@
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.rest.SolrRestletTestBase;
import org.junit.Test;
public class TestUniqueKeyFieldResource extends SolrRestletTestBase {
@Test
public void testGetUniqueKey() throws Exception {
assertQ("/schema/uniquekey?indent=on&wt=xml",
"count(/response/str[@name='uniqueKey']) = 1",
"/response/str[@name='uniqueKey'][.='id']");
}
}

View File

@ -108,7 +108,9 @@ abstract public class RestTestBase extends SolrJettyTestBase {
query = request.substring(queryStartPos + 1);
path = request.substring(0, queryStartPos);
}
query = setParam(query, "wt", "xml");
if ( ! query.matches(".*wt=schema\\.xml.*")) { // don't overwrite wt=schema.xml
query = setParam(query, "wt", "xml");
}
request = path + '?' + setParam(query, "indent", "on");
String response = restTestHarness.query(request);

View File

@ -127,11 +127,11 @@
</servlet>
<servlet>
<servlet-name>SchemaRestApi</servlet-name>
<servlet-name>SolrRestApi</servlet-name>
<servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
<init-param>
<param-name>org.restlet.application</param-name>
<param-value>org.apache.solr.rest.SchemaRestApi</param-value>
<param-value>org.apache.solr.rest.SolrRestApi</param-value>
</init-param>
</servlet>
@ -164,7 +164,7 @@
</servlet-mapping>
<servlet-mapping>
<servlet-name>SchemaRestApi</servlet-name>
<servlet-name>SolrRestApi</servlet-name>
<url-pattern>/schema/*</url-pattern>
</servlet-mapping>