You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ja...@apache.org on 2024/01/05 20:02:55 UTC

(solr) branch main updated: SOLR-16203: Initialize schema plugins loaded by SPI name (#2175)

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

janhoy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 8201bf81d79 SOLR-16203: Initialize schema plugins loaded by SPI name (#2175)
8201bf81d79 is described below

commit 8201bf81d79b638f281c3d075ba7c5e240ee9e08
Author: Jan Høydahl <ja...@apache.org>
AuthorDate: Fri Jan 5 21:02:49 2024 +0100

    SOLR-16203: Initialize schema plugins loaded by SPI name (#2175)
---
 solr/CHANGES.txt                                   |  2 +
 .../java/org/apache/solr/schema/IndexSchema.java   | 77 +++++++++++++++++++-
 .../org/apache/solr/schema/ManagedIndexSchema.java | 85 ----------------------
 .../solr/schema/ResolveAnalyzerByNameTest.java     | 10 +++
 4 files changed, 88 insertions(+), 86 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index e485be878aa..270e3ea778b 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -163,6 +163,8 @@ Bug Fixes
 * SOLR-17098: ZK Credentials and ACLs are no longer sent to all ZK Servers when using Streaming Expressions.
   They will only be used when sent to the default ZK Host. (Houston Putman, Jan Høydahl, David Smiley, Gus Heck, Qing Xu)
 
+* SOLR-16203: Properly initialize schema plugins loaded by SPI name (janhoy, hossman, Uwe Schindler)
+
 Dependency Upgrades
 ---------------------
 * SOLR-17012: Update Apache Hadoop to 3.3.6 and Apache Curator to 5.5.0 (Kevin Risden)
diff --git a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
index c395a2c8928..06dad3175dc 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -45,12 +45,17 @@ import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.CharFilterFactory;
 import org.apache.lucene.analysis.DelegatingAnalyzerWrapper;
+import org.apache.lucene.analysis.TokenFilterFactory;
+import org.apache.lucene.analysis.TokenizerFactory;
 import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.queries.payloads.PayloadDecoder;
 import org.apache.lucene.search.similarities.Similarity;
 import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.ResourceLoaderAware;
 import org.apache.lucene.util.Version;
+import org.apache.solr.analysis.TokenizerChain;
 import org.apache.solr.common.ConfigNode;
 import org.apache.solr.common.MapSerializable;
 import org.apache.solr.common.SolrDocument;
@@ -652,7 +657,6 @@ public class IndexSchema {
       loadCopyFields(rootNode);
 
       postReadInform();
-
     } catch (SolrException e) {
       throw new SolrException(
           ErrorCode.getErrorCode(e.code()),
@@ -677,6 +681,8 @@ public class IndexSchema {
     for (SchemaAware aware : schemaAware) {
       aware.inform(this);
     }
+    // Make sure all analyzers have resource loaders, even SPI loaded ones
+    fieldTypes.values().forEach(this::informResourceLoaderAwareObjectsForFieldType);
   }
 
   /**
@@ -1991,6 +1997,37 @@ public class IndexSchema {
     throw new SolrException(ErrorCode.SERVER_ERROR, msg);
   }
 
+  /** Informs analyzers used by a fieldType. */
+  private void informResourceLoaderAwareObjectsForFieldType(FieldType fieldType) {
+    // must inform any sub-components used in the
+    // tokenizer chain if they are ResourceLoaderAware
+    if (!fieldType.supportsAnalyzers()) return;
+
+    Analyzer indexAnalyzer = fieldType.getIndexAnalyzer();
+    if (indexAnalyzer != null && indexAnalyzer instanceof TokenizerChain)
+      informResourceLoaderAwareObjectsInChain((TokenizerChain) indexAnalyzer);
+
+    Analyzer queryAnalyzer = fieldType.getQueryAnalyzer();
+    // ref comparison is correct here (vs. equals) as they may be the same
+    // object in which case, we don't need to inform twice ... however, it's
+    // actually safe to call inform multiple times on an object anyway
+    if (queryAnalyzer != null
+        && queryAnalyzer != indexAnalyzer
+        && queryAnalyzer instanceof TokenizerChain)
+      informResourceLoaderAwareObjectsInChain((TokenizerChain) queryAnalyzer);
+
+    // if fieldType is a TextField, it might have a multi-term analyzer
+    if (fieldType instanceof TextField) {
+      TextField textFieldType = (TextField) fieldType;
+      Analyzer multiTermAnalyzer = textFieldType.getMultiTermAnalyzer();
+      if (multiTermAnalyzer != null
+          && multiTermAnalyzer != indexAnalyzer
+          && multiTermAnalyzer != queryAnalyzer
+          && multiTermAnalyzer instanceof TokenizerChain)
+        informResourceLoaderAwareObjectsInChain((TokenizerChain) multiTermAnalyzer);
+    }
+  }
+
   /**
    * 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 to
@@ -2026,6 +2063,44 @@ public class IndexSchema {
     throw new SolrException(ErrorCode.SERVER_ERROR, msg);
   }
 
+  /**
+   * After creating a new FieldType, it may contain components that implement the
+   * ResourceLoaderAware interface, which need to be informed after they are loaded (as they depend
+   * on this callback to complete initialization work)
+   */
+  private void informResourceLoaderAwareObjectsInChain(TokenizerChain chain) {
+    CharFilterFactory[] charFilters = chain.getCharFilterFactories();
+    for (CharFilterFactory next : charFilters) {
+      if (next instanceof ResourceLoaderAware) {
+        try {
+          SolrResourceLoader.informAware(loader, (ResourceLoaderAware) next);
+        } catch (IOException e) {
+          throw new SolrException(ErrorCode.SERVER_ERROR, e);
+        }
+      }
+    }
+
+    TokenizerFactory tokenizerFactory = chain.getTokenizerFactory();
+    if (tokenizerFactory instanceof ResourceLoaderAware) {
+      try {
+        SolrResourceLoader.informAware(loader, (ResourceLoaderAware) tokenizerFactory);
+      } catch (IOException e) {
+        throw new SolrException(ErrorCode.SERVER_ERROR, e);
+      }
+    }
+
+    TokenFilterFactory[] filters = chain.getTokenFilterFactories();
+    for (TokenFilterFactory next : filters) {
+      if (next instanceof ResourceLoaderAware) {
+        try {
+          SolrResourceLoader.informAware(loader, (ResourceLoaderAware) next);
+        } catch (IOException e) {
+          throw new SolrException(ErrorCode.SERVER_ERROR, e);
+        }
+      }
+    }
+  }
+
   /**
    * Returns the schema update lock that should be synchronized on to update the schema. Only
    * applicable to mutable schemas.
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 d495a90fae6..b41728e1264 100644
--- a/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchema.java
@@ -16,8 +16,6 @@
  */
 package org.apache.solr.schema;
 
-import static org.apache.solr.core.SolrResourceLoader.informAware;
-
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.Writer;
@@ -40,14 +38,8 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.CharFilterFactory;
-import org.apache.lucene.analysis.TokenFilterFactory;
-import org.apache.lucene.analysis.TokenizerFactory;
 import org.apache.lucene.util.IOUtils;
-import org.apache.lucene.util.ResourceLoaderAware;
 import org.apache.lucene.util.Version;
-import org.apache.solr.analysis.TokenizerChain;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrResponse;
@@ -1299,45 +1291,6 @@ public final class ManagedIndexSchema extends IndexSchema {
     return newSchema;
   }
 
-  @Override
-  protected void postReadInform() {
-    super.postReadInform();
-    for (FieldType fieldType : fieldTypes.values()) {
-      informResourceLoaderAwareObjectsForFieldType(fieldType);
-    }
-  }
-
-  /** Informs analyzers used by a fieldType. */
-  private void informResourceLoaderAwareObjectsForFieldType(FieldType fieldType) {
-    // must inform any sub-components used in the
-    // tokenizer chain if they are ResourceLoaderAware
-    if (!fieldType.supportsAnalyzers()) return;
-
-    Analyzer indexAnalyzer = fieldType.getIndexAnalyzer();
-    if (indexAnalyzer != null && indexAnalyzer instanceof TokenizerChain)
-      informResourceLoaderAwareObjectsInChain((TokenizerChain) indexAnalyzer);
-
-    Analyzer queryAnalyzer = fieldType.getQueryAnalyzer();
-    // ref comparison is correct here (vs. equals) as they may be the same
-    // object in which case, we don't need to inform twice ... however, it's
-    // actually safe to call inform multiple times on an object anyway
-    if (queryAnalyzer != null
-        && queryAnalyzer != indexAnalyzer
-        && queryAnalyzer instanceof TokenizerChain)
-      informResourceLoaderAwareObjectsInChain((TokenizerChain) queryAnalyzer);
-
-    // if fieldType is a TextField, it might have a multi-term analyzer
-    if (fieldType instanceof TextField) {
-      TextField textFieldType = (TextField) fieldType;
-      Analyzer multiTermAnalyzer = textFieldType.getMultiTermAnalyzer();
-      if (multiTermAnalyzer != null
-          && multiTermAnalyzer != indexAnalyzer
-          && multiTermAnalyzer != queryAnalyzer
-          && multiTermAnalyzer instanceof TokenizerChain)
-        informResourceLoaderAwareObjectsInChain((TokenizerChain) multiTermAnalyzer);
-    }
-  }
-
   @Override
   public SchemaField newField(String fieldName, String fieldType, Map<String, ?> options) {
     SchemaField sf;
@@ -1436,44 +1389,6 @@ public final class ManagedIndexSchema extends IndexSchema {
     return ft;
   }
 
-  /**
-   * After creating a new FieldType, it may contain components that implement the
-   * ResourceLoaderAware interface, which need to be informed after they are loaded (as they depend
-   * on this callback to complete initialization work)
-   */
-  private void informResourceLoaderAwareObjectsInChain(TokenizerChain chain) {
-    CharFilterFactory[] charFilters = chain.getCharFilterFactories();
-    for (CharFilterFactory next : charFilters) {
-      if (next instanceof ResourceLoaderAware) {
-        try {
-          informAware(loader, (ResourceLoaderAware) next);
-        } catch (IOException e) {
-          throw new SolrException(ErrorCode.SERVER_ERROR, e);
-        }
-      }
-    }
-
-    TokenizerFactory tokenizerFactory = chain.getTokenizerFactory();
-    if (tokenizerFactory instanceof ResourceLoaderAware) {
-      try {
-        informAware(loader, (ResourceLoaderAware) tokenizerFactory);
-      } catch (IOException e) {
-        throw new SolrException(ErrorCode.SERVER_ERROR, e);
-      }
-    }
-
-    TokenFilterFactory[] filters = chain.getTokenFilterFactories();
-    for (TokenFilterFactory next : filters) {
-      if (next instanceof ResourceLoaderAware) {
-        try {
-          informAware(loader, (ResourceLoaderAware) next);
-        } catch (IOException e) {
-          throw new SolrException(ErrorCode.SERVER_ERROR, e);
-        }
-      }
-    }
-  }
-
   private ManagedIndexSchema(
       Version luceneVersion,
       SolrResourceLoader loader,
diff --git a/solr/core/src/test/org/apache/solr/schema/ResolveAnalyzerByNameTest.java b/solr/core/src/test/org/apache/solr/schema/ResolveAnalyzerByNameTest.java
index b64a098b82f..f21aa618a58 100644
--- a/solr/core/src/test/org/apache/solr/schema/ResolveAnalyzerByNameTest.java
+++ b/solr/core/src/test/org/apache/solr/schema/ResolveAnalyzerByNameTest.java
@@ -35,6 +35,16 @@ public class ResolveAnalyzerByNameTest extends SolrTestCaseJ4 {
     initCore("solrconfig-basic.xml", "schema-analyzer-by-name.xml");
   }
 
+  @Test
+  public void testAnalyzerUsableForQueries() throws Exception {
+    assertQ(req("text2:bogus"), "//*[@numFound='0']");
+  }
+
+  public void testAnalyzerUsableForIndexing() throws Exception {
+    assertU(adoc("text2", "fat cat"));
+    assertU(commit());
+  }
+
   @Test
   public void testSchemaLoadingSimpleAnalyzer() {
     SolrCore core = h.getCore();