From 12a98467162b5e298227376ff02ebf643380e52c Mon Sep 17 00:00:00 2001 From: Renato Haeberli Date: Tue, 29 Sep 2026 08:24:43 +0200 Subject: [PATCH 1/2] ensure the upstream token is preserves its type and type is not set to SYNONYM for original token --- .../ManagedSynonymGraphFilterFactory.java | 20 +++++++++----- .../TestManagedSynonymGraphFilterFactory.java | 26 +++++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymGraphFilterFactory.java b/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymGraphFilterFactory.java index 6b9e6d6bedd2..47998ae9607b 100644 --- a/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymGraphFilterFactory.java +++ b/solr/core/src/java/org/apache/solr/rest/schema/analysis/ManagedSynonymGraphFilterFactory.java @@ -365,16 +365,24 @@ public void parse(Reader in) throws IOException, ParseException { boolean ignoreCase = synonymManager.getIgnoreCase(); for (CasePreservedSynonymMappings cpsm : synonymManager.synonymMappings.values()) { for (Map.Entry> entry : cpsm.mappings.entrySet()) { + // Use includeOrig=true so the original token keeps its upstream type and only the + // injected synonyms are tagged as SYNONYM + boolean mapsToItself = entry.getValue().contains(entry.getKey()); + CharsRef casedTerm = + analyze( + synonymManager.applyCaseSetting(ignoreCase, entry.getKey()), + new CharsRefBuilder()); for (String mapping : entry.getValue()) { - // apply the case setting to match the behavior of the SynonymMap builder - CharsRef casedTerm = - analyze( - synonymManager.applyCaseSetting(ignoreCase, entry.getKey()), - new CharsRefBuilder()); CharsRef casedMapping = analyze( synonymManager.applyCaseSetting(ignoreCase, mapping), new CharsRefBuilder()); - add(casedTerm, casedMapping, false); + if (mapsToItself) { + if (!casedTerm.equals(casedMapping)) { + add(casedTerm, casedMapping, true); + } + } else { + add(casedTerm, casedMapping, false); + } } } } diff --git a/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymGraphFilterFactory.java b/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymGraphFilterFactory.java index dc58da73485f..e42ddf06a9ae 100644 --- a/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymGraphFilterFactory.java +++ b/solr/core/src/test/org/apache/solr/rest/schema/analysis/TestManagedSynonymGraphFilterFactory.java @@ -247,6 +247,32 @@ public void testManagedSynonyms() throws Exception { assertJDelete(endpoint + "/cheerful/joyful", "/error/code==404"); } + @Test + public void testUpstreamTokenTypeIsPreserved() throws Exception { + String endpoint = "/schema/analysis/synonyms/englishgraph"; + + List equivGroup = Arrays.asList("funny", "entertaining", "whimsical"); + assertJPut(endpoint, toJSONString(equivGroup), "/responseHeader/status==0"); + + assertJQ(endpoint + "/funny", "/funny==['entertaining','funny','whimsical']"); + + restTestHarness.reload(); + + String analysisUrl = "/analysis/field?analysis.fieldtype=managed_graph_en&analysis.query=funny"; + String synFilter = "//arr[contains(@name,'SynonymGraphFilter')]"; + assertQ( + analysisUrl, + "count(" + + synFilter + + "/lst[str[@name='text'][.='funny']]/str[@name='type'][.='']) = 1", + "count(" + + synFilter + + "/lst[str[@name='text'][.='entertaining']]/str[@name='type'][.='SYNONYM']) = 1", + "count(" + + synFilter + + "/lst[str[@name='text'][.='whimsical']]/str[@name='type'][.='SYNONYM']) = 1"); + } + /** Can we add and remove stopwords with umlauts */ @Test public void testCanHandleDecodingAndEncodingForSynonyms() throws Exception { From affaa78bacc548f6777edd52205dc87573820367 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Wed, 21 Oct 2026 19:42:33 -0400 Subject: [PATCH 2/2] Add changelog entry CI's changelog-entry check was failing; this PR's fix was otherwise clean (verified: applies on current main, TestManagedSynonymGraphFilterFactory passes 5/5, and the new test genuinely fails without the fix). --- ...-original-token-type-managed-synonym-graph-filter.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 changelog/unreleased/preserve-original-token-type-managed-synonym-graph-filter.yml diff --git a/changelog/unreleased/preserve-original-token-type-managed-synonym-graph-filter.yml b/changelog/unreleased/preserve-original-token-type-managed-synonym-graph-filter.yml new file mode 100644 index 000000000000..08725631593d --- /dev/null +++ b/changelog/unreleased/preserve-original-token-type-managed-synonym-graph-filter.yml @@ -0,0 +1,9 @@ +# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc +title: ManagedSynonymGraphFilterFactory no longer tags the original token as type `SYNONYM` for equivalence-group mappings (e.g. `[terma]->[terma, termb, termc]`), using Lucene's `includeOrig` flag so only the injected synonyms get that type. +type: fixed +authors: + - name: Renato Haeberli + nick: renatoh +links: + - name: PR#4960 + url: https://github.com/apache/solr/pull/4960