You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mu...@apache.org on 2021/01/07 16:47:49 UTC

[lucene-solr] 02/04: SOLR-14950: fix regenerating of copyfield with explicit src/dest matching dyn rule

This is an automated email from the ASF dual-hosted git repository.

munendrasn pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit 35ef6d2a41bc4ebf54a473998fcffeaf03293aca
Author: Munendra S N <mu...@apache.org>
AuthorDate: Wed Nov 25 08:52:38 2020 +0530

    SOLR-14950: fix regenerating of copyfield with explicit src/dest matching dyn rule
    
    CopyFields are regenerated in case of replace-field or replace-field-type.
    While regenerating, source and destionation are checked against fields but source/dest
    could match dynamic rule too.
    For example,
    <copyField source="something_s" dest="spellcheck"/>
    <dynamicField name="*_s" type="string"/>
    here, something_s is not present in schema but matches the dynamic rule.
    
    To handle the above case, need to check dynamicFieldCache too while regenerating the
    copyFields
---
 solr/CHANGES.txt                                   |   6 +-
 .../org/apache/solr/schema/ManagedIndexSchema.java |   5 +-
 .../apache/solr/rest/schema/TestBulkSchemaAPI.java | 102 +++++++++++++++++++++
 3 files changed, 110 insertions(+), 3 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 1f151dd..881e573 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -105,7 +105,11 @@ Bug Fixes
 
 * SOLR-15047: Fix collapse parser behavior when collapsing on numeric fields to differentiate '0' group from null group (hossman)
 
- * SOLR-10860: Return proper error code for bad input in case of inplace updates (Tomas Eduardo Fernandez Lobbe, Munendra S N)
+* SOLR-10860: Return proper error code for bad input in case of inplace updates (Tomas Eduardo Fernandez Lobbe, Munendra S N)
+
+* SOLR-14950: Fix error in copyField regeneration when explicit source/destination is not present in schema but
+  matches the dynamic rule. The copyFields are rebuilt with replace-field and replace-field-type, if required
+  (Andrew Shumway, Munendra S N)
 
 Other Changes
 ---------------------
