mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-25 01:19:02 +00:00
Add time_zone setting for query_string
Query String query now supports a new `time_zone` option based on JODA time zones. When using a range on date field, the time zone is applied. ```json { "query": { "query_string": { "text": "date:[2012 TO 2014]", "timezone": "Europe/Paris" } } } ``` Closes #7880.
This commit is contained in:
parent
65d40468b8
commit
0ff61e1d6f
@ -74,6 +74,9 @@ providing text to a numeric field) to be ignored.
|
||||
|
||||
|`locale` | Locale that should be used for string conversions.
|
||||
Defaults to `ROOT`.
|
||||
|
||||
|`time_zone` | Time Zone to be applied to any range query related to dates. See also
|
||||
http://joda-time.sourceforge.net/api-release/org/joda/time/DateTimeZone.html[JODA timezone].
|
||||
|=======================================================================
|
||||
|
||||
When a multi term query is being generated, one can control how it gets
|
||||
|
@ -126,6 +126,9 @@ public class MapperQueryParser extends QueryParser {
|
||||
setFuzzyMinSim(settings.fuzzyMinSim());
|
||||
setFuzzyPrefixLength(settings.fuzzyPrefixLength());
|
||||
setLocale(settings.locale());
|
||||
if (settings.timeZone() != null) {
|
||||
setTimeZone(settings.timeZone().toTimeZone());
|
||||
}
|
||||
this.analyzeWildcard = settings.analyzeWildcard();
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ import com.carrotsearch.hppc.ObjectFloatOpenHashMap;
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.search.FuzzyQuery;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@ -61,7 +62,7 @@ public class QueryParserSettings {
|
||||
private String minimumShouldMatch;
|
||||
private boolean lenient;
|
||||
private Locale locale;
|
||||
|
||||
private DateTimeZone timeZone;
|
||||
|
||||
List<String> fields = null;
|
||||
Collection<String> queryTypes = null;
|
||||
@ -306,6 +307,14 @@ public class QueryParserSettings {
|
||||
return this.locale;
|
||||
}
|
||||
|
||||
public void timeZone(DateTimeZone timeZone) {
|
||||
this.timeZone = timeZone;
|
||||
}
|
||||
|
||||
public DateTimeZone timeZone() {
|
||||
return this.timeZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@ -349,6 +358,9 @@ public class QueryParserSettings {
|
||||
if (locale != null ? !locale.equals(that.locale) : that.locale != null) {
|
||||
return false;
|
||||
}
|
||||
if (timeZone != null ? !timeZone.equals(that.timeZone) : that.timeZone != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Float.compare(that.tieBreaker, tieBreaker) != 0) return false;
|
||||
if (useDisMax != that.useDisMax) return false;
|
||||
@ -385,6 +397,7 @@ public class QueryParserSettings {
|
||||
result = 31 * result + (tieBreaker != +0.0f ? Float.floatToIntBits(tieBreaker) : 0);
|
||||
result = 31 * result + (useDisMax ? 1 : 0);
|
||||
result = 31 * result + (locale != null ? locale.hashCode() : 0);
|
||||
result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,8 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder implements Boostab
|
||||
|
||||
private String queryName;
|
||||
|
||||
private String timeZone;
|
||||
|
||||
public QueryStringQueryBuilder(String queryString) {
|
||||
this.queryString = queryString;
|
||||
}
|
||||
@ -319,6 +321,14 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder implements Boostab
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* In case of date field, we can adjust the from/to fields using a timezone
|
||||
*/
|
||||
public QueryStringQueryBuilder timeZone(String timeZone) {
|
||||
this.timeZone = timeZone;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(QueryStringQueryParser.NAME);
|
||||
@ -402,6 +412,9 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder implements Boostab
|
||||
if (locale != null) {
|
||||
builder.field("locale", locale.toString());
|
||||
}
|
||||
if (timeZone != null) {
|
||||
builder.field("time_zone", timeZone);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.joda.DateMathParser;
|
||||
import org.elasticsearch.common.lucene.search.Queries;
|
||||
import org.elasticsearch.common.regex.Regex;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
@ -191,6 +192,12 @@ public class QueryStringQueryParser implements QueryParser {
|
||||
} else if ("locale".equals(currentFieldName)) {
|
||||
String localeStr = parser.text();
|
||||
qpSettings.locale(LocaleUtils.parse(localeStr));
|
||||
} else if ("time_zone".equals(currentFieldName)) {
|
||||
try {
|
||||
qpSettings.timeZone(DateMathParser.parseZone(parser.text()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new QueryParsingException(parseContext.index(), "[query_string] time_zone [" + parser.text() + "] is unknown");
|
||||
}
|
||||
} else if ("_name".equals(currentFieldName)) {
|
||||
queryName = parser.text();
|
||||
} else {
|
||||
|
@ -250,6 +250,21 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
|
||||
assertThat((double) disjuncts.get(1).getBoost(), closeTo(1, 0.01));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryStringTimezone() throws Exception {
|
||||
IndexQueryParserService queryParser = queryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/query-timezone.json");
|
||||
Query parsedQuery = queryParser.parse(query).query();
|
||||
assertThat(parsedQuery, instanceOf(TermRangeQuery.class));
|
||||
|
||||
try {
|
||||
queryParser.parse(copyToStringFromClasspath("/org/elasticsearch/index/query/query-timezone-incorrect.json"));
|
||||
fail("we expect a QueryParsingException as we are providing an unknown time_zome");
|
||||
} catch (QueryParsingException e) {
|
||||
// We expect this one
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchAllBuilder() throws Exception {
|
||||
IndexQueryParserService queryParser = queryParser();
|
||||
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"query_string":{
|
||||
"time_zone":"This timezone does not exist",
|
||||
"query":"date:[2012 TO 2014]"
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"query_string":{
|
||||
"time_zone":"Europe/Paris",
|
||||
"query":"date:[2012 TO 2014]"
|
||||
}
|
||||
}
|
@ -47,10 +47,7 @@ import org.joda.time.format.ISODateTimeFormat;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
|
||||
@ -557,6 +554,26 @@ public class SimpleQueryTests extends ElasticsearchIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test // https://github.com/elasticsearch/elasticsearch/issues/7880
|
||||
public void testDateRangeInQueryStringWithTimeZone_7880() {
|
||||
//the mapping needs to be provided upfront otherwise we are not sure how many failures we get back
|
||||
//as with dynamic mappings some shards might be lacking behind and parse a different query
|
||||
assertAcked(prepareCreate("test").addMapping(
|
||||
"type", "past", "type=date"
|
||||
));
|
||||
ensureGreen();
|
||||
|
||||
DateTimeZone timeZone = randomDateTimeZone();
|
||||
String now = ISODateTimeFormat.dateTime().print(new DateTime(timeZone));
|
||||
logger.info(" --> Using time_zone [{}], now is [{}]", timeZone.getID(), now);
|
||||
client().prepareIndex("test", "type", "1").setSource("past", now).get();
|
||||
refresh();
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch().setQuery(queryString("past:[now-1m/m TO now+1m/m]")
|
||||
.timeZone(timeZone.getID())).get();
|
||||
assertHitCount(searchResponse, 1l);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typeFilterTypeIndexedTests() throws Exception {
|
||||
typeFilterTests("not_analyzed");
|
||||
|
@ -102,6 +102,7 @@ import org.elasticsearch.search.SearchService;
|
||||
import org.elasticsearch.test.client.RandomizingClient;
|
||||
import org.elasticsearch.test.disruption.ServiceDisruptionScheme;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.junit.*;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -1676,6 +1677,23 @@ public abstract class ElasticsearchIntegrationTest extends ElasticsearchTestCase
|
||||
return randomFrom(Arrays.asList("paged_bytes", "fst", "doc_values"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random JODA Time Zone based on Java Time Zones
|
||||
*/
|
||||
public static DateTimeZone randomDateTimeZone() {
|
||||
DateTimeZone timeZone;
|
||||
|
||||
// It sounds like some Java Time Zones are unknown by JODA. For example: Asia/Riyadh88
|
||||
// We need to fallback in that case to a known time zone
|
||||
try {
|
||||
timeZone = DateTimeZone.forTimeZone(randomTimeZone());
|
||||
} catch (IllegalArgumentException e) {
|
||||
timeZone = DateTimeZone.forOffsetHours(randomIntBetween(-12, 12));
|
||||
}
|
||||
|
||||
return timeZone;
|
||||
}
|
||||
|
||||
protected NumShards getNumShards(String index) {
|
||||
MetaData metaData = client().admin().cluster().prepareState().get().getState().metaData();
|
||||
assertThat(metaData.hasIndex(index), equalTo(true));
|
||||
|
Loading…
x
Reference in New Issue
Block a user