mirror of
https://github.com/Alfresco/SearchServices.git
synced 2025-09-10 14:11:25 +00:00
[MNT-24377] Fixed search date math by adding exclusion for date fields in a fix for SEARCH-779 (#2182)
This commit is contained in:
@@ -119,6 +119,7 @@ import org.apache.solr.handler.component.ShardHandlerFactory;
|
|||||||
import org.apache.solr.request.SolrQueryRequest;
|
import org.apache.solr.request.SolrQueryRequest;
|
||||||
import org.apache.solr.response.DocsStreamer;
|
import org.apache.solr.response.DocsStreamer;
|
||||||
import org.apache.solr.schema.IndexSchema;
|
import org.apache.solr.schema.IndexSchema;
|
||||||
|
import org.apache.solr.schema.NumberType;
|
||||||
import org.apache.solr.schema.SchemaField;
|
import org.apache.solr.schema.SchemaField;
|
||||||
import org.apache.solr.search.SolrIndexSearcher;
|
import org.apache.solr.search.SolrIndexSearcher;
|
||||||
import org.apache.solr.update.UpdateShardHandlerConfig;
|
import org.apache.solr.update.UpdateShardHandlerConfig;
|
||||||
@@ -1517,27 +1518,17 @@ public class Solr4QueryParser extends QueryParser implements QueryConstants
|
|||||||
// make sure the field exists or return a dummy query so we have no
|
// make sure the field exists or return a dummy query so we have no
|
||||||
// error ....ACE-3231
|
// error ....ACE-3231
|
||||||
SchemaField schemaField = schema.getFieldOrNull(field);
|
SchemaField schemaField = schema.getFieldOrNull(field);
|
||||||
boolean isNumeric = false;
|
|
||||||
if (schemaField == null)
|
if (schemaField == null || schemaField.getType() == null)
|
||||||
{
|
{
|
||||||
return new TermQuery(new Term("_dummy_", "_miss_"));
|
return new TermQuery(new Term("_dummy_", "_miss_"));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
NumberType schemaFieldNumberType = schemaField.getType().getNumberType();
|
||||||
isNumeric = (schemaField.getType().getNumericType() != null);
|
if (isNonParsableNumberType(schemaFieldNumberType, queryText))
|
||||||
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,
|
// Use the analyzer to get all the tokens, and then build a TermQuery,
|
||||||
// PhraseQuery, or noth
|
// PhraseQuery, or noth
|
||||||
@@ -2357,7 +2348,8 @@ public class Solr4QueryParser extends QueryParser implements QueryConstants
|
|||||||
{
|
{
|
||||||
nextToken = list.get(0);
|
nextToken = list.get(0);
|
||||||
String termText = nextToken.toString();
|
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));
|
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
|
* @param list
|
||||||
* @return
|
* @return
|
||||||
|
@@ -60,10 +60,11 @@ import org.alfresco.solr.client.PropertyValue;
|
|||||||
import org.alfresco.solr.client.StringPropertyValue;
|
import org.alfresco.solr.client.StringPropertyValue;
|
||||||
import org.alfresco.solr.client.Transaction;
|
import org.alfresco.solr.client.Transaction;
|
||||||
import org.alfresco.util.ISO9075;
|
import org.alfresco.util.ISO9075;
|
||||||
import org.apache.solr.client.solrj.io.Tuple;
|
|
||||||
import org.apache.solr.core.SolrCore;
|
import org.apache.solr.core.SolrCore;
|
||||||
import org.apache.solr.util.TestHarness;
|
import org.apache.solr.util.TestHarness;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.util.AbstractMap;
|
import java.util.AbstractMap;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -814,6 +815,26 @@ public class TestDataProvider implements AlfrescoSolrConstants
|
|||||||
QName n32QName = QName.createQName(CONTENT_MODEL_1_0_URI, "thirtytwo");
|
QName n32QName = QName.createQName(CONTENT_MODEL_1_0_URI, "thirtytwo");
|
||||||
ChildAssociationRef n32CAR = new ChildAssociationRef(ASSOC_CONTAINS, rootNodeRef, n32QName, n32NodeRef, true, 0);
|
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);
|
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<QName, PropertyValue> 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<QName, PropertyValue> 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<QName, PropertyValue> getOrderProperties()
|
private Map<QName, PropertyValue> getOrderProperties()
|
||||||
|
@@ -92,4 +92,18 @@ public class MNTIT extends AbstractRequestHandlerIT
|
|||||||
assertResponseCardinality("\"AnalystName\" AND !\"AnalystName Craig\"", 1);
|
assertResponseCardinality("\"AnalystName\" AND !\"AnalystName Craig\"", 1);
|
||||||
assertResponseCardinality("cm:name:\"BASF*.txt\"", 4);
|
assertResponseCardinality("cm:name:\"BASF*.txt\"", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,98 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<model name="acme:myContentModel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
|
||||||
|
|
||||||
|
<!-- Optional meta-data about the model -->
|
||||||
|
<description>Sample Document Model</description>
|
||||||
|
<author>My Name</author>
|
||||||
|
<version>1.0</version>
|
||||||
|
|
||||||
|
<imports>
|
||||||
|
<!-- Import Alfresco Dictionary Definitions -->
|
||||||
|
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
|
||||||
|
<!-- Import Alfresco Content Domain Model Definitions -->
|
||||||
|
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
|
||||||
|
<!-- Import Alfresco System Model Definitions -->
|
||||||
|
<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys"/>
|
||||||
|
</imports>
|
||||||
|
|
||||||
|
<!-- Custom namespace for the ACME company -->
|
||||||
|
<namespaces>
|
||||||
|
<namespace uri="http://www.acme.org/model/content/1.0" prefix="acme"/>
|
||||||
|
</namespaces>
|
||||||
|
|
||||||
|
<constraints>
|
||||||
|
<constraint name="acme:securityClassificationOptions" type="LIST">
|
||||||
|
<parameter name="allowedValues">
|
||||||
|
<list>
|
||||||
|
<value></value>
|
||||||
|
<!-- Empty for default search-->
|
||||||
|
<value>Public</value>
|
||||||
|
<value>Client Confidential</value>
|
||||||
|
<value>Company Confidential</value>
|
||||||
|
<value>Strictly Confidential</value>
|
||||||
|
</list>
|
||||||
|
</parameter>
|
||||||
|
</constraint>
|
||||||
|
</constraints>
|
||||||
|
|
||||||
|
<!-- ===============================================================================================================
|
||||||
|
Constraints, Types, and Aspects go here...
|
||||||
|
-->
|
||||||
|
|
||||||
|
<types>
|
||||||
|
<!--
|
||||||
|
ACME Enterprise-wide Document root type.
|
||||||
|
All other custom document types would extend this one.
|
||||||
|
-->
|
||||||
|
<type name="acme:document">
|
||||||
|
<title>Sample Document Type</title>
|
||||||
|
<parent>cm:content</parent>
|
||||||
|
<properties>
|
||||||
|
<property name="acme:documentId">
|
||||||
|
<title>Document Identification Number</title>
|
||||||
|
<type>d:text</type>
|
||||||
|
</property>
|
||||||
|
<property name="acme:test">
|
||||||
|
<title>test property</title>
|
||||||
|
<type>d:text</type>
|
||||||
|
<index enabled="true">
|
||||||
|
<atomic>true</atomic>
|
||||||
|
<stored>false</stored>
|
||||||
|
<tokenised>false</tokenised>
|
||||||
|
</index>
|
||||||
|
</property>
|
||||||
|
<property name="acme:date">
|
||||||
|
<type>d:date</type>
|
||||||
|
<index enabled="true">
|
||||||
|
<tokenised>both</tokenised>
|
||||||
|
<facetable>true</facetable>
|
||||||
|
</index>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
|
</type>
|
||||||
|
</types>
|
||||||
|
|
||||||
|
<aspects>
|
||||||
|
<!-- A document can have security classification applied and
|
||||||
|
faceted search is specifically enabled for best performance and we change
|
||||||
|
default index config to not tokenize the value. -->
|
||||||
|
<aspect name="acme:securityClassified">
|
||||||
|
<title>ACME Security Classified</title>
|
||||||
|
<description>Content has been security classified</description>
|
||||||
|
<properties>
|
||||||
|
<property name="acme:securityClassification">
|
||||||
|
<type>d:text</type>
|
||||||
|
<index enabled="true">
|
||||||
|
<atomic>true</atomic>
|
||||||
|
<stored>false</stored>
|
||||||
|
<tokenised>false</tokenised>
|
||||||
|
</index>
|
||||||
|
<constraints>
|
||||||
|
<constraint ref="acme:securityClassificationOptions"/>
|
||||||
|
</constraints>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
|
</aspect>
|
||||||
|
</aspects>
|
||||||
|
|
||||||
|
</model>
|
Reference in New Issue
Block a user