You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by gs...@apache.org on 2013/07/08 16:05:34 UTC
svn commit: r1500744 - in /lucene/dev/branches/branch_4x: ./ solr/
solr/core/ solr/core/src/java/org/apache/solr/rest/schema/
solr/core/src/java/org/apache/solr/schema/
solr/core/src/test/org/apache/solr/rest/schema/
Author: gsingers
Date: Mon Jul 8 14:05:33 2013
New Revision: 1500744
URL: http://svn.apache.org/r1500744
Log:
SOLR-5010: merge from trunk
Modified:
lucene/dev/branches/branch_4x/ (props changed)
lucene/dev/branches/branch_4x/solr/ (props changed)
lucene/dev/branches/branch_4x/solr/CHANGES.txt (contents, props changed)
lucene/dev/branches/branch_4x/solr/core/ (props changed)
lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/rest/schema/FieldCollectionResource.java
lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/rest/schema/FieldResource.java
lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/rest/schema/TestManagedSchemaFieldResource.java
Modified: lucene/dev/branches/branch_4x/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/CHANGES.txt?rev=1500744&r1=1500743&r2=1500744&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/CHANGES.txt (original)
+++ lucene/dev/branches/branch_4x/solr/CHANGES.txt Mon Jul 8 14:05:33 2013
@@ -130,6 +130,8 @@ New Features
* SOLR-5003: CSV Update Handler supports optionally adding the line number/row id to
a document (gsingers)
+* SOLR-5010: Add support for creating copy fields to the Fields REST API (gsingers)
+
Bug Fixes
----------------------
Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/rest/schema/FieldCollectionResource.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/rest/schema/FieldCollectionResource.java?rev=1500744&r1=1500743&r2=1500744&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/rest/schema/FieldCollectionResource.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/rest/schema/FieldCollectionResource.java Mon Jul 8 14:05:33 2013
@@ -33,6 +33,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
@@ -126,6 +127,7 @@ public class FieldCollectionResource ext
throw new SolrException(ErrorCode.BAD_REQUEST, message);
} else {
Object object = ObjectBuilder.fromJSON(entity.getText());
+ Map<String, String> copyFields = new HashMap<String, String>();
if ( ! (object instanceof List)) {
String message = "Invalid JSON type " + object.getClass().getName() + ", expected List of the form"
+ " (ignore the backslashes): [{\"name\":\"foo\",\"type\":\"text_general\", ...}, {...}, ...]";
@@ -148,9 +150,24 @@ public class FieldCollectionResource ext
log.error(message);
throw new SolrException(ErrorCode.BAD_REQUEST, message);
}
+ // copyFields:"comma separated list of destination fields"
+ String copyTo = (String)map.get(IndexSchema.COPY_FIELDS);
+ if (copyTo != null){
+ map.remove(IndexSchema.COPY_FIELDS);
+ copyFields.put(fieldName, copyTo);
+ }
newFields.add(oldSchema.newField(fieldName, fieldType, map));
}
IndexSchema newSchema = oldSchema.addFields(newFields);
+ for (Map.Entry<String, String> entry : copyFields.entrySet()) {
+ //key is the source, value is a comma separated list of targets
+ String [] splits = entry.getValue().split(",");
+ if (splits != null && splits.length > 0){
+ for (int i = 0; i < splits.length; i++) {
+ newSchema.registerCopyField(entry.getKey(), splits[i].trim());
+ }
+ }
+ }
getSolrCore().setLatestSchema(newSchema);
}
}
Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/rest/schema/FieldResource.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/rest/schema/FieldResource.java?rev=1500744&r1=1500743&r2=1500744&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/rest/schema/FieldResource.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/rest/schema/FieldResource.java Mon Jul 8 14:05:33 2013
@@ -31,6 +31,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.Map;
/**
@@ -44,9 +47,9 @@ import java.util.Map;
* <p/>
* The PUT method accepts field addition requests in JSON format.
*/
-public class FieldResource extends BaseFieldResource implements GETable,PUTable {
+public class FieldResource extends BaseFieldResource implements GETable, PUTable {
private static final Logger log = LoggerFactory.getLogger(FieldResource.class);
-
+
private boolean includeDynamic;
private String fieldName;
@@ -59,7 +62,7 @@ public class FieldResource extends BaseF
super.doInit();
if (isExisting()) {
includeDynamic = getSolrRequest().getParams().getBool(INCLUDE_DYNAMIC_PARAM, false);
- fieldName = (String)getRequestAttributes().get(IndexSchema.NAME);
+ fieldName = (String) getRequestAttributes().get(IndexSchema.NAME);
try {
fieldName = null == fieldName ? "" : urlDecode(fieldName.trim()).trim();
} catch (UnsupportedEncodingException e) {
@@ -97,53 +100,61 @@ public class FieldResource extends BaseF
}
/**
- * Accepts JSON add field request, to URL
+ * Accepts JSON add field request, to URL
*/
@Override
public Representation put(Representation entity) {
try {
- if ( ! getSchema().isMutable()) {
+ if (!getSchema().isMutable()) {
final String message = "This IndexSchema is not mutable.";
throw new SolrException(ErrorCode.BAD_REQUEST, message);
} else {
if (null == entity.getMediaType()) {
entity.setMediaType(MediaType.APPLICATION_JSON);
}
- if ( ! entity.getMediaType().equals(MediaType.APPLICATION_JSON, true)) {
+ if (!entity.getMediaType().equals(MediaType.APPLICATION_JSON, true)) {
String message = "Only media type " + MediaType.APPLICATION_JSON.toString() + " is accepted."
- + " Request has media type " + entity.getMediaType().toString() + ".";
+ + " Request has media type " + entity.getMediaType().toString() + ".";
log.error(message);
throw new SolrException(ErrorCode.BAD_REQUEST, message);
} else {
Object object = ObjectBuilder.fromJSON(entity.getText());
- if ( ! (object instanceof Map)) {
+ if (!(object instanceof Map)) {
String message = "Invalid JSON type " + object.getClass().getName() + ", expected Map of the form"
- + " (ignore the backslashes): {\"type\":\"text_general\", ...}, either with or"
- + " without a \"name\" mapping. If the \"name\" is specified, it must match the"
- + " name given in the request URL: /schema/fields/(name)";
+ + " (ignore the backslashes): {\"type\":\"text_general\", ...}, either with or"
+ + " without a \"name\" mapping. If the \"name\" is specified, it must match the"
+ + " name given in the request URL: /schema/fields/(name)";
log.error(message);
throw new SolrException(ErrorCode.BAD_REQUEST, message);
} else {
- Map<String,Object> map = (Map<String,Object>)object;
+ Map<String, Object> map = (Map<String, Object>) object;
if (1 == map.size() && map.containsKey(IndexSchema.FIELD)) {
- map = (Map<String,Object>)map.get(IndexSchema.FIELD);
+ map = (Map<String, Object>) map.get(IndexSchema.FIELD);
}
String bodyFieldName;
- if (null != (bodyFieldName = (String)map.remove(IndexSchema.NAME)) && ! fieldName.equals(bodyFieldName)) {
- String message = "Field name in the request body '" + bodyFieldName
- + "' doesn't match field name in the request URL '" + fieldName + "'";
+ if (null != (bodyFieldName = (String) map.remove(IndexSchema.NAME)) && !fieldName.equals(bodyFieldName)) {
+ String message = "Field name in the request body '" + bodyFieldName
+ + "' doesn't match field name in the request URL '" + fieldName + "'";
log.error(message);
throw new SolrException(ErrorCode.BAD_REQUEST, message);
} else {
String fieldType;
- if (null == (fieldType = (String)map.remove(IndexSchema.TYPE))) {
+ if (null == (fieldType = (String) map.remove(IndexSchema.TYPE))) {
String message = "Missing '" + IndexSchema.TYPE + "' mapping.";
log.error(message);
throw new SolrException(ErrorCode.BAD_REQUEST, message);
} else {
- ManagedIndexSchema oldSchema = (ManagedIndexSchema)getSchema();
+ ManagedIndexSchema oldSchema = (ManagedIndexSchema) getSchema();
+ String copyTo = (String) map.get(IndexSchema.COPY_FIELDS);
+ Collection<String> copyFieldNames = Collections.emptySet();
+ if (copyTo != null) {
+ map.remove(IndexSchema.COPY_FIELDS);
+ String [] tmp = copyTo.split(",");
+ copyFieldNames = new HashSet<String>(tmp.length);
+ Collections.addAll(copyFieldNames, tmp);
+ }
SchemaField newField = oldSchema.newField(fieldName, fieldType, map);
- ManagedIndexSchema newSchema = oldSchema.addField(newField);
+ IndexSchema newSchema = oldSchema.addField(newField, copyFieldNames);
getSolrCore().setLatestSchema(newSchema);
}
}
Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/IndexSchema.java?rev=1500744&r1=1500743&r2=1500744&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/IndexSchema.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/IndexSchema.java Mon Jul 8 14:05:33 2013
@@ -1435,9 +1435,23 @@ public class IndexSchema {
}
/**
+ * Copies this schema, adds the given field to the copy, then persists the new schema.
+ *
+ * @param newField the SchemaField to add
+ * @param copyFieldNames 0 or more names of targets to copy this field to
+ * @return a new IndexSchema based on this schema with newField added
+ * @see #newField(String, String, Map)
+ */
+ public IndexSchema addField(SchemaField newField, Collection<String> copyFieldNames) {
+ String msg = "This IndexSchema is not mutable.";
+ log.error(msg);
+ throw new SolrException(ErrorCode.SERVER_ERROR, msg);
+ }
+
+ /**
* Copies this schema, adds the given fields to the copy, then persists the new schema.
*
- * @param newFields the SchemaFields to add
+ * @param newFields the SchemaFields to add
* @return a new IndexSchema based on this schema with newFields added
* @see #newField(String, String, Map)
*/
@@ -1448,6 +1462,20 @@ public class IndexSchema {
}
/**
+ * Copies this schema, adds the given fields to the copy, then persists the new schema.
+ *
+ * @param newFields the SchemaFields to add
+ * @param copyFieldNames 0 or more names of targets to copy this field to
+ * @return a new IndexSchema based on this schema with newFields added
+ * @see #newField(String, String, Map)
+ */
+ public IndexSchema addFields(Collection<SchemaField> newFields, Map<String, Collection<String>> copyFieldNames) {
+ String msg = "This IndexSchema is not mutable.";
+ log.error(msg);
+ throw new SolrException(ErrorCode.SERVER_ERROR, msg);
+ }
+
+ /**
* Returns a SchemaField if the given fieldName does not already
* exist in this schema, and does not match any dynamic fields
* in this schema. The resulting SchemaField can be used in a call
Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java?rev=1500744&r1=1500743&r2=1500744&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java Mon Jul 8 14:05:33 2013
@@ -40,6 +40,7 @@ import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Map;
/** Solr-managed schema - non-user-editable, but can be mutable via internal and external REST API requests. */
@@ -165,27 +166,40 @@ public final class ManagedIndexSchema ex
}
@Override
- public ManagedIndexSchema addField(SchemaField newField) {
+ public IndexSchema addField(SchemaField newField) {
return addFields(Arrays.asList(newField));
}
+ @Override
+ public IndexSchema addField(SchemaField newField, Collection<String> copyFieldNames) {
+ return addFields(Arrays.asList(newField), Collections.singletonMap(newField.getName(), copyFieldNames));
+ }
+
public class FieldExistsException extends SolrException {
public FieldExistsException(ErrorCode code, String msg) {
super(code, msg);
}
}
-
+
@Override
- public ManagedIndexSchema addFields(Collection<SchemaField> newFields) {
+ public IndexSchema addFields(Collection<SchemaField> newFields) {
+ return addFields(newFields, Collections.<String, Collection<String>>emptyMap());
+ }
+
+ @Override
+ public IndexSchema addFields(Collection<SchemaField> newFields, Map<String, Collection<String>> copyFieldNames) {
ManagedIndexSchema newSchema = null;
if (isMutable) {
boolean success = false;
+ if (copyFieldNames == null){
+ copyFieldNames = Collections.emptyMap();
+ }
while ( ! success) { // optimistic concurrency
// even though fields is volatile, we need to synchronize to avoid two addFields
// happening concurrently (and ending up missing one of them)
synchronized (getSchemaUpdateLock()) {
newSchema = shallowCopy(true);
-
+
for (SchemaField newField : newFields) {
if (null != newSchema.getFieldOrNull(newField.getName())) {
String msg = "Field '" + newField.getName() + "' already exists.";
@@ -201,6 +215,12 @@ public final class ManagedIndexSchema ex
log.debug("{} is required in this schema", newField.getName());
newSchema.requiredFields.add(newField);
}
+ Collection<String> copyFields = copyFieldNames.get(newField.getName());
+ if (copyFields != null) {
+ for (String copyField : copyFields) {
+ newSchema.registerCopyField(newField.getName(), copyField);
+ }
+ }
}
// Run the callbacks on SchemaAware now that everything else is done
for (SchemaAware aware : newSchema.schemaAware) {
Modified: lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/rest/schema/TestManagedSchemaFieldResource.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/rest/schema/TestManagedSchemaFieldResource.java?rev=1500744&r1=1500743&r2=1500744&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/rest/schema/TestManagedSchemaFieldResource.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/rest/schema/TestManagedSchemaFieldResource.java Mon Jul 8 14:05:33 2013
@@ -103,6 +103,29 @@ public class TestManagedSchemaFieldResou
}
@Test
+ public void testAddCopyField() throws Exception {
+ assertQ("/schema/fields/newfield2?indent=on&wt=xml",
+ "count(/response/lst[@name='field']) = 0",
+ "/response/lst[@name='responseHeader']/int[@name='status'] = '404'",
+ "/response/lst[@name='error']/int[@name='code'] = '404'");
+
+ assertJPut("/schema/fields/fieldA",
+ "{\"type\":\"text\",\"stored\":\"false\"}",
+ "/responseHeader/status==0");
+ assertJPut("/schema/fields/fieldB",
+ "{\"type\":\"text\",\"stored\":\"false\", \"copyFields\":\"fieldA\"}",
+ "/responseHeader/status==0");
+
+ assertQ("/schema/fields/fieldB?indent=on&wt=xml",
+ "count(/response/lst[@name='field']) = 1",
+ "/response/lst[@name='responseHeader']/int[@name='status'] = '0'");
+ assertQ("/schema/copyfields/?indent=on&wt=xml&source.fl=fieldB",
+ "count(/response/arr[@name='copyFields']/lst) = 1"
+ );
+
+ }
+
+ @Test
public void testPostMultipleFields() throws Exception {
assertQ("/schema/fields/newfield1?indent=on&wt=xml",
"count(/response/lst[@name='field']) = 0",
@@ -142,5 +165,35 @@ public class TestManagedSchemaFieldResou
"count(/response/result[@name='response']/doc/*) = 1",
"/response/result[@name='response']/doc/str[@name='id'][.='456']");
}
+
+ @Test
+ public void testPostCopy() throws Exception {
+ assertJPost("/schema/fields",
+ "[{\"name\":\"fieldA\",\"type\":\"text\",\"stored\":\"false\"},"
+ + "{\"name\":\"fieldB\",\"type\":\"text\",\"stored\":\"false\"},"
+ + " {\"name\":\"fieldC\",\"type\":\"text\",\"stored\":\"false\", \"copyFields\":\"fieldB\"}]",
+ "/responseHeader/status==0");
+ assertQ("/schema/copyfields/?indent=on&wt=xml&source.fl=fieldC",
+ "count(/response/arr[@name='copyFields']/lst) = 1"
+ );
+ assertJPost("/schema/fields",
+ "[{\"name\":\"fieldD\",\"type\":\"text\",\"stored\":\"false\"},"
+ + "{\"name\":\"fieldE\",\"type\":\"text\",\"stored\":\"false\"},"
+ + " {\"name\":\"fieldF\",\"type\":\"text\",\"stored\":\"false\", \"copyFields\":\"fieldD,fieldE\"}]",
+ "/responseHeader/status==0");
+ assertQ("/schema/copyfields/?indent=on&wt=xml&source.fl=fieldF",
+ "count(/response/arr[@name='copyFields']/lst) = 2"
+ );
+ assertJPost("/schema/fields",
+ "[{\"name\":\"fieldG\",\"type\":\"text\",\"stored\":\"false\"},"
+ + "{\"name\":\"fieldH\",\"type\":\"text\",\"stored\":\"false\"},"
+ + " {\"name\":\"fieldI\",\"type\":\"text\",\"stored\":\"false\", \"copyFields\":\"fieldG, fieldH \"}]",
+ "/responseHeader/status==0");
+ assertQ("/schema/copyfields/?indent=on&wt=xml&source.fl=fieldF",
+ "count(/response/arr[@name='copyFields']/lst) = 2"
+ );
+
+ }
+
}