diff --git a/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java b/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
index 3a06534..92e7016 100644
--- a/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
@@ -930,8 +930,9 @@ public final class ManagedIndexSchema extends IndexSchema {
   private void rebuildCopyFields(List<CopyField> oldCopyFields) {
     if (oldCopyFields.size() > 0) {
       for (CopyField copyField : oldCopyFields) {
-        SchemaField source = fields.get(copyField.getSource().getName());
-        SchemaField destination = fields.get(copyField.getDestination().getName());
+        // source or destination either could be explicit field which matches dynamic rule
+        SchemaField source = getFieldOrNull(copyField.getSource().getName());
+        SchemaField destination = getFieldOrNull(copyField.getDestination().getName());
         registerExplicitSrcAndDestFields
             (copyField.getSource().getName(), copyField.getMaxChars(), destination, source);
       }
diff --git a/solr/core/src/test/org/apache/solr/rest/schema/TestBulkSchemaAPI.java b/solr/core/src/test/org/apache/solr/rest/schema/TestBulkSchemaAPI.java
index ed7bd3e..b6afd25 100644
--- a/solr/core/src/test/org/apache/solr/rest/schema/TestBulkSchemaAPI.java
+++ b/solr/core/src/test/org/apache/solr/rest/schema/TestBulkSchemaAPI.java
@@ -708,6 +708,108 @@ public class TestBulkSchemaAPI extends RestTestBase {
     assertTrue("'bleh_s' copyField rule exists in the schema", l.isEmpty());
   }
 
+  @SuppressWarnings({"rawtypes"})
+  public void testCopyFieldWithReplace() throws Exception {
+    RestTestHarness harness = restTestHarness;
+    String newFieldName = "test_solr_14950";
+
+    // add-field-type
+    String addFieldTypeAnalyzer = "{\n" +
+        "'add-field-type' : {" +
+        "    'name' : 'myNewTextField',\n" +
+        "    'class':'solr.TextField',\n" +
+        "    'analyzer' : {\n" +
+        "        'charFilters' : [{\n" +
+        "                'name':'patternReplace',\n" +
+        "                'replacement':'$1$1',\n" +
+        "                'pattern':'([a-zA-Z])\\\\\\\\1+'\n" +
+        "            }],\n" +
+        "        'tokenizer' : { 'name':'whitespace' },\n" +
+        "        'filters' : [{ 'name':'asciiFolding' }]\n" +
+        "    }\n"+
+        "}}";
+
+    String response = restTestHarness.post("/schema", json(addFieldTypeAnalyzer));
+    Map map = (Map) fromJSONString(response);
+    assertNull(response, map.get("error"));
+    map = getObj(harness, "myNewTextField", "fieldTypes");
+    assertNotNull("'myNewTextField' field type does not exist in the schema", map);
+
+    // add-field
+    String payload = "{\n" +
+        "    'add-field' : {\n" +
+        "                 'name':'" + newFieldName + "',\n" +
+        "                 'type':'myNewTextField',\n" +
+        "                 'stored':true,\n" +
+        "                 'indexed':true\n" +
+        "                 }\n" +
+        "    }";
+
+    response = harness.post("/schema", json(payload));
+
+    map = (Map) fromJSONString(response);
+    assertNull(response, map.get("error"));
+
+    Map m = getObj(harness, newFieldName, "fields");
+    assertNotNull("'"+ newFieldName + "' field does not exist in the schema", m);
+
+    // add copy-field with explicit source and destination
+    List l = getSourceCopyFields(harness, "bleh_s");
+    assertTrue("'bleh_s' copyField rule exists in the schema", l.isEmpty());
+
+    payload = "{\n" +
+        "          'add-copy-field' : {\n" +
+        "                       'source' :'bleh_s',\n" +
+        "                       'dest':'"+ newFieldName + "'\n" +
+        "                       }\n" +
+        "          }\n";
+    response = harness.post("/schema", json(payload));
+
+    map = (Map) fromJSONString(response);
+    assertNull(response, map.get("error"));
+
+    l = getSourceCopyFields(harness, "bleh_s");
+    assertFalse("'bleh_s' copyField rule doesn't exist", l.isEmpty());
+    assertEquals("bleh_s", ((Map)l.get(0)).get("source"));
+    assertEquals(newFieldName, ((Map)l.get(0)).get("dest"));
+
+    // replace-field-type
+    String replaceFieldTypeAnalyzer = "{\n" +
+        "'replace-field-type' : {" +
+        "    'name' : 'myNewTextField',\n" +
+        "    'class':'solr.TextField',\n" +
+        "    'analyzer' : {\n" +
+        "        'tokenizer' : { 'name':'whitespace' },\n" +
+        "        'filters' : [{ 'name':'asciiFolding' }]\n" +
+        "    }\n"+
+        "}}";
+
+    response = restTestHarness.post("/schema", json(replaceFieldTypeAnalyzer));
+    map = (Map) fromJSONString(response);
+    assertNull(response, map.get("error"));
+
+    map = getObj(restTestHarness, "myNewTextField", "fieldTypes");
+    assertNotNull(map);
+    Map analyzer = (Map)map.get("analyzer");
+    assertNull("'myNewTextField' shouldn't contain charFilters", analyzer.get("charFilters"));
+
+    l = getSourceCopyFields(harness, "bleh_s");
+    assertFalse("'bleh_s' copyField rule doesn't exist", l.isEmpty());
+    assertEquals("bleh_s", ((Map)l.get(0)).get("source"));
+    assertEquals(newFieldName, ((Map)l.get(0)).get("dest"));
+
+    // with replace-field
+    String replaceField = "{'replace-field' : {'name':'" + newFieldName + "', 'type':'string'}}";
+    response = harness.post("/schema", json(replaceField));
+    map = (Map) fromJSONString(response);
+    assertNull(map.get("error"));
+
+    l = getSourceCopyFields(harness, "bleh_s");
+    assertFalse("'bleh_s' copyField rule doesn't exist", l.isEmpty());
+    assertEquals("bleh_s", ((Map)l.get(0)).get("source"));
+    assertEquals(newFieldName, ((Map)l.get(0)).get("dest"));
+  }
+
   @SuppressWarnings({"unchecked", "rawtypes"})
   public void testDeleteAndReplace() throws Exception {
     RestTestHarness harness = restTestHarness;