diff --git a/contrib/adsabs/src/java/org/apache/solr/search/AqpAdsabsQParser.java b/contrib/adsabs/src/java/org/apache/solr/search/AqpAdsabsQParser.java index 540fed5ab..0a6ff9100 100644 --- a/contrib/adsabs/src/java/org/apache/solr/search/AqpAdsabsQParser.java +++ b/contrib/adsabs/src/java/org/apache/solr/search/AqpAdsabsQParser.java @@ -1,9 +1,13 @@ package org.apache.solr.search; +import java.text.DateFormat; import java.text.FieldPosition; import java.text.NumberFormat; +import java.text.ParseException; import java.text.ParsePosition; import java.text.SimpleDateFormat; +import java.time.temporal.TemporalAccessor; +import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -24,7 +28,6 @@ import org.apache.lucene.queryparser.flexible.core.QueryNodeParseException; import org.apache.lucene.queryparser.flexible.core.config.QueryConfigHandler; import org.apache.lucene.queryparser.flexible.standard.config.LegacyNumericConfig; -import org.apache.lucene.queryparser.flexible.standard.config.NumberDateFormat; import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler; import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.Operator; import org.apache.lucene.search.Query; @@ -35,6 +38,7 @@ import org.apache.solr.schema.IndexSchema; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.apache.solr.util.DateMathParser; /** * This is the MAIN solr entry point - this instantiates 'aqp' query @@ -52,6 +56,7 @@ public class AqpAdsabsQParser extends QParser { public static TimeZone UTC = TimeZone.getTimeZone("UTC"); public static final Logger log = LoggerFactory .getLogger(AqpAdsabsQParser.class); + private AqpQueryParser qParser; @@ -251,6 +256,49 @@ public AqpAdsabsQParser(AqpQueryParser parser, String qstr, SolrParams localPara } + public class NumberDateFormat extends NumberFormat { + + private static final long serialVersionUID = -4334084585068547470L; + final private DateFormat dateFormat; + + /** + * Constructs a {@link NumberDateFormat} object using the given {@link DateFormat}. + * + * @param dateFormat {@link DateFormat} used to parse and format dates + */ + public NumberDateFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public StringBuffer format(double number, StringBuffer toAppendTo, + FieldPosition pos) { + return dateFormat.format(new Date((long) number), toAppendTo, pos); + } + + @Override + public StringBuffer format(long number, StringBuffer toAppendTo, + FieldPosition pos) { + return dateFormat.format(new Date(number), toAppendTo, pos); + } + + @Override + public Number parse(String source, ParsePosition parsePosition) { + final Date date = dateFormat.parse(source, parsePosition); + return (date == null) ? null : date.getTime(); + } + + @Override + public StringBuffer format(Object number, StringBuffer toAppendTo, + FieldPosition pos) { + return dateFormat.format(number, toAppendTo, pos); + } + + public DateFormat getFormatter() { + return dateFormat; + } + + } /** * Internal class that allows us to accept '*' (lucene's way of saying 'anything') @@ -259,9 +307,11 @@ private class MaxNumberFormat extends NumberFormat { private static final long serialVersionUID = -407706279343648005L; private NumberFormat parser = null; private Number max = null; + private DateMathParser dParser = new DateMathParser(UTC); public MaxNumberFormat(Number max) { this(NumberFormat.getNumberInstance(Locale.US), max); + } public MaxNumberFormat(NumberFormat parser, Number max) { this.parser = parser; @@ -285,6 +335,15 @@ public Number parse(String source, ParsePosition parsePosition) { parsePosition.setIndex(1); return max; } + // it might be a symbolic date math + try { + Date date = dParser.parseMath(null, source); + DateFormat formatter = ((NumberDateFormat) parser).getFormatter(); + source = formatter.format(date); + } catch (SolrException e) { + // pass + } + return parser.parse(source, parsePosition); } diff --git a/contrib/adsabs/src/test/org/apache/solr/analysis/TestAdsabsTypeDateString.java b/contrib/adsabs/src/test/org/apache/solr/analysis/TestAdsabsTypeDateString.java index b04191fb9..2abbbc8d6 100644 --- a/contrib/adsabs/src/test/org/apache/solr/analysis/TestAdsabsTypeDateString.java +++ b/contrib/adsabs/src/test/org/apache/solr/analysis/TestAdsabsTypeDateString.java @@ -21,6 +21,7 @@ import monty.solr.util.MontySolrQueryTestCase; import monty.solr.util.MontySolrSetup; +import org.apache.lucene.queries.mlt.MoreLikeThisQuery; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.LegacyNumericRangeQuery; import org.junit.BeforeClass; @@ -86,6 +87,22 @@ public void test() throws Exception { // test the query parser does the right thing //setDebug(true); + // added symbolic date math parsing + assertQueryEquals(req("defType", "aqp", "q", "date:[\"1976-12-30T00:30:00Z\" TO \"1977-12-30T00:30:00Z\"]"), + "date:[220753800000 TO 252289800000]", + LegacyNumericRangeQuery.class); + assertQueryEquals(req("defType", "aqp", "q", "date:[\"1976-12-30T00:30:00Z\" TO \"1976-12-30T00:30:00Z+1YEAR\"]"), + "date:[220753800000 TO 252289800000]", + LegacyNumericRangeQuery.class); + + // will become: 1972-05-21T17:33:18.772Z + assertQueryEquals(req("defType", "aqp", "q", "date:\"1972-05-20T17:33:18.772Z+1DAY\""), + "date:[75317598000 TO 75317598000]", + LegacyNumericRangeQuery.class); + assertQueryEquals(req("defType", "aqp", "q", "date:\"1972-05-21T17:33:18.772Z\""), + "date:[75317598000 TO 75317598000]", + LegacyNumericRangeQuery.class); + // 2012-01-01T00:00:00 - 2012-02-01T00:00:00 (excl) assertQueryEquals(req("q", "pubdate:2012-01", "defType", "aqp"), "date:[1325376000000 TO 1328054400000}", diff --git a/contrib/adsabs/src/test/org/apache/solr/search/TestAqpAdsabsSolrSearch.java b/contrib/adsabs/src/test/org/apache/solr/search/TestAqpAdsabsSolrSearch.java index 8f47f2af8..3c490a8f2 100644 --- a/contrib/adsabs/src/test/org/apache/solr/search/TestAqpAdsabsSolrSearch.java +++ b/contrib/adsabs/src/test/org/apache/solr/search/TestAqpAdsabsSolrSearch.java @@ -375,6 +375,7 @@ public void testSpecialCases() throws Exception { "title", "title bitle")); assertU(commit("waitSearcher", "true")); + // similar() assertQueryEquals(req("defType", "aqp", "q", "similar(foo bar baz, input)"), "like:foo bar baz",