SOLR-4537: Clean up schema information REST API

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1454141 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Steven Rowe 2013-03-07 22:41:18 +00:00
parent 62dcc4274a
commit 14c9f28f57
7 changed files with 117 additions and 61 deletions

View File

@ -38,6 +38,35 @@ TBD...
Detailed Change List Detailed Change List
---------------------- ----------------------
================== 4.3.0 ==================
Versions of Major Components
---------------------
Apache Tika 1.3
Carrot2 3.6.2
Velocity 1.7 and Velocity Tools 2.0
Apache UIMA 2.3.1
Apache ZooKeeper 3.4.5
Upgrading from Solr 4.2.0
----------------------
(No upgrade instructions yet)
Detailed Change List
----------------------
New Features
----------------------
Bug Fixes
----------------------
Other Changes
----------------------
* SOLR-4537: Clean up schema information REST API. (Steve Rowe)
================== 4.2.0 ================== ================== 4.2.0 ==================
Versions of Major Components Versions of Major Components

View File

@ -18,14 +18,10 @@ package org.apache.solr.rest;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.schema.CopyField;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField; import org.apache.solr.schema.SchemaField;
import org.restlet.resource.ResourceException; import org.restlet.resource.ResourceException;
import java.util.ArrayList; import java.util.LinkedHashSet;
import java.util.LinkedHashMap;
import java.util.List;
/** /**
@ -38,10 +34,10 @@ abstract class BaseFieldResource extends BaseSchemaResource {
private static final String SHOW_DEFAULTS = "showDefaults"; private static final String SHOW_DEFAULTS = "showDefaults";
private LinkedHashMap<String,SimpleOrderedMap<Object>> requestedFields; private LinkedHashSet<String> requestedFields;
private boolean showDefaults; private boolean showDefaults;
protected LinkedHashMap<String,SimpleOrderedMap<Object>> getRequestedFields() { protected LinkedHashSet<String> getRequestedFields() {
return requestedFields; return requestedFields;
} }
@ -70,10 +66,10 @@ abstract class BaseFieldResource extends BaseSchemaResource {
if (null != flParam) { if (null != flParam) {
String[] fields = flParam.trim().split("[,\\s]+"); String[] fields = flParam.trim().split("[,\\s]+");
if (fields.length > 0) { if (fields.length > 0) {
requestedFields = new LinkedHashMap<String,SimpleOrderedMap<Object>>(); requestedFields = new LinkedHashSet<String>();
for (String field : fields) { for (String field : fields) {
if ( ! field.isEmpty()) { if ( ! field.trim().isEmpty()) {
requestedFields.put(field, null); requestedFields.add(field.trim());
} }
} }
} }
@ -93,9 +89,9 @@ abstract class BaseFieldResource extends BaseSchemaResource {
SimpleOrderedMap<Object> properties = field.getNamedPropertyValues(showDefaults); SimpleOrderedMap<Object> properties = field.getNamedPropertyValues(showDefaults);
if ( ! getSchema().getFields().containsKey(field.getName())) { if ( ! getSchema().getFields().containsKey(field.getName())) {
String dynamicBase = getSchema().getDynamicPattern(field.getName()); String dynamicBase = getSchema().getDynamicPattern(field.getName());
// Add dynamicBase property if it's different from the field name.
if ( ! field.getName().equals(dynamicBase)) { if ( ! field.getName().equals(dynamicBase)) {
// Don't add dynamicBase property if it's identical to the field name. properties.add(DYNAMIC_BASE, dynamicBase);
properties.add(DYNAMIC_BASE, getSchema().getDynamicPattern(field.getName()));
} }
} }
if (field == getSchema().getUniqueKeyField()) { if (field == getSchema().getUniqueKeyField()) {

View File

@ -21,6 +21,7 @@ import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.schema.FieldType; import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField; import org.apache.solr.schema.SchemaField;
import org.restlet.representation.Representation; import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException; import org.restlet.resource.ResourceException;
@ -28,6 +29,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -55,32 +57,29 @@ public class DynamicFieldCollectionResource extends BaseFieldResource implements
public Representation get() { public Representation get() {
try { try {
SchemaField[] dynamicFields = getSchema().getDynamicFieldPrototypes(); List<SimpleOrderedMap<Object>> props = new ArrayList<SimpleOrderedMap<Object>>();
List<SimpleOrderedMap<Object>> props = new ArrayList<SimpleOrderedMap<Object>>(dynamicFields.length); if (null == getRequestedFields()) {
if (null != getRequestedFields()) { for (IndexSchema.DynamicField dynamicField : getSchema().getDynamicFields()) {
if ( ! dynamicField.getRegex().startsWith(INTERNAL_POLY_FIELD_PREFIX)) { // omit internal polyfields
props.add(getFieldProperties(dynamicField.getPrototype()));
}
}
} else {
if (0 == getRequestedFields().size()) { if (0 == getRequestedFields().size()) {
String message = "Empty " + CommonParams.FL + " parameter value"; String message = "Empty " + CommonParams.FL + " parameter value";
throw new SolrException(ErrorCode.BAD_REQUEST, message); throw new SolrException(ErrorCode.BAD_REQUEST, message);
} }
for (SchemaField prototype : dynamicFields) { Map<String,SchemaField> dynamicFieldsByName = new HashMap<String,SchemaField>();
if (getRequestedFields().containsKey(prototype.getName())) { for (IndexSchema.DynamicField dynamicField : getSchema().getDynamicFields()) {
getRequestedFields().put(prototype.getName(), getFieldProperties(prototype)); dynamicFieldsByName.put(dynamicField.getRegex(), dynamicField.getPrototype());
}
} }
// Use the same order as the fl parameter // Use the same order as the fl parameter
for (Map.Entry<String,SimpleOrderedMap<Object>> requestedField : getRequestedFields().entrySet()) { for (String dynamicFieldName : getRequestedFields()) {
SimpleOrderedMap<Object> fieldProperties = requestedField.getValue(); final SchemaField dynamicSchemaField = dynamicFieldsByName.get(dynamicFieldName);
// Should there be some form of error condition if (null == dynamicSchemaField) {
// if one or more of the requested fields were not found? log.info("Requested dynamic field '" + dynamicFieldName + "' not found.");
if (null != fieldProperties) { } else {
props.add(fieldProperties); props.add(getFieldProperties(dynamicSchemaField));
}
}
} else {
for (SchemaField prototype : dynamicFields) {
// omit internal polyfields
if ( ! prototype.getName().startsWith(INTERNAL_POLY_FIELD_PREFIX)) {
props.add(getFieldProperties(prototype));
} }
} }
} }

View File

@ -21,29 +21,37 @@ import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.schema.SchemaField;
import org.restlet.representation.Representation; import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException; import org.restlet.resource.ResourceException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.SortedSet;
import java.util.TreeSet;
/** /**
* This class responds to requests at /solr/(corename)/schema/fields * This class responds to requests at /solr/(corename)/schema/fields
* <p/> * <p/>
* One query parameters are supported: * Two query parameters are supported:
* <ul> * <ul>
* <li> * <li>
* "fl": a comma- and/or space-separated list of fields to send properties * "fl": a comma- and/or space-separated list of fields to send properties
* for in the response, rather than the default: all of them. * for in the response, rather than the default: all of them.
* </li> * </li>
* <li>
* "includeDynamic": if the "fl" parameter is specified, matching dynamic
* fields are included in the response and identified with the "dynamicBase"
* property. If the "fl" parameter is not specified, the "includeDynamic"
* query parameter is ignored.
* </li>
* </ul> * </ul>
*/ */
public class FieldCollectionResource extends BaseFieldResource implements GETable { public class FieldCollectionResource extends BaseFieldResource implements GETable {
private static final Logger log = LoggerFactory.getLogger(FieldCollectionResource.class); private static final Logger log = LoggerFactory.getLogger(FieldCollectionResource.class);
private boolean includeDynamic;
public FieldCollectionResource() { public FieldCollectionResource() {
super(); super();
@ -52,40 +60,39 @@ public class FieldCollectionResource extends BaseFieldResource implements GETabl
@Override @Override
public void doInit() throws ResourceException { public void doInit() throws ResourceException {
super.doInit(); super.doInit();
includeDynamic = getSolrRequest().getParams().getBool(INCLUDE_DYNAMIC_PARAM, false);
} }
@Override @Override
public Representation get() { public Representation get() {
try { try {
// Get all explicitly defined fields from the schema final List<SimpleOrderedMap<Object>> props = new ArrayList<SimpleOrderedMap<Object>>();
Set<String> fieldNames = new HashSet<String>(getSchema().getFields().keySet());
final List<SimpleOrderedMap<Object>> fieldCollectionProperties = new ArrayList<SimpleOrderedMap<Object>>(fieldNames.size());
if (null == getRequestedFields()) { if (null == getRequestedFields()) {
SortedSet<String> fieldNames = new TreeSet<String>(getSchema().getFields().keySet());
for (String fieldName : fieldNames) { for (String fieldName : fieldNames) {
fieldCollectionProperties.add(getFieldProperties(getSchema().getFieldOrNull(fieldName))); props.add(getFieldProperties(getSchema().getFields().get(fieldName)));
} }
} else { } else {
if (0 == getRequestedFields().size()) { if (0 == getRequestedFields().size()) {
String message = "Empty " + CommonParams.FL + " parameter value"; String message = "Empty " + CommonParams.FL + " parameter value";
throw new SolrException(ErrorCode.BAD_REQUEST, message); throw new SolrException(ErrorCode.BAD_REQUEST, message);
} }
for (String field : fieldNames) {
if (getRequestedFields().containsKey(field)) {
getRequestedFields().put(field, getFieldProperties(getSchema().getFieldOrNull(field)));
}
}
// Use the same order as the fl parameter // Use the same order as the fl parameter
for (SimpleOrderedMap<Object> fieldProperties : getRequestedFields().values()) { for (String fieldName : getRequestedFields()) {
// Should there be some form of error condition final SchemaField field;
// if one or more of the requested fields were not found? if (includeDynamic) {
if (null != fieldProperties) { field = getSchema().getFieldOrNull(fieldName);
fieldCollectionProperties.add(fieldProperties); } else {
field = getSchema().getFields().get(fieldName);
}
if (null == field) {
log.info("Requested field '" + fieldName + "' not found.");
} else {
props.add(getFieldProperties(field));
} }
} }
} }
getSolrResponse().add(SchemaRestApi.FIELDS, fieldCollectionProperties); getSolrResponse().add(SchemaRestApi.FIELDS, props);
} catch (Exception e) { } catch (Exception e) {
getSolrResponse().setException(e); getSolrResponse().setException(e);
} }

View File

@ -68,11 +68,10 @@ public class FieldResource extends BaseFieldResource implements GETable {
final String message = "Field name is missing"; final String message = "Field name is missing";
throw new SolrException(ErrorCode.BAD_REQUEST, message); throw new SolrException(ErrorCode.BAD_REQUEST, message);
} else { } else {
SchemaField field; final SchemaField field;
if (includeDynamic) { if (includeDynamic) {
field = getSchema().getFieldOrNull(fieldName); field = getSchema().getFieldOrNull(fieldName);
} else { } else {
// Don't look for matches among dynamic fields
field = getSchema().getFields().get(fieldName); field = getSchema().getFields().get(fieldName);
} }
if (null == field) { if (null == field) {

View File

@ -841,7 +841,8 @@ public final class IndexSchema {
public final static class DynamicField extends DynamicReplacement { public final static class DynamicField extends DynamicReplacement {
final SchemaField prototype; private final SchemaField prototype;
public SchemaField getPrototype() { return prototype; }
DynamicField(SchemaField prototype) { DynamicField(SchemaField prototype) {
super(prototype.name); super(prototype.name);

View File

@ -24,9 +24,9 @@ public class TestFieldCollectionResource extends SchemaRestletTestBase {
@Test @Test
public void testGetAllFields() throws Exception { public void testGetAllFields() throws Exception {
assertQ("/schema/fields?indent=on&wt=xml", assertQ("/schema/fields?indent=on&wt=xml",
"(/response/arr[@name='fields']/lst/str[@name='name'])[1] = 'custstopfilt'", "(/response/arr[@name='fields']/lst/str[@name='name'])[1] = 'HTMLstandardtok'",
"(/response/arr[@name='fields']/lst/str[@name='name'])[2] = 'lowerfilt'", "(/response/arr[@name='fields']/lst/str[@name='name'])[2] = 'HTMLwhitetok'",
"(/response/arr[@name='fields']/lst/str[@name='name'])[3] = 'test_basictv'", "(/response/arr[@name='fields']/lst/str[@name='name'])[3] = '_version_'",
"count(//copySources/str) = count(//copyDests/str)"); "count(//copySources/str) = count(//copyDests/str)");
} }
@ -37,6 +37,31 @@ public class TestFieldCollectionResource extends SchemaRestletTestBase {
"(/response/arr[@name='fields']/lst/str[@name='name'])[1] = 'id'", "(/response/arr[@name='fields']/lst/str[@name='name'])[1] = 'id'",
"(/response/arr[@name='fields']/lst/str[@name='name'])[2] = '_version_'"); "(/response/arr[@name='fields']/lst/str[@name='name'])[2] = '_version_'");
} }
@Test
public void testGetThreeFieldsDontIncludeDynamic() throws IOException {
//
assertQ("/schema/fields?indent=on&wt=xml&fl=id,_version_,price_i",
"count(/response/arr[@name='fields']/lst/str[@name='name']) = 2",
"(/response/arr[@name='fields']/lst/str[@name='name'])[1] = 'id'",
"(/response/arr[@name='fields']/lst/str[@name='name'])[2] = '_version_'");
}
@Test
public void testGetThreeFieldsIncludeDynamic() throws IOException {
assertQ("/schema/fields?indent=on&wt=xml&fl=id,_version_,price_i&includeDynamic=on",
"count(/response/arr[@name='fields']/lst/str[@name='name']) = 3",
"(/response/arr[@name='fields']/lst/str[@name='name'])[1] = 'id'",
"(/response/arr[@name='fields']/lst/str[@name='name'])[2] = '_version_'",
"(/response/arr[@name='fields']/lst/str[@name='name'])[3] = 'price_i'",
"/response/arr[@name='fields']/lst[ str[@name='name']='price_i' "
+" and str[@name='dynamicBase']='*_i']");
}
@Test @Test
public void testNotFoundFields() throws IOException { public void testNotFoundFields() throws IOException {
@ -48,9 +73,9 @@ public class TestFieldCollectionResource extends SchemaRestletTestBase {
@Test @Test
public void testJsonGetAllFields() throws Exception { public void testJsonGetAllFields() throws Exception {
assertJQ("/schema/fields?indent=on", assertJQ("/schema/fields?indent=on",
"/fields/[0]/name=='custstopfilt'", "/fields/[0]/name=='HTMLstandardtok'",
"/fields/[1]/name=='lowerfilt'", "/fields/[1]/name=='HTMLwhitetok'",
"/fields/[2]/name=='test_basictv'"); "/fields/[2]/name=='_version_'");
} }
@Test @Test