diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 76ae64e7fad..3c4d4d256c1 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -161,6 +161,11 @@ New Features * SOLR-6267: Let user override Interval Faceting key with LocalParams (Tomas Fernandez_Lobbe via Erick Erickson) +* SOLR-6020: Auto-generate a unique key in schema-less example if data does not have an id field. + The UUIDUpdateProcessor was improved to not require a field name in configuration and generate + a UUID into the unique Key field. + (Vitaliy Zhovtyuk, hossman, Steve Rowe, Erik Hatcher, shalin) + Bug Fixes ---------------------- diff --git a/solr/core/src/java/org/apache/solr/update/processor/AbstractDefaultValueUpdateProcessorFactory.java b/solr/core/src/java/org/apache/solr/update/processor/AbstractDefaultValueUpdateProcessorFactory.java index 9c87ec978dc..de8491102aa 100644 --- a/solr/core/src/java/org/apache/solr/update/processor/AbstractDefaultValueUpdateProcessorFactory.java +++ b/solr/core/src/java/org/apache/solr/update/processor/AbstractDefaultValueUpdateProcessorFactory.java @@ -72,7 +72,7 @@ public abstract class AbstractDefaultValueUpdateProcessorFactory * to any document which does not already have a value in * fieldName */ - protected static abstract class DefaultValueUpdateProcessor + static abstract class DefaultValueUpdateProcessor extends UpdateRequestProcessor { final String fieldName; diff --git a/solr/core/src/java/org/apache/solr/update/processor/UUIDUpdateProcessorFactory.java b/solr/core/src/java/org/apache/solr/update/processor/UUIDUpdateProcessorFactory.java index 30f84b412d0..3f9ef5aee7d 100644 --- a/solr/core/src/java/org/apache/solr/update/processor/UUIDUpdateProcessorFactory.java +++ b/solr/core/src/java/org/apache/solr/update/processor/UUIDUpdateProcessorFactory.java @@ -17,29 +17,28 @@ package org.apache.solr.update.processor; -import java.io.IOException; import java.util.UUID; import java.util.Locale; +import org.apache.commons.lang.StringUtils; import org.apache.solr.common.SolrException; import static org.apache.solr.common.SolrException.ErrorCode.*; -import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.util.NamedList; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; -import org.apache.solr.update.AddUpdateCommand; +import org.apache.solr.schema.SchemaField; /** *

- * An update processor that adds a newly generated UUID value - * to any document being added that does not already have a value in the + * An update processor that adds a newly generated UUID value + * to any document being added that does not already have a value in the * specified field. *

* *

- * In the example configuration below, if a document does not contain a value - * in the id field, a new UUID will be generated + * In the example configuration below, if a document does not contain a value + * in the id field, a new UUID will be generated * and added as the value of that field. *

* @@ -48,19 +47,46 @@ import org.apache.solr.update.AddUpdateCommand; * <str name="fieldName">id</str> * </processor> * - * + * + *

+ * If field name is omitted in processor configuration, + * then @{link org.apache.solr.schema.IndexSchema#getUniqueKeyField()} + * is used as field and a new UUID will be generated + * and added as the value of that field. The field type of the uniqueKeyField + * must be anything which accepts a string or UUID value. + *

* @see UUID */ -public class UUIDUpdateProcessorFactory - extends AbstractDefaultValueUpdateProcessorFactory { +public class UUIDUpdateProcessorFactory extends UpdateRequestProcessorFactory { - @Override - public UpdateRequestProcessor getInstance(SolrQueryRequest req, - SolrQueryResponse rsp, + protected String fieldName = null; + + @SuppressWarnings("unchecked") + public void init(NamedList args) { + + Object obj = args.remove("fieldName"); + if (null != obj) { + fieldName = obj.toString(); + } + + if (0 < args.size()) { + throw new SolrException(SERVER_ERROR, + "Unexpected init param(s): '" + + args.getName(0) + "'"); + } + } + + public UpdateRequestProcessor getInstance(SolrQueryRequest req, + SolrQueryResponse rsp, UpdateRequestProcessor next ) { - return new DefaultValueUpdateProcessor(fieldName, next) { + if (StringUtils.isEmpty(fieldName)) { + SchemaField schemaField = req.getSchema().getUniqueKeyField(); + fieldName = schemaField.getName(); + } + + return new AbstractDefaultValueUpdateProcessorFactory.DefaultValueUpdateProcessor(fieldName, next) { @Override - public Object getDefaultValue() { + public Object getDefaultValue() { return UUID.randomUUID().toString().toLowerCase(Locale.ROOT); } }; diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-update-processor-chains.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-update-processor-chains.xml index cd80c296877..b7be98e8bea 100644 --- a/solr/core/src/test-files/solr/collection1/conf/solrconfig-update-processor-chains.xml +++ b/solr/core/src/test-files/solr/collection1/conf/solrconfig-update-processor-chains.xml @@ -468,6 +468,18 @@ + + + + id + + + + + + + + uniq_.* diff --git a/solr/core/src/test/org/apache/solr/update/processor/UUIDUpdateProcessorFallbackTest.java b/solr/core/src/test/org/apache/solr/update/processor/UUIDUpdateProcessorFallbackTest.java new file mode 100644 index 00000000000..a11f9f43b78 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/update/processor/UUIDUpdateProcessorFallbackTest.java @@ -0,0 +1,155 @@ +package org.apache.solr.update.processor; + +/* + * 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.SolrTestCaseJ4; +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.SolrInputField; +import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.core.SolrCore; +import org.apache.solr.request.LocalSolrQueryRequest; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.request.SolrRequestInfo; +import org.apache.solr.response.SolrQueryResponse; +import org.apache.solr.update.AddUpdateCommand; +import org.junit.BeforeClass; + +import java.io.IOException; +import java.util.Date; +import java.util.UUID; + +public class UUIDUpdateProcessorFallbackTest extends SolrTestCaseJ4 { + + @BeforeClass + public static void beforeClass() throws Exception { + initCore("solrconfig-update-processor-chains.xml", "schema.xml"); + } + + public void testFallbackToUnique() throws Exception { + Date now = new Date(); + + // get all defaults + SolrInputDocument d = processAdd("default-values-fallback-to-unique", + doc(f("name", "Existing", "Values"))); + + assertNotNull(d); + + assertNotNull(d.getFieldValue("id")); + assertNotNull(UUID.fromString(d.getFieldValue("id").toString())); + + // get all defaults + d = processAdd("default-values-fallback-to-unique-automatically", + doc(f("name", "Existing", "Values"))); + + assertNotNull(d); + + assertNotNull(d.getFieldValue("id")); + assertNotNull(UUID.fromString(d.getFieldValue("id").toString())); + + // defaults already specified + d = processAdd("default-values-fallback-to-unique", + doc(f("timestamp", now), + f("id", "550e8400-e29b-41d4-a716-446655440000"), + f("processor_default_s", "I HAVE A VALUE"), + f("processor_default_i", 12345), + f("name", "Existing", "Values"))); + + assertNotNull(d); + + assertEquals("550e8400-e29b-41d4-a716-446655440000", + d.getFieldValue("id")); + + // defaults already specified + d = processAdd("default-values-fallback-to-unique-automatically", + doc(f("timestamp", now), + f("id", "550e8400-e29b-41d4-a716-446655440000"), + f("processor_default_s", "I HAVE A VALUE"), + f("processor_default_i", 121), + f("name", "Existing", "Values"))); + + assertNotNull(d); + + assertEquals("550e8400-e29b-41d4-a716-446655440000", + d.getFieldValue("id")); + assertEquals(121, d.getFieldValue("processor_default_i")); + } + + + /** + * Convenience method for building up SolrInputDocuments + */ + SolrInputDocument doc(SolrInputField... fields) { + SolrInputDocument d = new SolrInputDocument(); + for (SolrInputField f : fields) { + d.put(f.getName(), f); + } + return d; + } + + /** + * Convenience method for building up SolrInputFields + */ + SolrInputField field(String name, float boost, Object... values) { + SolrInputField f = new SolrInputField(name); + for (Object v : values) { + f.addValue(v, 1.0F); + } + f.setBoost(boost); + return f; + } + + /** + * Convenience method for building up SolrInputFields with default boost + */ + SolrInputField f(String name, Object... values) { + return field(name, 1.0F, values); + } + + + /** + * Runs a document through the specified chain, and returns the final + * document used when the chain is completed (NOTE: some chains may + * modify the document in place + */ + SolrInputDocument processAdd(final String chain, + final SolrInputDocument docIn) + throws IOException { + + SolrCore core = h.getCore(); + UpdateRequestProcessorChain pc = core.getUpdateProcessingChain(chain); + assertNotNull("No Chain named: " + chain, pc); + + SolrQueryResponse rsp = new SolrQueryResponse(); + + SolrQueryRequest req = new LocalSolrQueryRequest + (core, new ModifiableSolrParams()); + try { + SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req,rsp)); + AddUpdateCommand cmd = new AddUpdateCommand(req); + cmd.solrDoc = docIn; + + UpdateRequestProcessor processor = pc.createProcessor(req, rsp); + processor.processAdd(cmd); + + return cmd.solrDoc; + } finally { + SolrRequestInfo.clearRequestInfo(); + req.close(); + } + } +} diff --git a/solr/example/example-schemaless/solr/collection1/conf/solrconfig.xml b/solr/example/example-schemaless/solr/collection1/conf/solrconfig.xml index 98850fe21d5..cd991efd12f 100755 --- a/solr/example/example-schemaless/solr/collection1/conf/solrconfig.xml +++ b/solr/example/example-schemaless/solr/collection1/conf/solrconfig.xml @@ -1549,6 +1549,9 @@ See http://wiki.apache.org/solr/GuessingFieldTypes --> + + +