From 5bef0651ca729b920f696b87f52b8fec09c2a7ed Mon Sep 17 00:00:00 2001 From: Cezary Witkowski Date: Mon, 17 Feb 2025 13:11:41 +0100 Subject: [PATCH] [MNT-24377] Fixed search date math by adding exclusion for date fields in a fix for SEARCH-779 (#2182) --- .../alfresco/solr/query/Solr4QueryParser.java | 46 +++++---- .../solr/dataload/TestDataProvider.java | 25 ++++- .../solr/query/afts/requestHandler/MNTIT.java | 16 ++- .../test-files/alfrescoModels/acme.xml | 98 +++++++++++++++++++ 4 files changed, 164 insertions(+), 21 deletions(-) create mode 100644 search-services/alfresco-search/src/test/resources/test-files/alfrescoModels/acme.xml diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/query/Solr4QueryParser.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/query/Solr4QueryParser.java index 4dfa281c2..ef446c760 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/query/Solr4QueryParser.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/query/Solr4QueryParser.java @@ -119,6 +119,7 @@ import org.apache.solr.handler.component.ShardHandlerFactory; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.DocsStreamer; import org.apache.solr.schema.IndexSchema; +import org.apache.solr.schema.NumberType; import org.apache.solr.schema.SchemaField; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.update.UpdateShardHandlerConfig; @@ -1517,26 +1518,16 @@ public class Solr4QueryParser extends QueryParser implements QueryConstants // make sure the field exists or return a dummy query so we have no // error ....ACE-3231 SchemaField schemaField = schema.getFieldOrNull(field); - boolean isNumeric = false; - if (schemaField == null) + + if (schemaField == null || schemaField.getType() == null) { return new TermQuery(new Term("_dummy_", "_miss_")); - } - else + } + + NumberType schemaFieldNumberType = schemaField.getType().getNumberType(); + if (isNonParsableNumberType(schemaFieldNumberType, queryText)) { - isNumeric = (schemaField.getType().getNumericType() != null); - if (isNumeric) - { - //Check to see if queryText is numeric or else it will fail. - try - { - Double.valueOf(queryText); - } - catch (NumberFormatException e) - { - return new TermQuery(new Term("_dummy_", "_miss_")); - } - } + return new TermQuery(new Term("_dummy_", "_miss_")); } // Use the analyzer to get all the tokens, and then build a TermQuery, @@ -2357,7 +2348,8 @@ public class Solr4QueryParser extends QueryParser implements QueryConstants { nextToken = list.get(0); String termText = nextToken.toString(); - if (!isNumeric && (termText.contains("*") || termText.contains("?"))) + boolean isNotNumberType = schemaFieldNumberType == null; + if (isNotNumberType && (termText.contains("*") || termText.contains("?"))) { return newWildcardQuery(new Term(field, termText)); } @@ -2642,6 +2634,24 @@ public class Solr4QueryParser extends QueryParser implements QueryConstants } } + private boolean isNonParsableNumberType(NumberType schemaFieldNumberType, String queryText) + { + boolean isNumberType = schemaFieldNumberType != null; + boolean isNotDate = schemaFieldNumberType != NumberType.DATE; + if (isNumberType && isNotDate) + { + try + { + Double.parseDouble(queryText); + } + catch (NumberFormatException e) + { + return true; + } + } + return false; + } + /** * @param list * @return diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/dataload/TestDataProvider.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/dataload/TestDataProvider.java index a99533957..6a648b01a 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/dataload/TestDataProvider.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/dataload/TestDataProvider.java @@ -60,10 +60,11 @@ import org.alfresco.solr.client.PropertyValue; import org.alfresco.solr.client.StringPropertyValue; import org.alfresco.solr.client.Transaction; import org.alfresco.util.ISO9075; -import org.apache.solr.client.solrj.io.Tuple; import org.apache.solr.core.SolrCore; import org.apache.solr.util.TestHarness; +import java.time.LocalDate; +import java.time.ZoneOffset; import java.util.AbstractMap; import java.util.Date; import java.util.HashMap; @@ -814,6 +815,26 @@ public class TestDataProvider implements AlfrescoSolrConstants QName n32QName = QName.createQName(CONTENT_MODEL_1_0_URI, "thirtytwo"); ChildAssociationRef n32CAR = new ChildAssociationRef(ASSOC_CONTAINS, rootNodeRef, n32QName, n32NodeRef, true, 0); addNode(core, dataModel, 1, 32, 1, TYPE_CONTENT, null, properties32, null, "system", new ChildAssociationRef[] {n32CAR}, new NodeRef[] {rootNodeRef}, new String[] { "/" + n32QName.toString() }, n32NodeRef, true); + + String acmeNamespaceURI = "http://www.acme.org/model/content/1.0"; + QName propertyQname = QName.createQName(acmeNamespaceURI, "date"); + QName acmeDocumentQName = QName.createQName(acmeNamespaceURI, "document"); + + Map properties33 = new HashMap<>(); + String todayStartOfDay = LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toString(); + properties33.put(propertyQname, value(todayStartOfDay)); + NodeRef n33NodeRef = newNodeRef(); + QName n33QName = QName.createQName(acmeNamespaceURI, "thirtythree"); + ChildAssociationRef n33CAR = new ChildAssociationRef(ASSOC_CONTAINS, rootNodeRef, n33QName, n33NodeRef, true, 0); + addNode(core, dataModel, 1, 33, 1, acmeDocumentQName, null, properties33, null, "system", new ChildAssociationRef[] {n33CAR}, new NodeRef[] {rootNodeRef}, new String[] { "/" + n33QName.toString() }, n33NodeRef, true); + + Map properties34 = new HashMap<>(); + String yesterdayStartOfDay = LocalDate.now().atStartOfDay().minusDays(1).toInstant(ZoneOffset.UTC).toString(); + properties34.put(propertyQname, value(yesterdayStartOfDay)); + NodeRef n34NodeRef = newNodeRef(); + QName n34QName = QName.createQName(acmeNamespaceURI, "thirtyfour"); + ChildAssociationRef n34CAR = new ChildAssociationRef(ASSOC_CONTAINS, rootNodeRef, n34QName, n34NodeRef, true, 0); + addNode(core, dataModel, 1, 34, 1, acmeDocumentQName, null, properties34, null, "system", new ChildAssociationRef[] {n34CAR}, new NodeRef[] {rootNodeRef}, new String[] { "/" + n34QName.toString() }, n34NodeRef, true); } private Map getOrderProperties() @@ -906,4 +927,4 @@ public class TestDataProvider implements AlfrescoSolrConstants { return new StringPropertyValue(value); } -} \ No newline at end of file +} diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/query/afts/requestHandler/MNTIT.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/query/afts/requestHandler/MNTIT.java index 3dbb2a977..13cb0cf9f 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/query/afts/requestHandler/MNTIT.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/query/afts/requestHandler/MNTIT.java @@ -92,4 +92,18 @@ public class MNTIT extends AbstractRequestHandlerIT assertResponseCardinality("\"AnalystName\" AND !\"AnalystName Craig\"", 1); assertResponseCardinality("cm:name:\"BASF*.txt\"", 4); } -} \ No newline at end of file + + @Test + public void mnt24377() + { + assertResponseCardinality("acme:date:*", 2); // sanity check to make sure test nodes are indexed + + assertResponseCardinality("acme:date:NOW/DAY+1DAY", 0); + assertResponseCardinality("acme:date:NOW/DAY", 1); + assertResponseCardinality("acme:date:NOW/DAY-1DAY", 1); + assertResponseCardinality("acme:date:NOW/DAY-2DAY", 0); + + assertResponseCardinality("acme:date:TODAY", 1); + assertResponseCardinality("acme:date:NOW", 0); + } +} diff --git a/search-services/alfresco-search/src/test/resources/test-files/alfrescoModels/acme.xml b/search-services/alfresco-search/src/test/resources/test-files/alfrescoModels/acme.xml new file mode 100644 index 000000000..036a41318 --- /dev/null +++ b/search-services/alfresco-search/src/test/resources/test-files/alfrescoModels/acme.xml @@ -0,0 +1,98 @@ + + + + + Sample Document Model + My Name + 1.0 + + + + + + + + + + + + + + + + + + + + + + Public + Client Confidential + Company Confidential + Strictly Confidential + + + + + + + + + + + Sample Document Type + cm:content + + + Document Identification Number + d:text + + + test property + d:text + + true + false + false + + + + d:date + + both + true + + + + + + + + + + ACME Security Classified + Content has been security classified + + + d:text + + true + false + false + + + + + + + + + + \ No newline at end of file