Backport of fe9145f Closes #61546
This commit is contained in:
parent
0d5250c99b
commit
a0df0fb074
|
@ -41,6 +41,10 @@ provided `<field>`.
|
||||||
(Optional, string) Method used to rewrite the query. For valid values and more
|
(Optional, string) Method used to rewrite the query. For valid values and more
|
||||||
information, see the <<query-dsl-multi-term-rewrite, `rewrite` parameter>>.
|
information, see the <<query-dsl-multi-term-rewrite, `rewrite` parameter>>.
|
||||||
|
|
||||||
|
`case_insensitive`::
|
||||||
|
(Optional, boolean) allows ASCII case insensitive matching of the
|
||||||
|
value with the indexed field values when set to true. Setting to false is disallowed.
|
||||||
|
|
||||||
[[prefix-query-notes]]
|
[[prefix-query-notes]]
|
||||||
==== Notes
|
==== Notes
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,10 @@ Boost values are relative to the default value of `1.0`. A boost value between
|
||||||
`0` and `1.0` decreases the relevance score. A value greater than `1.0`
|
`0` and `1.0` decreases the relevance score. A value greater than `1.0`
|
||||||
increases the relevance score.
|
increases the relevance score.
|
||||||
|
|
||||||
|
`case_insensitive`::
|
||||||
|
(Optional, boolean) allows ASCII case insensitive matching of the
|
||||||
|
value with the indexed field values when set to true. Setting to false is disallowed.
|
||||||
|
|
||||||
[[term-query-notes]]
|
[[term-query-notes]]
|
||||||
==== Notes
|
==== Notes
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,10 @@ increases the relevance score.
|
||||||
(Optional, string) Method used to rewrite the query. For valid values and more information, see the
|
(Optional, string) Method used to rewrite the query. For valid values and more information, see the
|
||||||
<<query-dsl-multi-term-rewrite, `rewrite` parameter>>.
|
<<query-dsl-multi-term-rewrite, `rewrite` parameter>>.
|
||||||
|
|
||||||
|
`case_insensitive`::
|
||||||
|
(Optional, boolean) allows case insensitive matching of the
|
||||||
|
pattern with the indexed field values when set to true. Setting to false is disallowed.
|
||||||
|
|
||||||
[[wildcard-query-notes]]
|
[[wildcard-query-notes]]
|
||||||
==== Notes
|
==== Notes
|
||||||
===== Allow expensive queries
|
===== Allow expensive queries
|
||||||
|
|
|
@ -281,11 +281,11 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
if (prefixField == null || prefixField.termLengthWithinBounds(value.length()) == false) {
|
if (prefixField == null || prefixField.termLengthWithinBounds(value.length()) == false) {
|
||||||
return super.prefixQuery(value, method, context);
|
return super.prefixQuery(value, method, caseInsensitive, context);
|
||||||
} else {
|
} else {
|
||||||
final Query query = prefixField.prefixQuery(value, method, context);
|
final Query query = prefixField.prefixQuery(value, method, caseInsensitive, context);
|
||||||
if (method == null
|
if (method == null
|
||||||
|| method == MultiTermQuery.CONSTANT_SCORE_REWRITE
|
|| method == MultiTermQuery.CONSTANT_SCORE_REWRITE
|
||||||
|| method == MultiTermQuery.CONSTANT_SCORE_BOOLEAN_REWRITE) {
|
|| method == MultiTermQuery.CONSTANT_SCORE_BOOLEAN_REWRITE) {
|
||||||
|
@ -365,8 +365,11 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
if (value.length() >= minChars) {
|
if (value.length() >= minChars) {
|
||||||
|
if(caseInsensitive) {
|
||||||
|
return super.termQueryCaseInsensitive(value, context);
|
||||||
|
}
|
||||||
return super.termQuery(value, context);
|
return super.termQuery(value, context);
|
||||||
}
|
}
|
||||||
List<Automaton> automata = new ArrayList<>();
|
List<Automaton> automata = new ArrayList<>();
|
||||||
|
@ -507,11 +510,11 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
if (prefixFieldType == null || prefixFieldType.termLengthWithinBounds(value.length()) == false) {
|
if (prefixFieldType == null || prefixFieldType.termLengthWithinBounds(value.length()) == false) {
|
||||||
return super.prefixQuery(value, method, context);
|
return super.prefixQuery(value, method, caseInsensitive, context);
|
||||||
} else {
|
} else {
|
||||||
final Query query = prefixFieldType.prefixQuery(value, method, context);
|
final Query query = prefixFieldType.prefixQuery(value, method, caseInsensitive, context);
|
||||||
if (method == null
|
if (method == null
|
||||||
|| method == MultiTermQuery.CONSTANT_SCORE_REWRITE
|
|| method == MultiTermQuery.CONSTANT_SCORE_REWRITE
|
||||||
|| method == MultiTermQuery.CONSTANT_SCORE_BOOLEAN_REWRITE) {
|
|| method == MultiTermQuery.CONSTANT_SCORE_BOOLEAN_REWRITE) {
|
||||||
|
|
|
@ -136,13 +136,15 @@ public class ICUCollationKeywordFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method,
|
||||||
|
boolean caseInsensitive, QueryShardContext context) {
|
||||||
throw new UnsupportedOperationException("[prefix] queries are not supported on [" + CONTENT_TYPE + "] fields.");
|
throw new UnsupportedOperationException("[prefix] queries are not supported on [" + CONTENT_TYPE + "] fields.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query wildcardQuery(String value,
|
public Query wildcardQuery(String value,
|
||||||
@Nullable MultiTermQuery.RewriteMethod method,
|
@Nullable MultiTermQuery.RewriteMethod method,
|
||||||
|
boolean caseInsensitive,
|
||||||
QueryShardContext context) {
|
QueryShardContext context) {
|
||||||
throw new UnsupportedOperationException("[wildcard] queries are not supported on [" + CONTENT_TYPE + "] fields.");
|
throw new UnsupportedOperationException("[wildcard] queries are not supported on [" + CONTENT_TYPE + "] fields.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -879,4 +879,18 @@ public class Strings {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toLowercaseAscii(String in) {
|
||||||
|
StringBuilder out = new StringBuilder();
|
||||||
|
Iterator<Integer> iter = in.codePoints().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
int codepoint = iter.next();
|
||||||
|
if (codepoint > 128) {
|
||||||
|
out.appendCodePoint(codepoint);
|
||||||
|
} else {
|
||||||
|
out.appendCodePoint(Character.toLowerCase(codepoint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.common.lucene.search;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.Term;
|
||||||
|
import org.apache.lucene.search.AutomatonQuery;
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.apache.lucene.util.automaton.Automata;
|
||||||
|
import org.apache.lucene.util.automaton.Automaton;
|
||||||
|
import org.apache.lucene.util.automaton.MinimizationOperations;
|
||||||
|
import org.apache.lucene.util.automaton.Operations;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper functions for creating various forms of {@link AutomatonQuery}
|
||||||
|
*/
|
||||||
|
public class AutomatonQueries {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Build an automaton query accepting all terms with the specified prefix, ASCII case insensitive. */
|
||||||
|
public static Automaton caseInsensitivePrefix(String s) {
|
||||||
|
List<Automaton> list = new ArrayList<>();
|
||||||
|
Iterator<Integer> iter = s.codePoints().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
list.add(toCaseInsensitiveChar(iter.next(), Integer.MAX_VALUE));
|
||||||
|
}
|
||||||
|
list.add(Automata.makeAnyString());
|
||||||
|
|
||||||
|
Automaton a = Operations.concatenate(list);
|
||||||
|
a = MinimizationOperations.minimize(a, Integer.MAX_VALUE);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Build an automaton query accepting all terms with the specified prefix, ASCII case insensitive. */
|
||||||
|
public static AutomatonQuery caseInsensitivePrefixQuery(Term prefix) {
|
||||||
|
return new AutomatonQuery(prefix, caseInsensitivePrefix(prefix.text()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Build an automaton accepting all terms ASCII case insensitive. */
|
||||||
|
public static AutomatonQuery caseInsensitiveTermQuery(Term term) {
|
||||||
|
BytesRef prefix = term.bytes();
|
||||||
|
return new AutomatonQuery(term, toCaseInsensitiveString(prefix,Integer.MAX_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Build an automaton matching a wildcard pattern, ASCII case insensitive. */
|
||||||
|
public static AutomatonQuery caseInsensitiveWildcardQuery(Term wildcardquery) {
|
||||||
|
return new AutomatonQuery(wildcardquery, toCaseInsensitiveWildcardAutomaton(wildcardquery,Integer.MAX_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** String equality with support for wildcards */
|
||||||
|
public static final char WILDCARD_STRING = '*';
|
||||||
|
|
||||||
|
/** Char equality with support for wildcards */
|
||||||
|
public static final char WILDCARD_CHAR = '?';
|
||||||
|
|
||||||
|
/** Escape character */
|
||||||
|
public static final char WILDCARD_ESCAPE = '\\';
|
||||||
|
/**
|
||||||
|
* Convert Lucene wildcard syntax into an automaton.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("fallthrough")
|
||||||
|
public static Automaton toCaseInsensitiveWildcardAutomaton(Term wildcardquery, int maxDeterminizedStates) {
|
||||||
|
List<Automaton> automata = new ArrayList<>();
|
||||||
|
|
||||||
|
String wildcardText = wildcardquery.text();
|
||||||
|
|
||||||
|
for (int i = 0; i < wildcardText.length();) {
|
||||||
|
final int c = wildcardText.codePointAt(i);
|
||||||
|
int length = Character.charCount(c);
|
||||||
|
switch(c) {
|
||||||
|
case WILDCARD_STRING:
|
||||||
|
automata.add(Automata.makeAnyString());
|
||||||
|
break;
|
||||||
|
case WILDCARD_CHAR:
|
||||||
|
automata.add(Automata.makeAnyChar());
|
||||||
|
break;
|
||||||
|
case WILDCARD_ESCAPE:
|
||||||
|
// add the next codepoint instead, if it exists
|
||||||
|
if (i + length < wildcardText.length()) {
|
||||||
|
final int nextChar = wildcardText.codePointAt(i + length);
|
||||||
|
length += Character.charCount(nextChar);
|
||||||
|
automata.add(Automata.makeChar(nextChar));
|
||||||
|
break;
|
||||||
|
} // else fallthru, lenient parsing with a trailing \
|
||||||
|
default:
|
||||||
|
automata.add(toCaseInsensitiveChar(c, maxDeterminizedStates));
|
||||||
|
}
|
||||||
|
i += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Operations.concatenate(automata);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Automaton toCaseInsensitiveString(BytesRef br, int maxDeterminizedStates) {
|
||||||
|
return toCaseInsensitiveString(br.utf8ToString(), maxDeterminizedStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Automaton toCaseInsensitiveString(String s, int maxDeterminizedStates) {
|
||||||
|
List<Automaton> list = new ArrayList<>();
|
||||||
|
Iterator<Integer> iter = s.codePoints().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
list.add(toCaseInsensitiveChar(iter.next(), maxDeterminizedStates));
|
||||||
|
}
|
||||||
|
|
||||||
|
Automaton a = Operations.concatenate(list);
|
||||||
|
a = MinimizationOperations.minimize(a, maxDeterminizedStates);
|
||||||
|
return a;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Automaton toCaseInsensitiveChar(int codepoint, int maxDeterminizedStates) {
|
||||||
|
Automaton case1 = Automata.makeChar(codepoint);
|
||||||
|
// For now we only work with ASCII characters
|
||||||
|
if (codepoint > 128) {
|
||||||
|
return case1;
|
||||||
|
}
|
||||||
|
int altCase = Character.isLowerCase(codepoint) ? Character.toUpperCase(codepoint) : Character.toLowerCase(codepoint);
|
||||||
|
Automaton result;
|
||||||
|
if (altCase != codepoint) {
|
||||||
|
result = Operations.union(case1, Automata.makeChar(altCase));
|
||||||
|
result = MinimizationOperations.minimize(result, maxDeterminizedStates);
|
||||||
|
} else {
|
||||||
|
result = case1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -79,15 +79,39 @@ public class Regex {
|
||||||
* Match a String against the given pattern, supporting the following simple
|
* Match a String against the given pattern, supporting the following simple
|
||||||
* pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
|
* pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
|
||||||
* arbitrary number of pattern parts), as well as direct equality.
|
* arbitrary number of pattern parts), as well as direct equality.
|
||||||
|
* Matching is case sensitive.
|
||||||
*
|
*
|
||||||
* @param pattern the pattern to match against
|
* @param pattern the pattern to match against
|
||||||
* @param str the String to match
|
* @param str the String to match
|
||||||
* @return whether the String matches the given pattern
|
* @return whether the String matches the given pattern
|
||||||
*/
|
*/
|
||||||
public static boolean simpleMatch(String pattern, String str) {
|
public static boolean simpleMatch(String pattern, String str) {
|
||||||
|
return simpleMatch(pattern, str, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match a String against the given pattern, supporting the following simple
|
||||||
|
* pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
|
||||||
|
* arbitrary number of pattern parts), as well as direct equality.
|
||||||
|
*
|
||||||
|
* @param pattern the pattern to match against
|
||||||
|
* @param str the String to match
|
||||||
|
* @param caseInsensitive true if ASCII case differences should be ignored
|
||||||
|
* @return whether the String matches the given pattern
|
||||||
|
*/
|
||||||
|
public static boolean simpleMatch(String pattern, String str, boolean caseInsensitive) {
|
||||||
if (pattern == null || str == null) {
|
if (pattern == null || str == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (caseInsensitive) {
|
||||||
|
pattern = Strings.toLowercaseAscii(pattern);
|
||||||
|
str = Strings.toLowercaseAscii(str);
|
||||||
|
}
|
||||||
|
return simpleMatchWithNormalizedStrings(pattern, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean simpleMatchWithNormalizedStrings(String pattern, String str) {
|
||||||
final int firstIndex = pattern.indexOf('*');
|
final int firstIndex = pattern.indexOf('*');
|
||||||
if (firstIndex == -1) {
|
if (firstIndex == -1) {
|
||||||
return pattern.equals(str);
|
return pattern.equals(str);
|
||||||
|
@ -102,12 +126,12 @@ public class Regex {
|
||||||
return str.regionMatches(str.length() - pattern.length() + 1, pattern, 1, pattern.length() - 1);
|
return str.regionMatches(str.length() - pattern.length() + 1, pattern, 1, pattern.length() - 1);
|
||||||
} else if (nextIndex == 1) {
|
} else if (nextIndex == 1) {
|
||||||
// Double wildcard "**" - skipping the first "*"
|
// Double wildcard "**" - skipping the first "*"
|
||||||
return simpleMatch(pattern.substring(1), str);
|
return simpleMatchWithNormalizedStrings(pattern.substring(1), str);
|
||||||
}
|
}
|
||||||
final String part = pattern.substring(1, nextIndex);
|
final String part = pattern.substring(1, nextIndex);
|
||||||
int partIndex = str.indexOf(part);
|
int partIndex = str.indexOf(part);
|
||||||
while (partIndex != -1) {
|
while (partIndex != -1) {
|
||||||
if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) {
|
if (simpleMatchWithNormalizedStrings(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
partIndex = str.indexOf(part, partIndex + 1);
|
partIndex = str.indexOf(part, partIndex + 1);
|
||||||
|
@ -116,7 +140,7 @@ public class Regex {
|
||||||
}
|
}
|
||||||
return str.regionMatches(0, pattern, 0, firstIndex)
|
return str.regionMatches(0, pattern, 0, firstIndex)
|
||||||
&& (firstIndex == pattern.length() - 1 // only wildcard in pattern is at the end, so no need to look at the rest of the string
|
&& (firstIndex == pattern.length() - 1 // only wildcard in pattern is at the end, so no need to look at the rest of the string
|
||||||
|| simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex)));
|
|| simpleMatchWithNormalizedStrings(pattern.substring(firstIndex), str.substring(firstIndex)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -59,7 +59,7 @@ public abstract class ConstantFieldType extends MappedFieldType {
|
||||||
* Return whether the constant value of this field matches the provided {@code pattern}
|
* Return whether the constant value of this field matches the provided {@code pattern}
|
||||||
* as documented in {@link Regex#simpleMatch}.
|
* as documented in {@link Regex#simpleMatch}.
|
||||||
*/
|
*/
|
||||||
protected abstract boolean matches(String pattern, QueryShardContext context);
|
protected abstract boolean matches(String pattern, boolean caseInsensitive, QueryShardContext context);
|
||||||
|
|
||||||
private static String valueToString(Object value) {
|
private static String valueToString(Object value) {
|
||||||
return value instanceof BytesRef
|
return value instanceof BytesRef
|
||||||
|
@ -70,7 +70,17 @@ public abstract class ConstantFieldType extends MappedFieldType {
|
||||||
@Override
|
@Override
|
||||||
public final Query termQuery(Object value, QueryShardContext context) {
|
public final Query termQuery(Object value, QueryShardContext context) {
|
||||||
String pattern = valueToString(value);
|
String pattern = valueToString(value);
|
||||||
if (matches(pattern, context)) {
|
if (matches(pattern, false, context)) {
|
||||||
|
return Queries.newMatchAllQuery();
|
||||||
|
} else {
|
||||||
|
return new MatchNoDocsQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Query termQueryCaseInsensitive(Object value, QueryShardContext context) {
|
||||||
|
String pattern = valueToString(value);
|
||||||
|
if (matches(pattern, true, context)) {
|
||||||
return Queries.newMatchAllQuery();
|
return Queries.newMatchAllQuery();
|
||||||
} else {
|
} else {
|
||||||
return new MatchNoDocsQuery();
|
return new MatchNoDocsQuery();
|
||||||
|
@ -81,7 +91,7 @@ public abstract class ConstantFieldType extends MappedFieldType {
|
||||||
public final Query termsQuery(List<?> values, QueryShardContext context) {
|
public final Query termsQuery(List<?> values, QueryShardContext context) {
|
||||||
for (Object value : values) {
|
for (Object value : values) {
|
||||||
String pattern = valueToString(value);
|
String pattern = valueToString(value);
|
||||||
if (matches(pattern, context)) {
|
if (matches(pattern, false, context)) {
|
||||||
// `terms` queries are a disjunction, so one matching term is enough
|
// `terms` queries are a disjunction, so one matching term is enough
|
||||||
return Queries.newMatchAllQuery();
|
return Queries.newMatchAllQuery();
|
||||||
}
|
}
|
||||||
|
@ -92,9 +102,10 @@ public abstract class ConstantFieldType extends MappedFieldType {
|
||||||
@Override
|
@Override
|
||||||
public final Query prefixQuery(String prefix,
|
public final Query prefixQuery(String prefix,
|
||||||
@Nullable MultiTermQuery.RewriteMethod method,
|
@Nullable MultiTermQuery.RewriteMethod method,
|
||||||
|
boolean caseInsensitive,
|
||||||
QueryShardContext context) {
|
QueryShardContext context) {
|
||||||
String pattern = prefix + "*";
|
String pattern = prefix + "*";
|
||||||
if (matches(pattern, context)) {
|
if (matches(pattern, caseInsensitive, context)) {
|
||||||
return Queries.newMatchAllQuery();
|
return Queries.newMatchAllQuery();
|
||||||
} else {
|
} else {
|
||||||
return new MatchNoDocsQuery();
|
return new MatchNoDocsQuery();
|
||||||
|
@ -104,8 +115,9 @@ public abstract class ConstantFieldType extends MappedFieldType {
|
||||||
@Override
|
@Override
|
||||||
public final Query wildcardQuery(String value,
|
public final Query wildcardQuery(String value,
|
||||||
@Nullable MultiTermQuery.RewriteMethod method,
|
@Nullable MultiTermQuery.RewriteMethod method,
|
||||||
|
boolean caseInsensitive,
|
||||||
QueryShardContext context) {
|
QueryShardContext context) {
|
||||||
if (matches(value, context)) {
|
if (matches(value, caseInsensitive, context)) {
|
||||||
return Queries.newMatchAllQuery();
|
return Queries.newMatchAllQuery();
|
||||||
} else {
|
} else {
|
||||||
return new MatchNoDocsQuery();
|
return new MatchNoDocsQuery();
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData;
|
import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData;
|
||||||
import org.elasticsearch.index.query.QueryShardContext;
|
import org.elasticsearch.index.query.QueryShardContext;
|
||||||
|
@ -52,7 +53,12 @@ public class IndexFieldMapper extends MetadataFieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean matches(String pattern, QueryShardContext context) {
|
protected boolean matches(String pattern, boolean caseInsensitive, QueryShardContext context) {
|
||||||
|
if (caseInsensitive) {
|
||||||
|
// Thankfully, all index names are lower-cased so we don't have to pass a case_insensitive mode flag
|
||||||
|
// down to all the index name-matching logic. We just lower-case the search string
|
||||||
|
pattern = Strings.toLowercaseAscii(pattern);
|
||||||
|
}
|
||||||
return context.indexMatches(pattern);
|
return context.indexMatches(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,13 @@ public abstract class MappedFieldType {
|
||||||
// TODO: Standardize exception types
|
// TODO: Standardize exception types
|
||||||
public abstract Query termQuery(Object value, @Nullable QueryShardContext context);
|
public abstract Query termQuery(Object value, @Nullable QueryShardContext context);
|
||||||
|
|
||||||
|
|
||||||
|
// Case insensitive form of term query (not supported by all fields so must be overridden to enable)
|
||||||
|
public Query termQueryCaseInsensitive(Object value, @Nullable QueryShardContext context) {
|
||||||
|
throw new QueryShardException(context, "[" + name + "] field which is of type [" + typeName() +
|
||||||
|
"], does not support case insensitive term queries");
|
||||||
|
}
|
||||||
|
|
||||||
/** Build a constant-scoring query that matches all values. The default implementation uses a
|
/** Build a constant-scoring query that matches all values. The default implementation uses a
|
||||||
* {@link ConstantScoreQuery} around a {@link BooleanQuery} whose {@link Occur#SHOULD} clauses
|
* {@link ConstantScoreQuery} around a {@link BooleanQuery} whose {@link Occur#SHOULD} clauses
|
||||||
* are generated with {@link #termQuery}. */
|
* are generated with {@link #termQuery}. */
|
||||||
|
@ -206,14 +213,27 @@ public abstract class MappedFieldType {
|
||||||
+ "] which is of type [" + typeName() + "]");
|
+ "] which is of type [" + typeName() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Query prefixQuery(String value, @Nullable MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
// Case sensitive form of prefix query
|
||||||
|
public final Query prefixQuery(String value, @Nullable MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
||||||
|
return prefixQuery(value, method, false, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Query prefixQuery(String value, @Nullable MultiTermQuery.RewriteMethod method, boolean caseInsensitve,
|
||||||
|
QueryShardContext context) {
|
||||||
throw new QueryShardException(context, "Can only use prefix queries on keyword, text and wildcard fields - not on [" + name
|
throw new QueryShardException(context, "Can only use prefix queries on keyword, text and wildcard fields - not on [" + name
|
||||||
+ "] which is of type [" + typeName() + "]");
|
+ "] which is of type [" + typeName() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Case sensitive form of wildcard query
|
||||||
|
public final Query wildcardQuery(String value,
|
||||||
|
@Nullable MultiTermQuery.RewriteMethod method, QueryShardContext context
|
||||||
|
) {
|
||||||
|
return wildcardQuery(value, method, false, context);
|
||||||
|
}
|
||||||
|
|
||||||
public Query wildcardQuery(String value,
|
public Query wildcardQuery(String value,
|
||||||
@Nullable MultiTermQuery.RewriteMethod method,
|
@Nullable MultiTermQuery.RewriteMethod method,
|
||||||
QueryShardContext context) {
|
boolean caseInsensitve, QueryShardContext context) {
|
||||||
throw new QueryShardException(context, "Can only use wildcard queries on keyword, text and wildcard fields - not on [" + name
|
throw new QueryShardException(context, "Can only use wildcard queries on keyword, text and wildcard fields - not on [" + name
|
||||||
+ "] which is of type [" + typeName() + "]");
|
+ "] which is of type [" + typeName() + "]");
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
|
import org.apache.lucene.search.AutomatonQuery;
|
||||||
import org.apache.lucene.search.FuzzyQuery;
|
import org.apache.lucene.search.FuzzyQuery;
|
||||||
import org.apache.lucene.search.MultiTermQuery;
|
import org.apache.lucene.search.MultiTermQuery;
|
||||||
import org.apache.lucene.search.PrefixQuery;
|
import org.apache.lucene.search.PrefixQuery;
|
||||||
|
@ -32,6 +33,7 @@ import org.apache.lucene.util.BytesRef;
|
||||||
import org.apache.lucene.util.BytesRefBuilder;
|
import org.apache.lucene.util.BytesRefBuilder;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.common.lucene.BytesRefs;
|
import org.elasticsearch.common.lucene.BytesRefs;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.common.unit.Fuzziness;
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
import org.elasticsearch.index.query.QueryShardContext;
|
import org.elasticsearch.index.query.QueryShardContext;
|
||||||
import org.elasticsearch.index.query.support.QueryParsers;
|
import org.elasticsearch.index.query.support.QueryParsers;
|
||||||
|
@ -68,13 +70,21 @@ public abstract class StringFieldType extends TermBasedFieldType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
if (context.allowExpensiveQueries() == false) {
|
if (context.allowExpensiveQueries() == false) {
|
||||||
throw new ElasticsearchException("[prefix] queries cannot be executed when '" +
|
throw new ElasticsearchException("[prefix] queries cannot be executed when '" +
|
||||||
ALLOW_EXPENSIVE_QUERIES.getKey() + "' is set to false. For optimised prefix queries on text " +
|
ALLOW_EXPENSIVE_QUERIES.getKey() + "' is set to false. For optimised prefix queries on text " +
|
||||||
"fields please enable [index_prefixes].");
|
"fields please enable [index_prefixes].");
|
||||||
}
|
}
|
||||||
failIfNotIndexed();
|
failIfNotIndexed();
|
||||||
|
if (caseInsensitive) {
|
||||||
|
AutomatonQuery query = AutomatonQueries.caseInsensitivePrefixQuery((new Term(name(), indexedValueForSearch(value))));
|
||||||
|
if (method != null) {
|
||||||
|
query.setRewriteMethod(method);
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
|
||||||
|
}
|
||||||
PrefixQuery query = new PrefixQuery(new Term(name(), indexedValueForSearch(value)));
|
PrefixQuery query = new PrefixQuery(new Term(name(), indexedValueForSearch(value)));
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
query.setRewriteMethod(method);
|
query.setRewriteMethod(method);
|
||||||
|
@ -113,7 +123,7 @@ public abstract class StringFieldType extends TermBasedFieldType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query wildcardQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query wildcardQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
failIfNotIndexed();
|
failIfNotIndexed();
|
||||||
if (context.allowExpensiveQueries() == false) {
|
if (context.allowExpensiveQueries() == false) {
|
||||||
throw new ElasticsearchException("[wildcard] queries cannot be executed when '" +
|
throw new ElasticsearchException("[wildcard] queries cannot be executed when '" +
|
||||||
|
@ -127,7 +137,11 @@ public abstract class StringFieldType extends TermBasedFieldType {
|
||||||
} else {
|
} else {
|
||||||
term = new Term(name(), indexedValueForSearch(value));
|
term = new Term(name(), indexedValueForSearch(value));
|
||||||
}
|
}
|
||||||
|
if (caseInsensitive) {
|
||||||
|
AutomatonQuery query = AutomatonQueries.caseInsensitiveWildcardQuery(term);
|
||||||
|
QueryParsers.setRewriteMethod(query, method);
|
||||||
|
return query;
|
||||||
|
}
|
||||||
WildcardQuery query = new WildcardQuery(term);
|
WildcardQuery query = new WildcardQuery(term);
|
||||||
QueryParsers.setRewriteMethod(query, method);
|
QueryParsers.setRewriteMethod(query, method);
|
||||||
return query;
|
return query;
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.apache.lucene.search.TermInSetQuery;
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.common.lucene.BytesRefs;
|
import org.elasticsearch.common.lucene.BytesRefs;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.index.query.QueryShardContext;
|
import org.elasticsearch.index.query.QueryShardContext;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -47,6 +48,16 @@ public abstract class TermBasedFieldType extends SimpleMappedFieldType {
|
||||||
return BytesRefs.toBytesRef(value);
|
return BytesRefs.toBytesRef(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Query termQueryCaseInsensitive(Object value, QueryShardContext context) {
|
||||||
|
failIfNotIndexed();
|
||||||
|
Query query = AutomatonQueries.caseInsensitiveTermQuery(new Term(name(), indexedValueForSearch(value)));
|
||||||
|
if (boost() != 1f) {
|
||||||
|
query = new BoostQuery(query, boost());
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query termQuery(Object value, QueryShardContext context) {
|
public Query termQuery(Object value, QueryShardContext context) {
|
||||||
failIfNotIndexed();
|
failIfNotIndexed();
|
||||||
|
|
|
@ -60,6 +60,7 @@ import org.apache.lucene.util.automaton.Operations;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.collect.Iterators;
|
import org.elasticsearch.common.collect.Iterators;
|
||||||
import org.elasticsearch.common.lucene.Lucene;
|
import org.elasticsearch.common.lucene.Lucene;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
|
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||||
|
@ -439,12 +440,20 @@ public class TextFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
if (value.length() >= minChars) {
|
if (value.length() >= minChars) {
|
||||||
|
if (caseInsensitive) {
|
||||||
|
return super.termQueryCaseInsensitive(value, context);
|
||||||
|
}
|
||||||
return super.termQuery(value, context);
|
return super.termQuery(value, context);
|
||||||
}
|
}
|
||||||
List<Automaton> automata = new ArrayList<>();
|
List<Automaton> automata = new ArrayList<>();
|
||||||
automata.add(Automata.makeString(value));
|
if (caseInsensitive) {
|
||||||
|
automata.add(AutomatonQueries.toCaseInsensitiveString(value, Integer.MAX_VALUE));
|
||||||
|
} else {
|
||||||
|
automata.add(Automata.makeString(value));
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = value.length(); i < minChars; i++) {
|
for (int i = value.length(); i < minChars; i++) {
|
||||||
automata.add(Automata.makeAnyChar());
|
automata.add(Automata.makeAnyChar());
|
||||||
}
|
}
|
||||||
|
@ -636,11 +645,11 @@ public class TextFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
if (prefixFieldType == null || prefixFieldType.accept(value.length()) == false) {
|
if (prefixFieldType == null || prefixFieldType.accept(value.length()) == false) {
|
||||||
return super.prefixQuery(value, method, context);
|
return super.prefixQuery(value, method, caseInsensitive,context);
|
||||||
}
|
}
|
||||||
Query tq = prefixFieldType.prefixQuery(value, method, context);
|
Query tq = prefixFieldType.prefixQuery(value, method, caseInsensitive, context);
|
||||||
if (method == null || method == MultiTermQuery.CONSTANT_SCORE_REWRITE
|
if (method == null || method == MultiTermQuery.CONSTANT_SCORE_REWRITE
|
||||||
|| method == MultiTermQuery.CONSTANT_SCORE_BOOLEAN_REWRITE) {
|
|| method == MultiTermQuery.CONSTANT_SCORE_BOOLEAN_REWRITE) {
|
||||||
return new ConstantScoreQuery(tq);
|
return new ConstantScoreQuery(tq);
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.apache.lucene.index.IndexOptions;
|
||||||
import org.apache.lucene.index.IndexReader;
|
import org.apache.lucene.index.IndexReader;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.index.TermStates;
|
import org.apache.lucene.index.TermStates;
|
||||||
|
import org.apache.lucene.search.AutomatonQuery;
|
||||||
import org.apache.lucene.search.BooleanClause;
|
import org.apache.lucene.search.BooleanClause;
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
import org.apache.lucene.search.ConstantScoreQuery;
|
import org.apache.lucene.search.ConstantScoreQuery;
|
||||||
|
@ -38,6 +39,7 @@ import org.apache.lucene.search.TermQuery;
|
||||||
import org.apache.lucene.search.WildcardQuery;
|
import org.apache.lucene.search.WildcardQuery;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.common.lucene.search.Queries;
|
import org.elasticsearch.common.lucene.search.Queries;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData;
|
import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData;
|
||||||
|
@ -156,7 +158,7 @@ public class TypeFieldMapper extends MetadataFieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query wildcardQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query wildcardQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
Query termQuery = termQuery(value, context);
|
Query termQuery = termQuery(value, context);
|
||||||
if (termQuery instanceof MatchNoDocsQuery || termQuery instanceof MatchAllDocsQuery) {
|
if (termQuery instanceof MatchNoDocsQuery || termQuery instanceof MatchAllDocsQuery) {
|
||||||
return termQuery;
|
return termQuery;
|
||||||
|
@ -168,6 +170,12 @@ public class TypeFieldMapper extends MetadataFieldMapper {
|
||||||
}
|
}
|
||||||
Term term = MappedFieldType.extractTerm(termQuery);
|
Term term = MappedFieldType.extractTerm(termQuery);
|
||||||
|
|
||||||
|
if (caseInsensitive) {
|
||||||
|
AutomatonQuery query = AutomatonQueries.caseInsensitiveWildcardQuery(term);
|
||||||
|
QueryParsers.setRewriteMethod(query, method);
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
WildcardQuery query = new WildcardQuery(term);
|
WildcardQuery query = new WildcardQuery(term);
|
||||||
QueryParsers.setRewriteMethod(query, method);
|
QueryParsers.setRewriteMethod(query, method);
|
||||||
return query;
|
return query;
|
||||||
|
|
|
@ -152,18 +152,23 @@ public abstract class BaseTermQueryBuilder<QB extends BaseTermQueryBuilder<QB>>
|
||||||
builder.startObject(getName());
|
builder.startObject(getName());
|
||||||
builder.startObject(fieldName);
|
builder.startObject(fieldName);
|
||||||
builder.field(VALUE_FIELD.getPreferredName(), maybeConvertToString(this.value));
|
builder.field(VALUE_FIELD.getPreferredName(), maybeConvertToString(this.value));
|
||||||
|
addExtraXContent(builder, params);
|
||||||
printBoostAndQueryName(builder);
|
printBoostAndQueryName(builder);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void addExtraXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
// Do nothing but allows subclasses to override.
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final int doHashCode() {
|
protected int doHashCode() {
|
||||||
return Objects.hash(fieldName, value);
|
return Objects.hash(fieldName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final boolean doEquals(QB other) {
|
protected boolean doEquals(QB other) {
|
||||||
return Objects.equals(fieldName, other.fieldName) &&
|
return Objects.equals(fieldName, other.fieldName) &&
|
||||||
Objects.equals(value, other.value);
|
Objects.equals(value, other.value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.search.MatchAllDocsQuery;
|
||||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||||
import org.apache.lucene.search.MultiTermQuery;
|
import org.apache.lucene.search.MultiTermQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.ParsingException;
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
|
@ -51,6 +52,11 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||||
|
|
||||||
private final String value;
|
private final String value;
|
||||||
|
|
||||||
|
public static final boolean DEFAULT_CASE_INSENSITIVITY = false;
|
||||||
|
private static final ParseField CASE_INSENSITIVE_FIELD = new ParseField("case_insensitive");
|
||||||
|
private boolean caseInsensitive = DEFAULT_CASE_INSENSITIVITY;
|
||||||
|
|
||||||
|
|
||||||
private String rewrite;
|
private String rewrite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,6 +84,9 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||||
fieldName = in.readString();
|
fieldName = in.readString();
|
||||||
value = in.readString();
|
value = in.readString();
|
||||||
rewrite = in.readOptionalString();
|
rewrite = in.readOptionalString();
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_7_10_0)) {
|
||||||
|
caseInsensitive = in.readBoolean();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -85,6 +94,9 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||||
out.writeString(fieldName);
|
out.writeString(fieldName);
|
||||||
out.writeString(value);
|
out.writeString(value);
|
||||||
out.writeOptionalString(rewrite);
|
out.writeOptionalString(rewrite);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_7_10_0)) {
|
||||||
|
out.writeBoolean(caseInsensitive);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -96,6 +108,18 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PrefixQueryBuilder caseInsensitive(boolean caseInsensitive) {
|
||||||
|
if (caseInsensitive == false) {
|
||||||
|
throw new IllegalArgumentException("The case insensitive setting cannot be set to false.");
|
||||||
|
}
|
||||||
|
this.caseInsensitive = caseInsensitive;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean caseInsensitive() {
|
||||||
|
return this.caseInsensitive;
|
||||||
|
}
|
||||||
|
|
||||||
public PrefixQueryBuilder rewrite(String rewrite) {
|
public PrefixQueryBuilder rewrite(String rewrite) {
|
||||||
this.rewrite = rewrite;
|
this.rewrite = rewrite;
|
||||||
return this;
|
return this;
|
||||||
|
@ -113,6 +137,9 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||||
if (rewrite != null) {
|
if (rewrite != null) {
|
||||||
builder.field(REWRITE_FIELD.getPreferredName(), rewrite);
|
builder.field(REWRITE_FIELD.getPreferredName(), rewrite);
|
||||||
}
|
}
|
||||||
|
if (caseInsensitive != DEFAULT_CASE_INSENSITIVITY) {
|
||||||
|
builder.field(CASE_INSENSITIVE_FIELD.getPreferredName(), caseInsensitive);
|
||||||
|
}
|
||||||
printBoostAndQueryName(builder);
|
printBoostAndQueryName(builder);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
@ -125,6 +152,7 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||||
|
|
||||||
String queryName = null;
|
String queryName = null;
|
||||||
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
||||||
|
boolean caseInsensitive = DEFAULT_CASE_INSENSITIVITY;
|
||||||
String currentFieldName = null;
|
String currentFieldName = null;
|
||||||
XContentParser.Token token;
|
XContentParser.Token token;
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
@ -145,6 +173,12 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||||
boost = parser.floatValue();
|
boost = parser.floatValue();
|
||||||
} else if (REWRITE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
} else if (REWRITE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
rewrite = parser.textOrNull();
|
rewrite = parser.textOrNull();
|
||||||
|
} else if (CASE_INSENSITIVE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
|
caseInsensitive = parser.booleanValue();
|
||||||
|
if (caseInsensitive == false) {
|
||||||
|
throw new ParsingException(parser.getTokenLocation(),
|
||||||
|
"[prefix] query does not support [" + currentFieldName + "] = false");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new ParsingException(parser.getTokenLocation(),
|
throw new ParsingException(parser.getTokenLocation(),
|
||||||
"[prefix] query does not support [" + currentFieldName + "]");
|
"[prefix] query does not support [" + currentFieldName + "]");
|
||||||
|
@ -158,10 +192,14 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PrefixQueryBuilder(fieldName, value)
|
PrefixQueryBuilder result = new PrefixQueryBuilder(fieldName, value)
|
||||||
.rewrite(rewrite)
|
.rewrite(rewrite)
|
||||||
.boost(boost)
|
.boost(boost)
|
||||||
.queryName(queryName);
|
.queryName(queryName);
|
||||||
|
if (caseInsensitive) {
|
||||||
|
result.caseInsensitive(caseInsensitive);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -180,7 +218,7 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||||
// This logic is correct for all field types, but by only applying it to constant
|
// This logic is correct for all field types, but by only applying it to constant
|
||||||
// fields we also have the guarantee that it doesn't perform I/O, which is important
|
// fields we also have the guarantee that it doesn't perform I/O, which is important
|
||||||
// since rewrites might happen on a network thread.
|
// since rewrites might happen on a network thread.
|
||||||
Query query = fieldType.prefixQuery(value, null, context); // the rewrite method doesn't matter
|
Query query = fieldType.prefixQuery(value, null, caseInsensitive, context); // the rewrite method doesn't matter
|
||||||
if (query instanceof MatchAllDocsQuery) {
|
if (query instanceof MatchAllDocsQuery) {
|
||||||
return new MatchAllQueryBuilder();
|
return new MatchAllQueryBuilder();
|
||||||
} else if (query instanceof MatchNoDocsQuery) {
|
} else if (query instanceof MatchNoDocsQuery) {
|
||||||
|
@ -202,18 +240,19 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||||
if (fieldType == null) {
|
if (fieldType == null) {
|
||||||
throw new IllegalStateException("Rewrite first");
|
throw new IllegalStateException("Rewrite first");
|
||||||
}
|
}
|
||||||
return fieldType.prefixQuery(value, method, context);
|
return fieldType.prefixQuery(value, method, caseInsensitive, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final int doHashCode() {
|
protected final int doHashCode() {
|
||||||
return Objects.hash(fieldName, value, rewrite);
|
return Objects.hash(fieldName, value, rewrite, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean doEquals(PrefixQueryBuilder other) {
|
protected boolean doEquals(PrefixQueryBuilder other) {
|
||||||
return Objects.equals(fieldName, other.fieldName) &&
|
return Objects.equals(fieldName, other.fieldName) &&
|
||||||
Objects.equals(value, other.value) &&
|
Objects.equals(value, other.value) &&
|
||||||
Objects.equals(rewrite, other.rewrite);
|
Objects.equals(rewrite, other.rewrite) &&
|
||||||
|
Objects.equals(caseInsensitive, other.caseInsensitive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,20 +22,31 @@ package org.elasticsearch.index.query;
|
||||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.ParsingException;
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent.Params;
|
||||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
import org.elasticsearch.index.mapper.ConstantFieldType;
|
import org.elasticsearch.index.mapper.ConstantFieldType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Query that matches documents containing a term.
|
* A Query that matches documents containing a term.
|
||||||
*/
|
*/
|
||||||
public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> {
|
public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> {
|
||||||
public static final String NAME = "term";
|
public static final String NAME = "term";
|
||||||
|
public static final boolean DEFAULT_CASE_INSENSITIVITY = false;
|
||||||
|
private static final ParseField CASE_INSENSITIVE_FIELD = new ParseField("case_insensitive");
|
||||||
|
|
||||||
|
|
||||||
|
private boolean caseInsensitive = DEFAULT_CASE_INSENSITIVITY;
|
||||||
|
|
||||||
|
|
||||||
private static final ParseField TERM_FIELD = new ParseField("term");
|
private static final ParseField TERM_FIELD = new ParseField("term");
|
||||||
private static final ParseField VALUE_FIELD = new ParseField("value");
|
private static final ParseField VALUE_FIELD = new ParseField("value");
|
||||||
|
@ -75,11 +86,34 @@ public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> {
|
||||||
super(fieldName, value);
|
super(fieldName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TermQueryBuilder caseInsensitive(boolean caseInsensitive) {
|
||||||
|
if (caseInsensitive == false) {
|
||||||
|
throw new IllegalArgumentException("The case insensitive setting cannot be set to false.");
|
||||||
|
}
|
||||||
|
this.caseInsensitive = caseInsensitive;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean caseInsensitive() {
|
||||||
|
return this.caseInsensitive;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read from a stream.
|
* Read from a stream.
|
||||||
*/
|
*/
|
||||||
public TermQueryBuilder(StreamInput in) throws IOException {
|
public TermQueryBuilder(StreamInput in) throws IOException {
|
||||||
super(in);
|
super(in);
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_7_10_0)) {
|
||||||
|
caseInsensitive = in.readBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void doWriteTo(StreamOutput out) throws IOException {
|
||||||
|
super.doWriteTo(out);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_7_10_0)) {
|
||||||
|
out.writeBoolean(caseInsensitive);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TermQueryBuilder fromXContent(XContentParser parser) throws IOException {
|
public static TermQueryBuilder fromXContent(XContentParser parser) throws IOException {
|
||||||
|
@ -87,6 +121,7 @@ public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> {
|
||||||
String fieldName = null;
|
String fieldName = null;
|
||||||
Object value = null;
|
Object value = null;
|
||||||
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
||||||
|
boolean caseInsensitive = DEFAULT_CASE_INSENSITIVITY;
|
||||||
String currentFieldName = null;
|
String currentFieldName = null;
|
||||||
XContentParser.Token token;
|
XContentParser.Token token;
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
@ -107,6 +142,12 @@ public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> {
|
||||||
queryName = parser.text();
|
queryName = parser.text();
|
||||||
} else if (AbstractQueryBuilder.BOOST_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
} else if (AbstractQueryBuilder.BOOST_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
boost = parser.floatValue();
|
boost = parser.floatValue();
|
||||||
|
} else if (CASE_INSENSITIVE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
|
caseInsensitive = parser.booleanValue();
|
||||||
|
if (caseInsensitive == false) {
|
||||||
|
throw new ParsingException(parser.getTokenLocation(),
|
||||||
|
"[term] query does not support [" + currentFieldName + "] = false");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new ParsingException(parser.getTokenLocation(),
|
throw new ParsingException(parser.getTokenLocation(),
|
||||||
"[term] query does not support [" + currentFieldName + "]");
|
"[term] query does not support [" + currentFieldName + "]");
|
||||||
|
@ -127,9 +168,19 @@ public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> {
|
||||||
if (queryName != null) {
|
if (queryName != null) {
|
||||||
termQuery.queryName(queryName);
|
termQuery.queryName(queryName);
|
||||||
}
|
}
|
||||||
|
if (caseInsensitive) {
|
||||||
|
termQuery.caseInsensitive(caseInsensitive);
|
||||||
|
}
|
||||||
return termQuery;
|
return termQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addExtraXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
if (caseInsensitive != DEFAULT_CASE_INSENSITIVITY) {
|
||||||
|
builder.field(CASE_INSENSITIVE_FIELD.getPreferredName(), caseInsensitive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException {
|
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException {
|
||||||
QueryShardContext context = queryRewriteContext.convertToShardContext();
|
QueryShardContext context = queryRewriteContext.convertToShardContext();
|
||||||
|
@ -141,7 +192,13 @@ public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> {
|
||||||
// This logic is correct for all field types, but by only applying it to constant
|
// This logic is correct for all field types, but by only applying it to constant
|
||||||
// fields we also have the guarantee that it doesn't perform I/O, which is important
|
// fields we also have the guarantee that it doesn't perform I/O, which is important
|
||||||
// since rewrites might happen on a network thread.
|
// since rewrites might happen on a network thread.
|
||||||
Query query = fieldType.termQuery(value, context);
|
Query query = null;
|
||||||
|
if (caseInsensitive) {
|
||||||
|
query = fieldType.termQueryCaseInsensitive(value, context);
|
||||||
|
} else {
|
||||||
|
query = fieldType.termQuery(value, context);
|
||||||
|
}
|
||||||
|
|
||||||
if (query instanceof MatchAllDocsQuery) {
|
if (query instanceof MatchAllDocsQuery) {
|
||||||
return new MatchAllQueryBuilder();
|
return new MatchAllQueryBuilder();
|
||||||
} else if (query instanceof MatchNoDocsQuery) {
|
} else if (query instanceof MatchNoDocsQuery) {
|
||||||
|
@ -160,11 +217,27 @@ public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> {
|
||||||
if (mapper == null) {
|
if (mapper == null) {
|
||||||
throw new IllegalStateException("Rewrite first");
|
throw new IllegalStateException("Rewrite first");
|
||||||
}
|
}
|
||||||
return mapper.termQuery(this.value, context);
|
if (caseInsensitive) {
|
||||||
|
return mapper.termQueryCaseInsensitive(value, context);
|
||||||
|
}
|
||||||
|
return mapper.termQuery(value, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWriteableName() {
|
public String getWriteableName() {
|
||||||
return NAME;
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final int doHashCode() {
|
||||||
|
return Objects.hash(super.doHashCode(), caseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final boolean doEquals(TermQueryBuilder other) {
|
||||||
|
return super.doEquals(other) &&
|
||||||
|
Objects.equals(caseInsensitive, other.caseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.search.MatchAllDocsQuery;
|
||||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||||
import org.apache.lucene.search.MultiTermQuery;
|
import org.apache.lucene.search.MultiTermQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.ParsingException;
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
|
@ -59,6 +60,10 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||||
|
|
||||||
private String rewrite;
|
private String rewrite;
|
||||||
|
|
||||||
|
public static final boolean DEFAULT_CASE_INSENSITIVITY = false;
|
||||||
|
private static final ParseField CASE_INSENSITIVE_FIELD = new ParseField("case_insensitive");
|
||||||
|
private boolean caseInsensitive = DEFAULT_CASE_INSENSITIVITY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the wildcard search query. Supported wildcards are {@code *}, which
|
* Implements the wildcard search query. Supported wildcards are {@code *}, which
|
||||||
* matches any character sequence (including the empty one), and {@code ?},
|
* matches any character sequence (including the empty one), and {@code ?},
|
||||||
|
@ -89,6 +94,9 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||||
fieldName = in.readString();
|
fieldName = in.readString();
|
||||||
value = in.readString();
|
value = in.readString();
|
||||||
rewrite = in.readOptionalString();
|
rewrite = in.readOptionalString();
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_7_10_0)) {
|
||||||
|
caseInsensitive = in.readBoolean();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -96,6 +104,9 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||||
out.writeString(fieldName);
|
out.writeString(fieldName);
|
||||||
out.writeString(value);
|
out.writeString(value);
|
||||||
out.writeOptionalString(rewrite);
|
out.writeOptionalString(rewrite);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_7_10_0)) {
|
||||||
|
out.writeBoolean(caseInsensitive);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -116,6 +127,18 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||||
return this.rewrite;
|
return this.rewrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WildcardQueryBuilder caseInsensitive(boolean caseInsensitive) {
|
||||||
|
if (caseInsensitive == false) {
|
||||||
|
throw new IllegalArgumentException("The case insensitive setting cannot be set to false.");
|
||||||
|
}
|
||||||
|
this.caseInsensitive = caseInsensitive;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean caseInsensitive() {
|
||||||
|
return this.caseInsensitive;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWriteableName() {
|
public String getWriteableName() {
|
||||||
return NAME;
|
return NAME;
|
||||||
|
@ -129,6 +152,9 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||||
if (rewrite != null) {
|
if (rewrite != null) {
|
||||||
builder.field(REWRITE_FIELD.getPreferredName(), rewrite);
|
builder.field(REWRITE_FIELD.getPreferredName(), rewrite);
|
||||||
}
|
}
|
||||||
|
if (caseInsensitive != DEFAULT_CASE_INSENSITIVITY) {
|
||||||
|
builder.field(CASE_INSENSITIVE_FIELD.getPreferredName(), caseInsensitive);
|
||||||
|
}
|
||||||
printBoostAndQueryName(builder);
|
printBoostAndQueryName(builder);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
@ -139,6 +165,7 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||||
String rewrite = null;
|
String rewrite = null;
|
||||||
String value = null;
|
String value = null;
|
||||||
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
||||||
|
boolean caseInsensitive = DEFAULT_CASE_INSENSITIVITY;
|
||||||
String queryName = null;
|
String queryName = null;
|
||||||
String currentFieldName = null;
|
String currentFieldName = null;
|
||||||
XContentParser.Token token;
|
XContentParser.Token token;
|
||||||
|
@ -160,6 +187,12 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||||
boost = parser.floatValue();
|
boost = parser.floatValue();
|
||||||
} else if (REWRITE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
} else if (REWRITE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
rewrite = parser.textOrNull();
|
rewrite = parser.textOrNull();
|
||||||
|
} else if (CASE_INSENSITIVE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
|
caseInsensitive = parser.booleanValue();
|
||||||
|
if (caseInsensitive == false) {
|
||||||
|
throw new ParsingException(parser.getTokenLocation(),
|
||||||
|
"[prefix] query does not support [" + currentFieldName + "] = false");
|
||||||
|
}
|
||||||
} else if (AbstractQueryBuilder.NAME_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
} else if (AbstractQueryBuilder.NAME_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
queryName = parser.text();
|
queryName = parser.text();
|
||||||
} else {
|
} else {
|
||||||
|
@ -175,10 +208,14 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new WildcardQueryBuilder(fieldName, value)
|
WildcardQueryBuilder result = new WildcardQueryBuilder(fieldName, value)
|
||||||
.rewrite(rewrite)
|
.rewrite(rewrite)
|
||||||
.boost(boost)
|
.boost(boost)
|
||||||
.queryName(queryName);
|
.queryName(queryName);
|
||||||
|
if (caseInsensitive) {
|
||||||
|
result.caseInsensitive(caseInsensitive);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -192,7 +229,7 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||||
// This logic is correct for all field types, but by only applying it to constant
|
// This logic is correct for all field types, but by only applying it to constant
|
||||||
// fields we also have the guarantee that it doesn't perform I/O, which is important
|
// fields we also have the guarantee that it doesn't perform I/O, which is important
|
||||||
// since rewrites might happen on a network thread.
|
// since rewrites might happen on a network thread.
|
||||||
Query query = fieldType.wildcardQuery(value, null, context); // the rewrite method doesn't matter
|
Query query = fieldType.wildcardQuery(value, null, caseInsensitive, context); // the rewrite method doesn't matter
|
||||||
if (query instanceof MatchAllDocsQuery) {
|
if (query instanceof MatchAllDocsQuery) {
|
||||||
return new MatchAllQueryBuilder();
|
return new MatchAllQueryBuilder();
|
||||||
} else if (query instanceof MatchNoDocsQuery) {
|
} else if (query instanceof MatchNoDocsQuery) {
|
||||||
|
@ -216,18 +253,19 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||||
|
|
||||||
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(
|
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(
|
||||||
rewrite, null, LoggingDeprecationHandler.INSTANCE);
|
rewrite, null, LoggingDeprecationHandler.INSTANCE);
|
||||||
return fieldType.wildcardQuery(value, method, context);
|
return fieldType.wildcardQuery(value, method, caseInsensitive, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int doHashCode() {
|
protected int doHashCode() {
|
||||||
return Objects.hash(fieldName, value, rewrite);
|
return Objects.hash(fieldName, value, rewrite, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean doEquals(WildcardQueryBuilder other) {
|
protected boolean doEquals(WildcardQueryBuilder other) {
|
||||||
return Objects.equals(fieldName, other.fieldName) &&
|
return Objects.equals(fieldName, other.fieldName) &&
|
||||||
Objects.equals(value, other.value) &&
|
Objects.equals(value, other.value) &&
|
||||||
Objects.equals(rewrite, other.rewrite);
|
Objects.equals(rewrite, other.rewrite)&&
|
||||||
|
Objects.equals(caseInsensitive, other.caseInsensitive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.elasticsearch.common.regex;
|
||||||
|
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -54,13 +55,17 @@ public class RegexTests extends ESTestCase {
|
||||||
|
|
||||||
public void testDoubleWildcardMatch() {
|
public void testDoubleWildcardMatch() {
|
||||||
assertTrue(Regex.simpleMatch("ddd", "ddd"));
|
assertTrue(Regex.simpleMatch("ddd", "ddd"));
|
||||||
|
assertTrue(Regex.simpleMatch("ddd", "Ddd", true));
|
||||||
|
assertFalse(Regex.simpleMatch("ddd", "Ddd"));
|
||||||
assertTrue(Regex.simpleMatch("d*d*d", "dadd"));
|
assertTrue(Regex.simpleMatch("d*d*d", "dadd"));
|
||||||
assertTrue(Regex.simpleMatch("**ddd", "dddd"));
|
assertTrue(Regex.simpleMatch("**ddd", "dddd"));
|
||||||
|
assertTrue(Regex.simpleMatch("**ddD", "dddd", true));
|
||||||
assertFalse(Regex.simpleMatch("**ddd", "fff"));
|
assertFalse(Regex.simpleMatch("**ddd", "fff"));
|
||||||
assertTrue(Regex.simpleMatch("fff*ddd", "fffabcddd"));
|
assertTrue(Regex.simpleMatch("fff*ddd", "fffabcddd"));
|
||||||
assertTrue(Regex.simpleMatch("fff**ddd", "fffabcddd"));
|
assertTrue(Regex.simpleMatch("fff**ddd", "fffabcddd"));
|
||||||
assertFalse(Regex.simpleMatch("fff**ddd", "fffabcdd"));
|
assertFalse(Regex.simpleMatch("fff**ddd", "fffabcdd"));
|
||||||
assertTrue(Regex.simpleMatch("fff*******ddd", "fffabcddd"));
|
assertTrue(Regex.simpleMatch("fff*******ddd", "fffabcddd"));
|
||||||
|
assertTrue(Regex.simpleMatch("fff*******ddd", "FffAbcdDd", true));
|
||||||
assertFalse(Regex.simpleMatch("fff******ddd", "fffabcdd"));
|
assertFalse(Regex.simpleMatch("fff******ddd", "fffabcdd"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +81,8 @@ public class RegexTests extends ESTestCase {
|
||||||
pattern = pattern.substring(0, shrinkStart) + "*" + pattern.substring(shrinkEnd);
|
pattern = pattern.substring(0, shrinkStart) + "*" + pattern.substring(shrinkEnd);
|
||||||
}
|
}
|
||||||
assertTrue("[" + pattern + "] should match [" + matchingString + "]", Regex.simpleMatch(pattern, matchingString));
|
assertTrue("[" + pattern + "] should match [" + matchingString + "]", Regex.simpleMatch(pattern, matchingString));
|
||||||
|
assertTrue("[" + pattern + "] should match [" + matchingString.toUpperCase(Locale.ROOT) + "]",
|
||||||
|
Regex.simpleMatch(pattern, matchingString.toUpperCase(Locale.ROOT), true));
|
||||||
|
|
||||||
// construct a pattern that does not match this string by inserting a non-matching character (a digit)
|
// construct a pattern that does not match this string by inserting a non-matching character (a digit)
|
||||||
final int insertPos = between(0, pattern.length());
|
final int insertPos = between(0, pattern.length());
|
||||||
|
|
|
@ -46,7 +46,9 @@ public class IndexFieldTypeTests extends ESTestCase {
|
||||||
MappedFieldType ft = IndexFieldMapper.IndexFieldType.INSTANCE;
|
MappedFieldType ft = IndexFieldMapper.IndexFieldType.INSTANCE;
|
||||||
|
|
||||||
assertEquals(new MatchAllDocsQuery(), ft.wildcardQuery("ind*x", null, createContext()));
|
assertEquals(new MatchAllDocsQuery(), ft.wildcardQuery("ind*x", null, createContext()));
|
||||||
|
assertEquals(new MatchAllDocsQuery(), ft.wildcardQuery("iNd*x", null, true, createContext()));
|
||||||
assertEquals(new MatchNoDocsQuery(), ft.wildcardQuery("other_ind*x", null, createContext()));
|
assertEquals(new MatchNoDocsQuery(), ft.wildcardQuery("other_ind*x", null, createContext()));
|
||||||
|
assertEquals(new MatchNoDocsQuery(), ft.wildcardQuery("Other_ind*x", null, true, createContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRegexpQuery() {
|
public void testRegexpQuery() {
|
||||||
|
|
|
@ -42,6 +42,7 @@ import org.elasticsearch.index.IndexSettings;
|
||||||
import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType;
|
import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType;
|
||||||
import org.elasticsearch.index.mapper.RangeFieldMapper.RangeFieldType;
|
import org.elasticsearch.index.mapper.RangeFieldMapper.RangeFieldType;
|
||||||
import org.elasticsearch.index.query.QueryShardContext;
|
import org.elasticsearch.index.query.QueryShardContext;
|
||||||
|
import org.elasticsearch.index.query.QueryShardException;
|
||||||
import org.elasticsearch.test.IndexSettingsModule;
|
import org.elasticsearch.test.IndexSettingsModule;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -480,4 +481,14 @@ public class RangeFieldTypeTests extends FieldTypeTestCase {
|
||||||
assertEquals(getExpectedRangeQuery(relation, value, value, includeLower, includeUpper),
|
assertEquals(getExpectedRangeQuery(relation, value, value, includeLower, includeUpper),
|
||||||
ft.termQuery(value, context));
|
ft.termQuery(value, context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testCaseInsensitiveQuery() throws Exception {
|
||||||
|
QueryShardContext context = createContext();
|
||||||
|
RangeFieldType ft = createDefaultFieldType();
|
||||||
|
|
||||||
|
Object value = nextFrom();
|
||||||
|
QueryShardException ex = expectThrows(QueryShardException.class,
|
||||||
|
() -> ft.termQueryCaseInsensitive(value, context));
|
||||||
|
assertTrue(ex.getMessage().contains("does not support case insensitive term queries"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.apache.lucene.util.automaton.Automaton;
|
||||||
import org.apache.lucene.util.automaton.Operations;
|
import org.apache.lucene.util.automaton.Operations;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.common.lucene.BytesRefs;
|
import org.elasticsearch.common.lucene.BytesRefs;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.common.unit.Fuzziness;
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
import org.elasticsearch.index.mapper.TextFieldMapper.TextFieldType;
|
import org.elasticsearch.index.mapper.TextFieldMapper.TextFieldType;
|
||||||
|
|
||||||
|
@ -63,6 +64,7 @@ public class TextFieldTypeTests extends FieldTypeTestCase {
|
||||||
public void testTermQuery() {
|
public void testTermQuery() {
|
||||||
MappedFieldType ft = createFieldType();
|
MappedFieldType ft = createFieldType();
|
||||||
assertEquals(new TermQuery(new Term("field", "foo")), ft.termQuery("foo", null));
|
assertEquals(new TermQuery(new Term("field", "foo")), ft.termQuery("foo", null));
|
||||||
|
assertEquals(AutomatonQueries.caseInsensitiveTermQuery(new Term("field", "fOo")), ft.termQueryCaseInsensitive("fOo", null));
|
||||||
|
|
||||||
MappedFieldType unsearchable = new TextFieldType("field", false, Collections.emptyMap());
|
MappedFieldType unsearchable = new TextFieldType("field", false, Collections.emptyMap());
|
||||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||||
|
@ -132,18 +134,22 @@ public class TextFieldTypeTests extends FieldTypeTestCase {
|
||||||
TextFieldType ft = createFieldType();
|
TextFieldType ft = createFieldType();
|
||||||
ft.setPrefixFieldType(new TextFieldMapper.PrefixFieldType(ft, "field._index_prefix", 2, 10, true));
|
ft.setPrefixFieldType(new TextFieldMapper.PrefixFieldType(ft, "field._index_prefix", 2, 10, true));
|
||||||
|
|
||||||
Query q = ft.prefixQuery("goin", CONSTANT_SCORE_REWRITE, randomMockShardContext());
|
Query q = ft.prefixQuery("goin", CONSTANT_SCORE_REWRITE, false, randomMockShardContext());
|
||||||
assertEquals(new ConstantScoreQuery(new TermQuery(new Term("field._index_prefix", "goin"))), q);
|
assertEquals(new ConstantScoreQuery(new TermQuery(new Term("field._index_prefix", "goin"))), q);
|
||||||
|
|
||||||
q = ft.prefixQuery("internationalisatio", CONSTANT_SCORE_REWRITE, MOCK_QSC);
|
q = ft.prefixQuery("internationalisatio", CONSTANT_SCORE_REWRITE, false, MOCK_QSC);
|
||||||
assertEquals(new PrefixQuery(new Term("field", "internationalisatio")), q);
|
assertEquals(new PrefixQuery(new Term("field", "internationalisatio")), q);
|
||||||
|
|
||||||
|
q = ft.prefixQuery("Internationalisatio", CONSTANT_SCORE_REWRITE, true, MOCK_QSC);
|
||||||
|
assertEquals(AutomatonQueries.caseInsensitivePrefixQuery(new Term("field", "Internationalisatio")), q);
|
||||||
|
|
||||||
|
|
||||||
ElasticsearchException ee = expectThrows(ElasticsearchException.class,
|
ElasticsearchException ee = expectThrows(ElasticsearchException.class,
|
||||||
() -> ft.prefixQuery("internationalisatio", null, MOCK_QSC_DISALLOW_EXPENSIVE));
|
() -> ft.prefixQuery("internationalisatio", null, false, MOCK_QSC_DISALLOW_EXPENSIVE));
|
||||||
assertEquals("[prefix] queries cannot be executed when 'search.allow_expensive_queries' is set to false. " +
|
assertEquals("[prefix] queries cannot be executed when 'search.allow_expensive_queries' is set to false. " +
|
||||||
"For optimised prefix queries on text fields please enable [index_prefixes].", ee.getMessage());
|
"For optimised prefix queries on text fields please enable [index_prefixes].", ee.getMessage());
|
||||||
|
|
||||||
q = ft.prefixQuery("g", CONSTANT_SCORE_REWRITE, randomMockShardContext());
|
q = ft.prefixQuery("g", CONSTANT_SCORE_REWRITE, false, randomMockShardContext());
|
||||||
Automaton automaton
|
Automaton automaton
|
||||||
= Operations.concatenate(Arrays.asList(Automata.makeChar('g'), Automata.makeAnyChar()));
|
= Operations.concatenate(Arrays.asList(Automata.makeChar('g'), Automata.makeAnyChar()));
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,14 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.index.mapper;
|
package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
||||||
import org.elasticsearch.common.UUIDs;
|
import org.elasticsearch.common.UUIDs;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.common.lucene.search.Queries;
|
import org.elasticsearch.common.lucene.search.Queries;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.index.IndexSettings;
|
import org.elasticsearch.index.IndexSettings;
|
||||||
|
@ -61,6 +63,9 @@ public class TypeFieldTypeTests extends ESTestCase {
|
||||||
query = ft.termQuery("my_type", context);
|
query = ft.termQuery("my_type", context);
|
||||||
assertEquals(new MatchAllDocsQuery(), query);
|
assertEquals(new MatchAllDocsQuery(), query);
|
||||||
|
|
||||||
|
query = ft.termQueryCaseInsensitive("my_Type", context);
|
||||||
|
assertEquals(AutomatonQueries.caseInsensitiveTermQuery(new Term("_type", "my_Type")), query);
|
||||||
|
|
||||||
Mockito.when(mapperService.hasNested()).thenReturn(true);
|
Mockito.when(mapperService.hasNested()).thenReturn(true);
|
||||||
query = ft.termQuery("my_type", context);
|
query = ft.termQuery("my_type", context);
|
||||||
assertEquals(Queries.newNonNestedFilter(context.indexVersionCreated()), query);
|
assertEquals(Queries.newNonNestedFilter(context.indexVersionCreated()), query);
|
||||||
|
@ -70,5 +75,9 @@ public class TypeFieldTypeTests extends ESTestCase {
|
||||||
Mockito.when(mapperService.documentMapper()).thenReturn(mapper);
|
Mockito.when(mapperService.documentMapper()).thenReturn(mapper);
|
||||||
query = ft.termQuery("my_type", context);
|
query = ft.termQuery("my_type", context);
|
||||||
assertEquals(new MatchNoDocsQuery(), query);
|
assertEquals(new MatchNoDocsQuery(), query);
|
||||||
|
|
||||||
|
query = ft.termQueryCaseInsensitive("other_Type", context);
|
||||||
|
assertEquals(AutomatonQueries.caseInsensitiveTermQuery(new Term("_type", "other_Type")), query);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,8 @@ public class PrefixQueryBuilderTests extends AbstractQueryTestCase<PrefixQueryBu
|
||||||
|
|
||||||
public void testFromJson() throws IOException {
|
public void testFromJson() throws IOException {
|
||||||
String json =
|
String json =
|
||||||
"{ \"prefix\" : { \"user\" : { \"value\" : \"ki\", \"boost\" : 2.0 } }}";
|
"{ \"prefix\" : { \"user\" : { \"value\" : \"ki\", \"boost\" : 2.0"
|
||||||
|
+ "} }}";
|
||||||
|
|
||||||
PrefixQueryBuilder parsed = (PrefixQueryBuilder) parseQuery(json);
|
PrefixQueryBuilder parsed = (PrefixQueryBuilder) parseQuery(json);
|
||||||
checkGeneratedJson(json, parsed);
|
checkGeneratedJson(json, parsed);
|
||||||
|
|
|
@ -22,6 +22,7 @@ package org.elasticsearch.index.query;
|
||||||
import com.fasterxml.jackson.core.io.JsonStringEncoder;
|
import com.fasterxml.jackson.core.io.JsonStringEncoder;
|
||||||
|
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
|
import org.apache.lucene.search.AutomatonQuery;
|
||||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||||
import org.apache.lucene.search.PointRangeQuery;
|
import org.apache.lucene.search.PointRangeQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
|
@ -87,12 +88,14 @@ public class TermQueryBuilderTests extends AbstractTermQueryTestCase<TermQueryBu
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected TermQueryBuilder createQueryBuilder(String fieldName, Object value) {
|
protected TermQueryBuilder createQueryBuilder(String fieldName, Object value) {
|
||||||
return new TermQueryBuilder(fieldName, value);
|
TermQueryBuilder result = new TermQueryBuilder(fieldName, value);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doAssertLuceneQuery(TermQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
protected void doAssertLuceneQuery(TermQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
||||||
assertThat(query, either(instanceOf(TermQuery.class)).or(instanceOf(PointRangeQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
|
assertThat(query, either(instanceOf(TermQuery.class)).or(instanceOf(PointRangeQuery.class)).or(instanceOf(MatchNoDocsQuery.class))
|
||||||
|
.or(instanceOf(AutomatonQuery.class)));
|
||||||
MappedFieldType mapper = context.fieldMapper(queryBuilder.fieldName());
|
MappedFieldType mapper = context.fieldMapper(queryBuilder.fieldName());
|
||||||
if (query instanceof TermQuery) {
|
if (query instanceof TermQuery) {
|
||||||
TermQuery termQuery = (TermQuery) query;
|
TermQuery termQuery = (TermQuery) query;
|
||||||
|
@ -100,15 +103,22 @@ public class TermQueryBuilderTests extends AbstractTermQueryTestCase<TermQueryBu
|
||||||
String expectedFieldName = expectedFieldName(queryBuilder.fieldName());
|
String expectedFieldName = expectedFieldName(queryBuilder.fieldName());
|
||||||
assertThat(termQuery.getTerm().field(), equalTo(expectedFieldName));
|
assertThat(termQuery.getTerm().field(), equalTo(expectedFieldName));
|
||||||
|
|
||||||
Term term = ((TermQuery) mapper.termQuery(queryBuilder.value(), null)).getTerm();
|
Term term = ((TermQuery) termQuery(mapper, queryBuilder.value(), queryBuilder.caseInsensitive())).getTerm();
|
||||||
assertThat(termQuery.getTerm(), equalTo(term));
|
assertThat(termQuery.getTerm(), equalTo(term));
|
||||||
} else if (mapper != null) {
|
} else if (mapper != null) {
|
||||||
assertEquals(query, mapper.termQuery(queryBuilder.value(), null));
|
assertEquals(query, termQuery(mapper, queryBuilder.value(), queryBuilder.caseInsensitive()));
|
||||||
} else {
|
} else {
|
||||||
assertThat(query, instanceOf(MatchNoDocsQuery.class));
|
assertThat(query, instanceOf(MatchNoDocsQuery.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Query termQuery(MappedFieldType mapper, Object value, boolean caseInsensitive) {
|
||||||
|
if (caseInsensitive) {
|
||||||
|
return mapper.termQueryCaseInsensitive(value, null);
|
||||||
|
}
|
||||||
|
return mapper.termQuery(value, null);
|
||||||
|
}
|
||||||
|
|
||||||
public void testTermArray() throws IOException {
|
public void testTermArray() throws IOException {
|
||||||
String queryAsString = "{\n" +
|
String queryAsString = "{\n" +
|
||||||
" \"term\": {\n" +
|
" \"term\": {\n" +
|
||||||
|
|
|
@ -103,7 +103,8 @@ public class WildcardQueryBuilderTests extends AbstractQueryTestCase<WildcardQue
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFromJson() throws IOException {
|
public void testFromJson() throws IOException {
|
||||||
String json = "{ \"wildcard\" : { \"user\" : { \"wildcard\" : \"ki*y\", \"boost\" : 2.0 } }}";
|
String json = "{ \"wildcard\" : { \"user\" : { \"wildcard\" : \"ki*y\", \"boost\" : 2.0"
|
||||||
|
+ " } }}";
|
||||||
WildcardQueryBuilder parsed = (WildcardQueryBuilder) parseQuery(json);
|
WildcardQueryBuilder parsed = (WildcardQueryBuilder) parseQuery(json);
|
||||||
checkGeneratedJson(json, parsed);
|
checkGeneratedJson(json, parsed);
|
||||||
assertEquals(json, "ki*y", parsed.value());
|
assertEquals(json, "ki*y", parsed.value());
|
||||||
|
|
|
@ -132,11 +132,11 @@ public class ConstantKeywordFieldMapper extends ParametrizedFieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean matches(String pattern, QueryShardContext context) {
|
protected boolean matches(String pattern, boolean caseInsensitive, QueryShardContext context) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Regex.simpleMatch(pattern, value);
|
return Regex.simpleMatch(pattern, value, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,9 +21,12 @@ public class ConstantKeywordFieldTypeTests extends FieldTypeTestCase {
|
||||||
public void testTermQuery() {
|
public void testTermQuery() {
|
||||||
ConstantKeywordFieldType ft = new ConstantKeywordFieldType("f", "foo");
|
ConstantKeywordFieldType ft = new ConstantKeywordFieldType("f", "foo");
|
||||||
assertEquals(new MatchAllDocsQuery(), ft.termQuery("foo", null));
|
assertEquals(new MatchAllDocsQuery(), ft.termQuery("foo", null));
|
||||||
|
assertEquals(new MatchAllDocsQuery(), ft.termQueryCaseInsensitive("fOo", null));
|
||||||
assertEquals(new MatchNoDocsQuery(), ft.termQuery("bar", null));
|
assertEquals(new MatchNoDocsQuery(), ft.termQuery("bar", null));
|
||||||
|
assertEquals(new MatchNoDocsQuery(), ft.termQueryCaseInsensitive("bAr", null));
|
||||||
ConstantKeywordFieldType bar = new ConstantKeywordFieldType("f", "bar");
|
ConstantKeywordFieldType bar = new ConstantKeywordFieldType("f", "bar");
|
||||||
assertEquals(new MatchNoDocsQuery(), bar.termQuery("foo", null));
|
assertEquals(new MatchNoDocsQuery(), bar.termQuery("foo", null));
|
||||||
|
assertEquals(new MatchNoDocsQuery(), bar.termQueryCaseInsensitive("fOo", null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testTermsQuery() {
|
public void testTermsQuery() {
|
||||||
|
@ -39,18 +42,24 @@ public class ConstantKeywordFieldTypeTests extends FieldTypeTestCase {
|
||||||
|
|
||||||
public void testWildcardQuery() {
|
public void testWildcardQuery() {
|
||||||
ConstantKeywordFieldType bar = new ConstantKeywordFieldType("f", "bar");
|
ConstantKeywordFieldType bar = new ConstantKeywordFieldType("f", "bar");
|
||||||
assertEquals(new MatchNoDocsQuery(), bar.wildcardQuery("f*o", null, null));
|
assertEquals(new MatchNoDocsQuery(), bar.wildcardQuery("f*o", null, false, null));
|
||||||
|
assertEquals(new MatchNoDocsQuery(), bar.wildcardQuery("F*o", null, true, null));
|
||||||
ConstantKeywordFieldType ft = new ConstantKeywordFieldType("f", "foo");
|
ConstantKeywordFieldType ft = new ConstantKeywordFieldType("f", "foo");
|
||||||
assertEquals(new MatchAllDocsQuery(), ft.wildcardQuery("f*o", null, null));
|
assertEquals(new MatchAllDocsQuery(), ft.wildcardQuery("f*o", null, false, null));
|
||||||
assertEquals(new MatchNoDocsQuery(), ft.wildcardQuery("b*r", null, null));
|
assertEquals(new MatchAllDocsQuery(), ft.wildcardQuery("F*o", null, true, null));
|
||||||
|
assertEquals(new MatchNoDocsQuery(), ft.wildcardQuery("b*r", null, false, null));
|
||||||
|
assertEquals(new MatchNoDocsQuery(), ft.wildcardQuery("B*r", null, true, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrefixQuery() {
|
public void testPrefixQuery() {
|
||||||
ConstantKeywordFieldType bar = new ConstantKeywordFieldType("f", "bar");
|
ConstantKeywordFieldType bar = new ConstantKeywordFieldType("f", "bar");
|
||||||
assertEquals(new MatchNoDocsQuery(), bar.prefixQuery("fo", null, null));
|
assertEquals(new MatchNoDocsQuery(), bar.prefixQuery("fo", null, false, null));
|
||||||
|
assertEquals(new MatchNoDocsQuery(), bar.prefixQuery("fO", null, true, null));
|
||||||
ConstantKeywordFieldType ft = new ConstantKeywordFieldType("f", "foo");
|
ConstantKeywordFieldType ft = new ConstantKeywordFieldType("f", "foo");
|
||||||
assertEquals(new MatchAllDocsQuery(), ft.prefixQuery("fo", null, null));
|
assertEquals(new MatchAllDocsQuery(), ft.prefixQuery("fo", null, false, null));
|
||||||
assertEquals(new MatchNoDocsQuery(), ft.prefixQuery("ba", null, null));
|
assertEquals(new MatchAllDocsQuery(), ft.prefixQuery("fO", null, true, null));
|
||||||
|
assertEquals(new MatchNoDocsQuery(), ft.prefixQuery("ba", null, false, null));
|
||||||
|
assertEquals(new MatchNoDocsQuery(), ft.prefixQuery("Ba", null, true, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testExistsQuery() {
|
public void testExistsQuery() {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.apache.lucene.index.IndexOptions;
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.index.OrdinalMap;
|
import org.apache.lucene.index.OrdinalMap;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
|
import org.apache.lucene.search.BoostQuery;
|
||||||
import org.apache.lucene.search.DocValuesFieldExistsQuery;
|
import org.apache.lucene.search.DocValuesFieldExistsQuery;
|
||||||
import org.apache.lucene.search.MultiTermQuery;
|
import org.apache.lucene.search.MultiTermQuery;
|
||||||
import org.apache.lucene.search.PrefixQuery;
|
import org.apache.lucene.search.PrefixQuery;
|
||||||
|
@ -20,6 +21,7 @@ import org.apache.lucene.search.SortField;
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.common.lucene.Lucene;
|
import org.elasticsearch.common.lucene.Lucene;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.common.unit.Fuzziness;
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
import org.elasticsearch.common.util.BigArrays;
|
import org.elasticsearch.common.util.BigArrays;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
@ -292,11 +294,23 @@ public final class FlatObjectFieldMapper extends DynamicKeyFieldMapper {
|
||||||
@Override
|
@Override
|
||||||
public Query wildcardQuery(String value,
|
public Query wildcardQuery(String value,
|
||||||
MultiTermQuery.RewriteMethod method,
|
MultiTermQuery.RewriteMethod method,
|
||||||
|
boolean caseInsensitive,
|
||||||
QueryShardContext context) {
|
QueryShardContext context) {
|
||||||
throw new UnsupportedOperationException("[wildcard] queries are not currently supported on keyed " +
|
throw new UnsupportedOperationException("[wildcard] queries are not currently supported on keyed " +
|
||||||
"[" + CONTENT_TYPE + "] fields.");
|
"[" + CONTENT_TYPE + "] fields.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Query termQueryCaseInsensitive(Object value, QueryShardContext context) {
|
||||||
|
Query query = AutomatonQueries.caseInsensitiveTermQuery(new Term(name(), indexedValueForSearch(value)));
|
||||||
|
if (boost() != 1f) {
|
||||||
|
query = new BoostQuery(query, boost());
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BytesRef indexedValueForSearch(Object value) {
|
public BytesRef indexedValueForSearch(Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.apache.lucene.search.TermQuery;
|
||||||
import org.apache.lucene.search.TermRangeQuery;
|
import org.apache.lucene.search.TermRangeQuery;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.common.unit.Fuzziness;
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
import org.elasticsearch.index.mapper.FieldTypeTestCase;
|
import org.elasticsearch.index.mapper.FieldTypeTestCase;
|
||||||
import org.elasticsearch.xpack.flattened.mapper.FlatObjectFieldMapper.KeyedFlatObjectFieldType;
|
import org.elasticsearch.xpack.flattened.mapper.FlatObjectFieldMapper.KeyedFlatObjectFieldType;
|
||||||
|
@ -48,6 +49,11 @@ public class KeyedFlatObjectFieldTypeTests extends FieldTypeTestCase {
|
||||||
Query expected = new TermQuery(new Term("field", "key\0value"));
|
Query expected = new TermQuery(new Term("field", "key\0value"));
|
||||||
assertEquals(expected, ft.termQuery("value", null));
|
assertEquals(expected, ft.termQuery("value", null));
|
||||||
|
|
||||||
|
expected = AutomatonQueries.caseInsensitiveTermQuery(new Term("field", "key\0value"));
|
||||||
|
assertEquals(expected, ft.termQueryCaseInsensitive("value", null));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
KeyedFlatObjectFieldType unsearchable = new KeyedFlatObjectFieldType("field", false, true, "key",
|
KeyedFlatObjectFieldType unsearchable = new KeyedFlatObjectFieldType("field", false, true, "key",
|
||||||
false, Collections.emptyMap());
|
false, Collections.emptyMap());
|
||||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||||
|
@ -81,10 +87,14 @@ public class KeyedFlatObjectFieldTypeTests extends FieldTypeTestCase {
|
||||||
KeyedFlatObjectFieldType ft = createFieldType();
|
KeyedFlatObjectFieldType ft = createFieldType();
|
||||||
|
|
||||||
Query expected = new PrefixQuery(new Term("field", "key\0val"));
|
Query expected = new PrefixQuery(new Term("field", "key\0val"));
|
||||||
assertEquals(expected, ft.prefixQuery("val", MultiTermQuery.CONSTANT_SCORE_REWRITE, MOCK_QSC));
|
assertEquals(expected, ft.prefixQuery("val", MultiTermQuery.CONSTANT_SCORE_REWRITE, false, MOCK_QSC));
|
||||||
|
|
||||||
|
expected = AutomatonQueries.caseInsensitivePrefixQuery(new Term("field", "key\0vAl"));
|
||||||
|
assertEquals(expected, ft.prefixQuery("vAl", MultiTermQuery.CONSTANT_SCORE_REWRITE, true, MOCK_QSC));
|
||||||
|
|
||||||
|
|
||||||
ElasticsearchException ee = expectThrows(ElasticsearchException.class,
|
ElasticsearchException ee = expectThrows(ElasticsearchException.class,
|
||||||
() -> ft.prefixQuery("val", MultiTermQuery.CONSTANT_SCORE_REWRITE, MOCK_QSC_DISALLOW_EXPENSIVE));
|
() -> ft.prefixQuery("val", MultiTermQuery.CONSTANT_SCORE_REWRITE, false, MOCK_QSC_DISALLOW_EXPENSIVE));
|
||||||
assertEquals("[prefix] queries cannot be executed when 'search.allow_expensive_queries' is set to false. " +
|
assertEquals("[prefix] queries cannot be executed when 'search.allow_expensive_queries' is set to false. " +
|
||||||
"For optimised prefix queries on text fields please enable [index_prefixes].", ee.getMessage());
|
"For optimised prefix queries on text fields please enable [index_prefixes].", ee.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -138,7 +148,7 @@ public class KeyedFlatObjectFieldTypeTests extends FieldTypeTestCase {
|
||||||
KeyedFlatObjectFieldType ft = createFieldType();
|
KeyedFlatObjectFieldType ft = createFieldType();
|
||||||
|
|
||||||
UnsupportedOperationException e = expectThrows(UnsupportedOperationException.class,
|
UnsupportedOperationException e = expectThrows(UnsupportedOperationException.class,
|
||||||
() -> ft.wildcardQuery("valu*", null, randomMockShardContext()));
|
() -> ft.wildcardQuery("valu*", null, false, randomMockShardContext()));
|
||||||
assertEquals("[wildcard] queries are not currently supported on keyed [flattened] fields.", e.getMessage());
|
assertEquals("[wildcard] queries are not currently supported on keyed [flattened] fields.", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import org.apache.lucene.search.TermRangeQuery;
|
||||||
import org.apache.lucene.search.WildcardQuery;
|
import org.apache.lucene.search.WildcardQuery;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.common.unit.Fuzziness;
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
|
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.FieldTypeTestCase;
|
import org.elasticsearch.index.mapper.FieldTypeTestCase;
|
||||||
|
@ -43,6 +44,10 @@ public class RootFlatObjectFieldTypeTests extends FieldTypeTestCase {
|
||||||
Query expected = new TermQuery(new Term("field", "value"));
|
Query expected = new TermQuery(new Term("field", "value"));
|
||||||
assertEquals(expected, ft.termQuery("value", null));
|
assertEquals(expected, ft.termQuery("value", null));
|
||||||
|
|
||||||
|
expected = AutomatonQueries.caseInsensitiveTermQuery(new Term("field", "Value"));
|
||||||
|
assertEquals(expected, ft.termQueryCaseInsensitive("Value", null));
|
||||||
|
|
||||||
|
|
||||||
RootFlatObjectFieldType unsearchable = new RootFlatObjectFieldType("field", false, true,
|
RootFlatObjectFieldType unsearchable = new RootFlatObjectFieldType("field", false, true,
|
||||||
Collections.emptyMap(), false);
|
Collections.emptyMap(), false);
|
||||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||||
|
|
|
@ -133,12 +133,12 @@ abstract class AbstractScriptMappedFieldType<LeafFactory> extends MappedFieldTyp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
throw new IllegalArgumentException(unsupported("prefix", "keyword, text and wildcard"));
|
throw new IllegalArgumentException(unsupported("prefix", "keyword, text and wildcard"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query wildcardQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query wildcardQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
throw new IllegalArgumentException(unsupported("wildcard", "keyword, text and wildcard"));
|
throw new IllegalArgumentException(unsupported("wildcard", "keyword, text and wildcard"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.apache.lucene.search.MatchNoDocsQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.common.Booleans;
|
import org.elasticsearch.common.Booleans;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.lucene.search.Queries;
|
import org.elasticsearch.common.lucene.search.Queries;
|
||||||
import org.elasticsearch.common.time.DateMathParser;
|
import org.elasticsearch.common.time.DateMathParser;
|
||||||
import org.elasticsearch.index.mapper.BooleanFieldMapper;
|
import org.elasticsearch.index.mapper.BooleanFieldMapper;
|
||||||
|
@ -138,10 +139,16 @@ public class BooleanScriptMappedFieldType extends AbstractScriptMappedFieldType<
|
||||||
return termsQuery(trueAllowed, falseAllowed, context);
|
return termsQuery(trueAllowed, falseAllowed, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Query termQueryCaseInsensitive(Object value, QueryShardContext context) {
|
||||||
|
checkAllowExpensiveQueries(context);
|
||||||
|
return new BooleanScriptFieldTermQuery(script, leafFactory(context.lookup()), name(), toBoolean(value, true));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query termQuery(Object value, QueryShardContext context) {
|
public Query termQuery(Object value, QueryShardContext context) {
|
||||||
checkAllowExpensiveQueries(context);
|
checkAllowExpensiveQueries(context);
|
||||||
return new BooleanScriptFieldTermQuery(script, leafFactory(context), name(), toBoolean(value));
|
return new BooleanScriptFieldTermQuery(script, leafFactory(context), name(), toBoolean(value, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -152,7 +159,7 @@ public class BooleanScriptMappedFieldType extends AbstractScriptMappedFieldType<
|
||||||
boolean trueAllowed = false;
|
boolean trueAllowed = false;
|
||||||
boolean falseAllowed = false;
|
boolean falseAllowed = false;
|
||||||
for (Object value : values) {
|
for (Object value : values) {
|
||||||
if (toBoolean(value)) {
|
if (toBoolean(value, false)) {
|
||||||
trueAllowed = true;
|
trueAllowed = true;
|
||||||
} else {
|
} else {
|
||||||
falseAllowed = true;
|
falseAllowed = true;
|
||||||
|
@ -177,10 +184,14 @@ public class BooleanScriptMappedFieldType extends AbstractScriptMappedFieldType<
|
||||||
return new MatchNoDocsQuery("neither true nor false allowed");
|
return new MatchNoDocsQuery("neither true nor false allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean toBoolean(Object value) {
|
||||||
|
return toBoolean(value, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the term into a boolean. Inspired by {@link BooleanFieldMapper.BooleanFieldType#indexedValueForSearch(Object)}.
|
* Convert the term into a boolean. Inspired by {@link BooleanFieldMapper.BooleanFieldType#indexedValueForSearch(Object)}.
|
||||||
*/
|
*/
|
||||||
private static boolean toBoolean(Object value) {
|
private static boolean toBoolean(Object value, boolean caseInsensitive) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -193,6 +204,9 @@ public class BooleanScriptMappedFieldType extends AbstractScriptMappedFieldType<
|
||||||
} else {
|
} else {
|
||||||
sValue = value.toString();
|
sValue = value.toString();
|
||||||
}
|
}
|
||||||
|
if (caseInsensitive) {
|
||||||
|
sValue = Strings.toLowercaseAscii(sValue);
|
||||||
|
}
|
||||||
return Booleans.parseBoolean(sValue);
|
return Booleans.parseBoolean(sValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,9 +88,14 @@ public final class KeywordScriptMappedFieldType extends AbstractScriptMappedFiel
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, RewriteMethod method, org.elasticsearch.index.query.QueryShardContext context) {
|
public Query prefixQuery(
|
||||||
|
String value,
|
||||||
|
RewriteMethod method,
|
||||||
|
boolean caseInsensitive,
|
||||||
|
org.elasticsearch.index.query.QueryShardContext context
|
||||||
|
) {
|
||||||
checkAllowExpensiveQueries(context);
|
checkAllowExpensiveQueries(context);
|
||||||
return new StringScriptFieldPrefixQuery(script, leafFactory(context), name(), value);
|
return new StringScriptFieldPrefixQuery(script, leafFactory(context), name(), value, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -128,13 +133,39 @@ public final class KeywordScriptMappedFieldType extends AbstractScriptMappedFiel
|
||||||
if (matchFlags != 0) {
|
if (matchFlags != 0) {
|
||||||
throw new IllegalArgumentException("Match flags not yet implemented [" + matchFlags + "]");
|
throw new IllegalArgumentException("Match flags not yet implemented [" + matchFlags + "]");
|
||||||
}
|
}
|
||||||
return new StringScriptFieldRegexpQuery(script, leafFactory(context), name(), value, syntaxFlags, maxDeterminizedStates);
|
return new StringScriptFieldRegexpQuery(
|
||||||
|
script,
|
||||||
|
leafFactory(context),
|
||||||
|
name(),
|
||||||
|
value,
|
||||||
|
syntaxFlags,
|
||||||
|
matchFlags,
|
||||||
|
maxDeterminizedStates
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Query termQueryCaseInsensitive(Object value, QueryShardContext context) {
|
||||||
|
checkAllowExpensiveQueries(context);
|
||||||
|
return new StringScriptFieldTermQuery(
|
||||||
|
script,
|
||||||
|
leafFactory(context),
|
||||||
|
name(),
|
||||||
|
BytesRefs.toString(Objects.requireNonNull(value)),
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query termQuery(Object value, QueryShardContext context) {
|
public Query termQuery(Object value, QueryShardContext context) {
|
||||||
checkAllowExpensiveQueries(context);
|
checkAllowExpensiveQueries(context);
|
||||||
return new StringScriptFieldTermQuery(script, leafFactory(context), name(), BytesRefs.toString(Objects.requireNonNull(value)));
|
return new StringScriptFieldTermQuery(
|
||||||
|
script,
|
||||||
|
leafFactory(context),
|
||||||
|
name(),
|
||||||
|
BytesRefs.toString(Objects.requireNonNull(value)),
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -145,8 +176,8 @@ public final class KeywordScriptMappedFieldType extends AbstractScriptMappedFiel
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query wildcardQuery(String value, RewriteMethod method, QueryShardContext context) {
|
public Query wildcardQuery(String value, RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
checkAllowExpensiveQueries(context);
|
checkAllowExpensiveQueries(context);
|
||||||
return new StringScriptFieldWildcardQuery(script, leafFactory(context), name(), value);
|
return new StringScriptFieldWildcardQuery(script, leafFactory(context), name(), value, caseInsensitive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,9 @@ package org.elasticsearch.xpack.runtimefields.query;
|
||||||
import org.apache.lucene.search.PrefixQuery;
|
import org.apache.lucene.search.PrefixQuery;
|
||||||
import org.apache.lucene.search.QueryVisitor;
|
import org.apache.lucene.search.QueryVisitor;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.apache.lucene.util.automaton.Automaton;
|
||||||
import org.apache.lucene.util.automaton.ByteRunAutomaton;
|
import org.apache.lucene.util.automaton.ByteRunAutomaton;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.script.Script;
|
import org.elasticsearch.script.Script;
|
||||||
import org.elasticsearch.xpack.runtimefields.mapper.StringFieldScript;
|
import org.elasticsearch.xpack.runtimefields.mapper.StringFieldScript;
|
||||||
|
|
||||||
|
@ -18,26 +20,63 @@ import java.util.Objects;
|
||||||
|
|
||||||
public class StringScriptFieldPrefixQuery extends AbstractStringScriptFieldQuery {
|
public class StringScriptFieldPrefixQuery extends AbstractStringScriptFieldQuery {
|
||||||
private final String prefix;
|
private final String prefix;
|
||||||
|
private final boolean caseInsensitive;
|
||||||
|
|
||||||
public StringScriptFieldPrefixQuery(Script script, StringFieldScript.LeafFactory leafFactory, String fieldName, String prefix) {
|
public StringScriptFieldPrefixQuery(
|
||||||
|
Script script,
|
||||||
|
StringFieldScript.LeafFactory leafFactory,
|
||||||
|
String fieldName,
|
||||||
|
String prefix,
|
||||||
|
boolean caseInsensitive
|
||||||
|
) {
|
||||||
super(script, leafFactory, fieldName);
|
super(script, leafFactory, fieldName);
|
||||||
this.prefix = Objects.requireNonNull(prefix);
|
this.prefix = Objects.requireNonNull(prefix);
|
||||||
|
this.caseInsensitive = caseInsensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean matches(List<String> values) {
|
protected boolean matches(List<String> values) {
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
if (value != null && value.startsWith(prefix)) {
|
if (startsWith(value, prefix, caseInsensitive)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Check if a String starts with a specified prefix (optionally case insensitive).</p>
|
||||||
|
*
|
||||||
|
* @see java.lang.String#startsWith(String)
|
||||||
|
* @param str the String to check, may be null
|
||||||
|
* @param prefix the prefix to find, may be null
|
||||||
|
* @param ignoreCase inidicates whether the compare should ignore case
|
||||||
|
* (case insensitive) or not.
|
||||||
|
* @return <code>true</code> if the String starts with the prefix or
|
||||||
|
* both <code>null</code>
|
||||||
|
*/
|
||||||
|
private static boolean startsWith(String str, String prefix, boolean ignoreCase) {
|
||||||
|
if (str == null || prefix == null) {
|
||||||
|
return (str == null && prefix == null);
|
||||||
|
}
|
||||||
|
if (prefix.length() > str.length()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return str.regionMatches(ignoreCase, 0, prefix, 0, prefix.length());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(QueryVisitor visitor) {
|
public void visit(QueryVisitor visitor) {
|
||||||
if (visitor.acceptField(fieldName())) {
|
if (visitor.acceptField(fieldName())) {
|
||||||
visitor.consumeTermsMatching(this, fieldName(), () -> new ByteRunAutomaton(PrefixQuery.toAutomaton(new BytesRef(prefix))));
|
visitor.consumeTermsMatching(this, fieldName(), () -> new ByteRunAutomaton(buildAutomaton(new BytesRef(prefix))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Automaton buildAutomaton(BytesRef prefix) {
|
||||||
|
if (caseInsensitive) {
|
||||||
|
return AutomatonQueries.caseInsensitivePrefix(prefix.utf8ToString());
|
||||||
|
} else {
|
||||||
|
return PrefixQuery.toAutomaton(prefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +90,7 @@ public class StringScriptFieldPrefixQuery extends AbstractStringScriptFieldQuery
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(super.hashCode(), prefix);
|
return Objects.hash(super.hashCode(), prefix, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -60,10 +99,14 @@ public class StringScriptFieldPrefixQuery extends AbstractStringScriptFieldQuery
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
StringScriptFieldPrefixQuery other = (StringScriptFieldPrefixQuery) obj;
|
StringScriptFieldPrefixQuery other = (StringScriptFieldPrefixQuery) obj;
|
||||||
return prefix.equals(other.prefix);
|
return prefix.equals(other.prefix) && caseInsensitive == other.caseInsensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
String prefix() {
|
String prefix() {
|
||||||
return prefix;
|
return prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean caseInsensitive() {
|
||||||
|
return caseInsensitive;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,24 +15,27 @@ import java.util.Objects;
|
||||||
|
|
||||||
public class StringScriptFieldRegexpQuery extends AbstractStringScriptFieldAutomatonQuery {
|
public class StringScriptFieldRegexpQuery extends AbstractStringScriptFieldAutomatonQuery {
|
||||||
private final String pattern;
|
private final String pattern;
|
||||||
private final int flags;
|
private final int syntaxFlags;
|
||||||
|
private final int matchFlags;
|
||||||
|
|
||||||
public StringScriptFieldRegexpQuery(
|
public StringScriptFieldRegexpQuery(
|
||||||
Script script,
|
Script script,
|
||||||
StringFieldScript.LeafFactory leafFactory,
|
StringFieldScript.LeafFactory leafFactory,
|
||||||
String fieldName,
|
String fieldName,
|
||||||
String pattern,
|
String pattern,
|
||||||
int flags,
|
int syntaxFlags,
|
||||||
|
int matchFlags,
|
||||||
int maxDeterminizedStates
|
int maxDeterminizedStates
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
script,
|
script,
|
||||||
leafFactory,
|
leafFactory,
|
||||||
fieldName,
|
fieldName,
|
||||||
new ByteRunAutomaton(new RegExp(Objects.requireNonNull(pattern), flags).toAutomaton(maxDeterminizedStates))
|
new ByteRunAutomaton(new RegExp(Objects.requireNonNull(pattern), syntaxFlags, matchFlags).toAutomaton(maxDeterminizedStates))
|
||||||
);
|
);
|
||||||
this.pattern = pattern;
|
this.pattern = pattern;
|
||||||
this.flags = flags;
|
this.syntaxFlags = syntaxFlags;
|
||||||
|
this.matchFlags = matchFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,7 +49,7 @@ public class StringScriptFieldRegexpQuery extends AbstractStringScriptFieldAutom
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(super.hashCode(), pattern, flags);
|
return Objects.hash(super.hashCode(), pattern, syntaxFlags, matchFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,14 +58,18 @@ public class StringScriptFieldRegexpQuery extends AbstractStringScriptFieldAutom
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
StringScriptFieldRegexpQuery other = (StringScriptFieldRegexpQuery) obj;
|
StringScriptFieldRegexpQuery other = (StringScriptFieldRegexpQuery) obj;
|
||||||
return pattern.equals(other.pattern) && flags == other.flags;
|
return pattern.equals(other.pattern) && syntaxFlags == other.syntaxFlags && matchFlags == other.matchFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
String pattern() {
|
String pattern() {
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
int flags() {
|
int syntaxFlags() {
|
||||||
return flags;
|
return syntaxFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
int matchFlags() {
|
||||||
|
return matchFlags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,16 +16,28 @@ import java.util.Objects;
|
||||||
|
|
||||||
public class StringScriptFieldTermQuery extends AbstractStringScriptFieldQuery {
|
public class StringScriptFieldTermQuery extends AbstractStringScriptFieldQuery {
|
||||||
private final String term;
|
private final String term;
|
||||||
|
private final boolean caseInsensitive;
|
||||||
|
|
||||||
public StringScriptFieldTermQuery(Script script, StringFieldScript.LeafFactory leafFactory, String fieldName, String term) {
|
public StringScriptFieldTermQuery(
|
||||||
|
Script script,
|
||||||
|
StringFieldScript.LeafFactory leafFactory,
|
||||||
|
String fieldName,
|
||||||
|
String term,
|
||||||
|
boolean caseInsensitive
|
||||||
|
) {
|
||||||
super(script, leafFactory, fieldName);
|
super(script, leafFactory, fieldName);
|
||||||
this.term = Objects.requireNonNull(term);
|
this.term = Objects.requireNonNull(term);
|
||||||
|
this.caseInsensitive = caseInsensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean matches(List<String> values) {
|
protected boolean matches(List<String> values) {
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
if (term.equals(value)) {
|
if (caseInsensitive) {
|
||||||
|
if (term.equalsIgnoreCase(value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (term.equals(value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +59,7 @@ public class StringScriptFieldTermQuery extends AbstractStringScriptFieldQuery {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(super.hashCode(), term);
|
return Objects.hash(super.hashCode(), term, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,10 +68,14 @@ public class StringScriptFieldTermQuery extends AbstractStringScriptFieldQuery {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
StringScriptFieldTermQuery other = (StringScriptFieldTermQuery) obj;
|
StringScriptFieldTermQuery other = (StringScriptFieldTermQuery) obj;
|
||||||
return term.equals(other.term);
|
return term.equals(other.term) && caseInsensitive == other.caseInsensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
String term() {
|
String term() {
|
||||||
return term;
|
return term;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean caseInsensitive() {
|
||||||
|
return caseInsensitive;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@ package org.elasticsearch.xpack.runtimefields.query;
|
||||||
|
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.WildcardQuery;
|
import org.apache.lucene.search.WildcardQuery;
|
||||||
|
import org.apache.lucene.util.automaton.Automaton;
|
||||||
import org.apache.lucene.util.automaton.ByteRunAutomaton;
|
import org.apache.lucene.util.automaton.ByteRunAutomaton;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.script.Script;
|
import org.elasticsearch.script.Script;
|
||||||
import org.elasticsearch.xpack.runtimefields.mapper.StringFieldScript;
|
import org.elasticsearch.xpack.runtimefields.mapper.StringFieldScript;
|
||||||
|
|
||||||
|
@ -16,15 +18,30 @@ import java.util.Objects;
|
||||||
|
|
||||||
public class StringScriptFieldWildcardQuery extends AbstractStringScriptFieldAutomatonQuery {
|
public class StringScriptFieldWildcardQuery extends AbstractStringScriptFieldAutomatonQuery {
|
||||||
private final String pattern;
|
private final String pattern;
|
||||||
|
private final boolean caseInsensitive;
|
||||||
|
|
||||||
public StringScriptFieldWildcardQuery(Script script, StringFieldScript.LeafFactory leafFactory, String fieldName, String pattern) {
|
public StringScriptFieldWildcardQuery(
|
||||||
|
Script script,
|
||||||
|
StringFieldScript.LeafFactory leafFactory,
|
||||||
|
String fieldName,
|
||||||
|
String pattern,
|
||||||
|
boolean caseInsensitive
|
||||||
|
) {
|
||||||
super(
|
super(
|
||||||
script,
|
script,
|
||||||
leafFactory,
|
leafFactory,
|
||||||
fieldName,
|
fieldName,
|
||||||
new ByteRunAutomaton(WildcardQuery.toAutomaton(new Term(fieldName, Objects.requireNonNull(pattern))))
|
new ByteRunAutomaton(buildAutomaton(new Term(fieldName, Objects.requireNonNull(pattern)), caseInsensitive))
|
||||||
);
|
);
|
||||||
this.pattern = pattern;
|
this.pattern = pattern;
|
||||||
|
this.caseInsensitive = caseInsensitive;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Automaton buildAutomaton(Term term, boolean caseInsensitive) {
|
||||||
|
if (caseInsensitive) {
|
||||||
|
return AutomatonQueries.toCaseInsensitiveWildcardAutomaton(term, Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
return WildcardQuery.toAutomaton(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -37,7 +54,7 @@ public class StringScriptFieldWildcardQuery extends AbstractStringScriptFieldAut
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(super.hashCode(), pattern);
|
return Objects.hash(super.hashCode(), pattern, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,10 +63,14 @@ public class StringScriptFieldWildcardQuery extends AbstractStringScriptFieldAut
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
StringScriptFieldWildcardQuery other = (StringScriptFieldWildcardQuery) obj;
|
StringScriptFieldWildcardQuery other = (StringScriptFieldWildcardQuery) obj;
|
||||||
return pattern.equals(other.pattern);
|
return pattern.equals(other.pattern) && caseInsensitive == other.caseInsensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
String pattern() {
|
String pattern() {
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean caseInsensitive() {
|
||||||
|
return caseInsensitive;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,7 +272,7 @@ public class KeywordScriptMappedFieldTypeTests extends AbstractScriptMappedField
|
||||||
}
|
}
|
||||||
|
|
||||||
private Query randomRegexpQuery(MappedFieldType ft, QueryShardContext ctx) {
|
private Query randomRegexpQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||||
return ft.regexpQuery(randomAlphaOfLengthBetween(1, 1000), randomInt(0xFFFF), 0, Integer.MAX_VALUE, null, ctx);
|
return ft.regexpQuery(randomAlphaOfLengthBetween(1, 1000), randomInt(0xFF), 0, Integer.MAX_VALUE, null, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,12 +16,18 @@ import static org.hamcrest.Matchers.is;
|
||||||
public class StringScriptFieldPrefixQueryTests extends AbstractStringScriptFieldQueryTestCase<StringScriptFieldPrefixQuery> {
|
public class StringScriptFieldPrefixQueryTests extends AbstractStringScriptFieldQueryTestCase<StringScriptFieldPrefixQuery> {
|
||||||
@Override
|
@Override
|
||||||
protected StringScriptFieldPrefixQuery createTestInstance() {
|
protected StringScriptFieldPrefixQuery createTestInstance() {
|
||||||
return new StringScriptFieldPrefixQuery(randomScript(), leafFactory, randomAlphaOfLength(5), randomAlphaOfLength(6));
|
return new StringScriptFieldPrefixQuery(
|
||||||
|
randomScript(),
|
||||||
|
leafFactory,
|
||||||
|
randomAlphaOfLength(5),
|
||||||
|
randomAlphaOfLength(6),
|
||||||
|
randomBoolean()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected StringScriptFieldPrefixQuery copy(StringScriptFieldPrefixQuery orig) {
|
protected StringScriptFieldPrefixQuery copy(StringScriptFieldPrefixQuery orig) {
|
||||||
return new StringScriptFieldPrefixQuery(orig.script(), leafFactory, orig.fieldName(), orig.prefix());
|
return new StringScriptFieldPrefixQuery(orig.script(), leafFactory, orig.fieldName(), orig.prefix(), orig.caseInsensitive());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,6 +35,7 @@ public class StringScriptFieldPrefixQueryTests extends AbstractStringScriptField
|
||||||
Script script = orig.script();
|
Script script = orig.script();
|
||||||
String fieldName = orig.fieldName();
|
String fieldName = orig.fieldName();
|
||||||
String prefix = orig.prefix();
|
String prefix = orig.prefix();
|
||||||
|
boolean caseInsensitive = orig.caseInsensitive();
|
||||||
switch (randomInt(2)) {
|
switch (randomInt(2)) {
|
||||||
case 0:
|
case 0:
|
||||||
script = randomValueOtherThan(script, this::randomScript);
|
script = randomValueOtherThan(script, this::randomScript);
|
||||||
|
@ -39,19 +46,30 @@ public class StringScriptFieldPrefixQueryTests extends AbstractStringScriptField
|
||||||
case 2:
|
case 2:
|
||||||
prefix += "modified";
|
prefix += "modified";
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
caseInsensitive = !caseInsensitive;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
return new StringScriptFieldPrefixQuery(script, leafFactory, fieldName, prefix);
|
return new StringScriptFieldPrefixQuery(script, leafFactory, fieldName, prefix, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void testMatches() {
|
public void testMatches() {
|
||||||
StringScriptFieldPrefixQuery query = new StringScriptFieldPrefixQuery(randomScript(), leafFactory, "test", "foo");
|
StringScriptFieldPrefixQuery query = new StringScriptFieldPrefixQuery(randomScript(), leafFactory, "test", "foo", false);
|
||||||
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("foo")));
|
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("foo")));
|
||||||
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("Foo")));
|
||||||
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("foooo")));
|
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("foooo")));
|
||||||
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("Foooo")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("fo")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("fo")));
|
||||||
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("fo", "foo")));
|
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("fo", "foo")));
|
||||||
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("Fo", "fOo")));
|
||||||
|
|
||||||
|
StringScriptFieldPrefixQuery ciQuery = new StringScriptFieldPrefixQuery(randomScript(), leafFactory, "test", "foo", true);
|
||||||
|
assertTrue(ciQuery.matches(org.elasticsearch.common.collect.List.of("fOo")));
|
||||||
|
assertTrue(ciQuery.matches(org.elasticsearch.common.collect.List.of("Foooo")));
|
||||||
|
assertTrue(ciQuery.matches(org.elasticsearch.common.collect.List.of("fo", "foO")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,12 +18,14 @@ import static org.hamcrest.Matchers.is;
|
||||||
public class StringScriptFieldRegexpQueryTests extends AbstractStringScriptFieldQueryTestCase<StringScriptFieldRegexpQuery> {
|
public class StringScriptFieldRegexpQueryTests extends AbstractStringScriptFieldQueryTestCase<StringScriptFieldRegexpQuery> {
|
||||||
@Override
|
@Override
|
||||||
protected StringScriptFieldRegexpQuery createTestInstance() {
|
protected StringScriptFieldRegexpQuery createTestInstance() {
|
||||||
|
int matchFlags = randomBoolean() ? 0 : RegExp.ASCII_CASE_INSENSITIVE;
|
||||||
return new StringScriptFieldRegexpQuery(
|
return new StringScriptFieldRegexpQuery(
|
||||||
randomScript(),
|
randomScript(),
|
||||||
leafFactory,
|
leafFactory,
|
||||||
randomAlphaOfLength(5),
|
randomAlphaOfLength(5),
|
||||||
randomAlphaOfLength(6),
|
randomAlphaOfLength(6),
|
||||||
randomInt(RegExp.ALL),
|
randomInt(RegExp.ALL),
|
||||||
|
matchFlags,
|
||||||
Operations.DEFAULT_MAX_DETERMINIZED_STATES
|
Operations.DEFAULT_MAX_DETERMINIZED_STATES
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +37,8 @@ public class StringScriptFieldRegexpQueryTests extends AbstractStringScriptField
|
||||||
leafFactory,
|
leafFactory,
|
||||||
orig.fieldName(),
|
orig.fieldName(),
|
||||||
orig.pattern(),
|
orig.pattern(),
|
||||||
orig.flags(),
|
orig.syntaxFlags(),
|
||||||
|
orig.matchFlags(),
|
||||||
Operations.DEFAULT_MAX_DETERMINIZED_STATES
|
Operations.DEFAULT_MAX_DETERMINIZED_STATES
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -45,8 +48,9 @@ public class StringScriptFieldRegexpQueryTests extends AbstractStringScriptField
|
||||||
Script script = orig.script();
|
Script script = orig.script();
|
||||||
String fieldName = orig.fieldName();
|
String fieldName = orig.fieldName();
|
||||||
String pattern = orig.pattern();
|
String pattern = orig.pattern();
|
||||||
int flags = orig.flags();
|
int syntaxFlags = orig.syntaxFlags();
|
||||||
switch (randomInt(3)) {
|
int matchFlags = orig.matchFlags();
|
||||||
|
switch (randomInt(4)) {
|
||||||
case 0:
|
case 0:
|
||||||
script = randomValueOtherThan(script, this::randomScript);
|
script = randomValueOtherThan(script, this::randomScript);
|
||||||
break;
|
break;
|
||||||
|
@ -57,12 +61,23 @@ public class StringScriptFieldRegexpQueryTests extends AbstractStringScriptField
|
||||||
pattern += "modified";
|
pattern += "modified";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
flags = randomValueOtherThan(flags, () -> randomInt(RegExp.ALL));
|
syntaxFlags = randomValueOtherThan(syntaxFlags, () -> randomInt(RegExp.ALL));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
matchFlags = (matchFlags & RegExp.ASCII_CASE_INSENSITIVE) != 0 ? 0 : RegExp.ASCII_CASE_INSENSITIVE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
return new StringScriptFieldRegexpQuery(script, leafFactory, fieldName, pattern, flags, Operations.DEFAULT_MAX_DETERMINIZED_STATES);
|
return new StringScriptFieldRegexpQuery(
|
||||||
|
script,
|
||||||
|
leafFactory,
|
||||||
|
fieldName,
|
||||||
|
pattern,
|
||||||
|
syntaxFlags,
|
||||||
|
matchFlags,
|
||||||
|
Operations.DEFAULT_MAX_DETERMINIZED_STATES
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -73,14 +88,28 @@ public class StringScriptFieldRegexpQueryTests extends AbstractStringScriptField
|
||||||
"test",
|
"test",
|
||||||
"a.+b",
|
"a.+b",
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
Operations.DEFAULT_MAX_DETERMINIZED_STATES
|
Operations.DEFAULT_MAX_DETERMINIZED_STATES
|
||||||
);
|
);
|
||||||
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("astuffb")));
|
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("astuffb")));
|
||||||
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("astuffB")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("fffff")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("fffff")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("ab")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("ab")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("aasdf")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("aasdf")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("dsfb")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("dsfb")));
|
||||||
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("astuffb", "fffff")));
|
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("astuffb", "fffff")));
|
||||||
|
|
||||||
|
StringScriptFieldRegexpQuery ciQuery = new StringScriptFieldRegexpQuery(
|
||||||
|
randomScript(),
|
||||||
|
leafFactory,
|
||||||
|
"test",
|
||||||
|
"a.+b",
|
||||||
|
0,
|
||||||
|
RegExp.ASCII_CASE_INSENSITIVE,
|
||||||
|
Operations.DEFAULT_MAX_DETERMINIZED_STATES
|
||||||
|
);
|
||||||
|
assertTrue(ciQuery.matches(org.elasticsearch.common.collect.List.of("astuffB")));
|
||||||
|
assertTrue(ciQuery.matches(org.elasticsearch.common.collect.List.of("Astuffb", "fffff")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -96,6 +125,7 @@ public class StringScriptFieldRegexpQueryTests extends AbstractStringScriptField
|
||||||
"test",
|
"test",
|
||||||
"a.+b",
|
"a.+b",
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
Operations.DEFAULT_MAX_DETERMINIZED_STATES
|
Operations.DEFAULT_MAX_DETERMINIZED_STATES
|
||||||
);
|
);
|
||||||
ByteRunAutomaton automaton = visitForSingleAutomata(query);
|
ByteRunAutomaton automaton = visitForSingleAutomata(query);
|
||||||
|
|
|
@ -22,12 +22,12 @@ import static org.hamcrest.Matchers.equalTo;
|
||||||
public class StringScriptFieldTermQueryTests extends AbstractStringScriptFieldQueryTestCase<StringScriptFieldTermQuery> {
|
public class StringScriptFieldTermQueryTests extends AbstractStringScriptFieldQueryTestCase<StringScriptFieldTermQuery> {
|
||||||
@Override
|
@Override
|
||||||
protected StringScriptFieldTermQuery createTestInstance() {
|
protected StringScriptFieldTermQuery createTestInstance() {
|
||||||
return new StringScriptFieldTermQuery(randomScript(), leafFactory, randomAlphaOfLength(5), randomAlphaOfLength(6));
|
return new StringScriptFieldTermQuery(randomScript(), leafFactory, randomAlphaOfLength(5), randomAlphaOfLength(6), randomBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected StringScriptFieldTermQuery copy(StringScriptFieldTermQuery orig) {
|
protected StringScriptFieldTermQuery copy(StringScriptFieldTermQuery orig) {
|
||||||
return new StringScriptFieldTermQuery(orig.script(), leafFactory, orig.fieldName(), orig.term());
|
return new StringScriptFieldTermQuery(orig.script(), leafFactory, orig.fieldName(), orig.term(), orig.caseInsensitive());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -35,7 +35,8 @@ public class StringScriptFieldTermQueryTests extends AbstractStringScriptFieldQu
|
||||||
Script script = orig.script();
|
Script script = orig.script();
|
||||||
String fieldName = orig.fieldName();
|
String fieldName = orig.fieldName();
|
||||||
String term = orig.term();
|
String term = orig.term();
|
||||||
switch (randomInt(2)) {
|
boolean caseInsensitive = orig.caseInsensitive();
|
||||||
|
switch (randomInt(3)) {
|
||||||
case 0:
|
case 0:
|
||||||
script = randomValueOtherThan(script, this::randomScript);
|
script = randomValueOtherThan(script, this::randomScript);
|
||||||
break;
|
break;
|
||||||
|
@ -45,18 +46,26 @@ public class StringScriptFieldTermQueryTests extends AbstractStringScriptFieldQu
|
||||||
case 2:
|
case 2:
|
||||||
term += "modified";
|
term += "modified";
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
caseInsensitive = !caseInsensitive;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
return new StringScriptFieldTermQuery(script, leafFactory, fieldName, term);
|
return new StringScriptFieldTermQuery(script, leafFactory, fieldName, term, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void testMatches() {
|
public void testMatches() {
|
||||||
StringScriptFieldTermQuery query = new StringScriptFieldTermQuery(randomScript(), leafFactory, "test", "foo");
|
StringScriptFieldTermQuery query = new StringScriptFieldTermQuery(randomScript(), leafFactory, "test", "foo", false);
|
||||||
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("foo")));
|
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("foo")));
|
||||||
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("foO")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("bar")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("bar")));
|
||||||
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("foo", "bar")));
|
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("foo", "bar")));
|
||||||
|
|
||||||
|
StringScriptFieldTermQuery ciQuery = new StringScriptFieldTermQuery(randomScript(), leafFactory, "test", "foo", true);
|
||||||
|
assertTrue(ciQuery.matches(org.elasticsearch.common.collect.List.of("Foo")));
|
||||||
|
assertTrue(ciQuery.matches(org.elasticsearch.common.collect.List.of("fOo", "bar")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -15,12 +15,18 @@ import static org.hamcrest.Matchers.equalTo;
|
||||||
public class StringScriptFieldWildcardQueryTests extends AbstractStringScriptFieldQueryTestCase<StringScriptFieldWildcardQuery> {
|
public class StringScriptFieldWildcardQueryTests extends AbstractStringScriptFieldQueryTestCase<StringScriptFieldWildcardQuery> {
|
||||||
@Override
|
@Override
|
||||||
protected StringScriptFieldWildcardQuery createTestInstance() {
|
protected StringScriptFieldWildcardQuery createTestInstance() {
|
||||||
return new StringScriptFieldWildcardQuery(randomScript(), leafFactory, randomAlphaOfLength(5), randomAlphaOfLength(6));
|
return new StringScriptFieldWildcardQuery(
|
||||||
|
randomScript(),
|
||||||
|
leafFactory,
|
||||||
|
randomAlphaOfLength(5),
|
||||||
|
randomAlphaOfLength(6),
|
||||||
|
randomBoolean()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected StringScriptFieldWildcardQuery copy(StringScriptFieldWildcardQuery orig) {
|
protected StringScriptFieldWildcardQuery copy(StringScriptFieldWildcardQuery orig) {
|
||||||
return new StringScriptFieldWildcardQuery(orig.script(), leafFactory, orig.fieldName(), orig.pattern());
|
return new StringScriptFieldWildcardQuery(orig.script(), leafFactory, orig.fieldName(), orig.pattern(), orig.caseInsensitive());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -28,7 +34,8 @@ public class StringScriptFieldWildcardQueryTests extends AbstractStringScriptFie
|
||||||
Script script = orig.script();
|
Script script = orig.script();
|
||||||
String fieldName = orig.fieldName();
|
String fieldName = orig.fieldName();
|
||||||
String pattern = orig.pattern();
|
String pattern = orig.pattern();
|
||||||
switch (randomInt(2)) {
|
boolean caseInsensitive = orig.caseInsensitive();
|
||||||
|
switch (randomInt(3)) {
|
||||||
case 0:
|
case 0:
|
||||||
script = randomValueOtherThan(script, this::randomScript);
|
script = randomValueOtherThan(script, this::randomScript);
|
||||||
break;
|
break;
|
||||||
|
@ -38,22 +45,31 @@ public class StringScriptFieldWildcardQueryTests extends AbstractStringScriptFie
|
||||||
case 2:
|
case 2:
|
||||||
pattern += "modified";
|
pattern += "modified";
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
caseInsensitive = !caseInsensitive;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
return new StringScriptFieldWildcardQuery(script, leafFactory, fieldName, pattern);
|
return new StringScriptFieldWildcardQuery(script, leafFactory, fieldName, pattern, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void testMatches() {
|
public void testMatches() {
|
||||||
StringScriptFieldWildcardQuery query = new StringScriptFieldWildcardQuery(randomScript(), leafFactory, "test", "a*b");
|
StringScriptFieldWildcardQuery query = new StringScriptFieldWildcardQuery(randomScript(), leafFactory, "test", "a*b", false);
|
||||||
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("astuffb")));
|
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("astuffb")));
|
||||||
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("Astuffb")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("fffff")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("fffff")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("a")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("a")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("b")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("b")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("aasdf")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("aasdf")));
|
||||||
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("dsfb")));
|
assertFalse(query.matches(org.elasticsearch.common.collect.List.of("dsfb")));
|
||||||
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("astuffb", "fffff")));
|
assertTrue(query.matches(org.elasticsearch.common.collect.List.of("astuffb", "fffff")));
|
||||||
|
|
||||||
|
StringScriptFieldWildcardQuery ciQuery = new StringScriptFieldWildcardQuery(randomScript(), leafFactory, "test", "a*b", true);
|
||||||
|
assertTrue(ciQuery.matches(org.elasticsearch.common.collect.List.of("Astuffb")));
|
||||||
|
assertTrue(ciQuery.matches(org.elasticsearch.common.collect.List.of("astuffB", "fffff")));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,7 +79,7 @@ public class StringScriptFieldWildcardQueryTests extends AbstractStringScriptFie
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void testVisit() {
|
public void testVisit() {
|
||||||
StringScriptFieldWildcardQuery query = new StringScriptFieldWildcardQuery(randomScript(), leafFactory, "test", "a*b");
|
StringScriptFieldWildcardQuery query = new StringScriptFieldWildcardQuery(randomScript(), leafFactory, "test", "a*b", false);
|
||||||
ByteRunAutomaton automaton = visitForSingleAutomata(query);
|
ByteRunAutomaton automaton = visitForSingleAutomata(query);
|
||||||
BytesRef term = new BytesRef("astuffb");
|
BytesRef term = new BytesRef("astuffb");
|
||||||
assertTrue(automaton.run(term.bytes, term.offset, term.length));
|
assertTrue(automaton.run(term.bytes, term.offset, term.length));
|
||||||
|
|
|
@ -138,8 +138,8 @@ public class VersionStringFieldMapper extends ParametrizedFieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
return wildcardQuery(value + "*", method, context);
|
return wildcardQuery(value + "*", method, caseInsensitive, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -237,7 +237,7 @@ public class VersionStringFieldMapper extends ParametrizedFieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query wildcardQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query wildcardQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
if (context.allowExpensiveQueries() == false) {
|
if (context.allowExpensiveQueries() == false) {
|
||||||
throw new ElasticsearchException(
|
throw new ElasticsearchException(
|
||||||
"[wildcard] queries cannot be executed when '" + ALLOW_EXPENSIVE_QUERIES.getKey() + "' is set to false."
|
"[wildcard] queries cannot be executed when '" + ALLOW_EXPENSIVE_QUERIES.getKey() + "' is set to false."
|
||||||
|
|
|
@ -40,6 +40,7 @@ import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.geo.ShapeRelation;
|
import org.elasticsearch.common.geo.ShapeRelation;
|
||||||
import org.elasticsearch.common.lucene.BytesRefs;
|
import org.elasticsearch.common.lucene.BytesRefs;
|
||||||
import org.elasticsearch.common.lucene.Lucene;
|
import org.elasticsearch.common.lucene.Lucene;
|
||||||
|
import org.elasticsearch.common.lucene.search.AutomatonQueries;
|
||||||
import org.elasticsearch.common.time.DateMathParser;
|
import org.elasticsearch.common.time.DateMathParser;
|
||||||
import org.elasticsearch.common.unit.Fuzziness;
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
@ -218,7 +219,7 @@ public class WildcardFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query wildcardQuery(String wildcardPattern, RewriteMethod method, QueryShardContext context) {
|
public Query wildcardQuery(String wildcardPattern, RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
|
|
||||||
String ngramIndexPattern = addLineEndChars(toLowerCase(wildcardPattern));
|
String ngramIndexPattern = addLineEndChars(toLowerCase(wildcardPattern));
|
||||||
|
|
||||||
|
@ -276,7 +277,11 @@ public class WildcardFieldMapper extends FieldMapper {
|
||||||
clauseCount++;
|
clauseCount++;
|
||||||
}
|
}
|
||||||
Supplier<Automaton> deferredAutomatonSupplier = () -> {
|
Supplier<Automaton> deferredAutomatonSupplier = () -> {
|
||||||
return WildcardQuery.toAutomaton(new Term(name(), wildcardPattern));
|
if(caseInsensitive) {
|
||||||
|
return AutomatonQueries.toCaseInsensitiveWildcardAutomaton(new Term(name(), wildcardPattern), Integer.MAX_VALUE);
|
||||||
|
} else {
|
||||||
|
return WildcardQuery.toAutomaton(new Term(name(), wildcardPattern));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
AutomatonQueryOnBinaryDv verifyingQuery = new AutomatonQueryOnBinaryDv(name(), wildcardPattern, deferredAutomatonSupplier);
|
AutomatonQueryOnBinaryDv verifyingQuery = new AutomatonQueryOnBinaryDv(name(), wildcardPattern, deferredAutomatonSupplier);
|
||||||
if (clauseCount > 0) {
|
if (clauseCount > 0) {
|
||||||
|
@ -845,7 +850,7 @@ public class WildcardFieldMapper extends FieldMapper {
|
||||||
@Override
|
@Override
|
||||||
public Query termQuery(Object value, QueryShardContext context) {
|
public Query termQuery(Object value, QueryShardContext context) {
|
||||||
String searchTerm = BytesRefs.toString(value);
|
String searchTerm = BytesRefs.toString(value);
|
||||||
return wildcardQuery(escapeWildcardSyntax(searchTerm), MultiTermQuery.CONSTANT_SCORE_REWRITE, context);
|
return wildcardQuery(escapeWildcardSyntax(searchTerm), MultiTermQuery.CONSTANT_SCORE_REWRITE, false, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String escapeWildcardSyntax(String term) {
|
private String escapeWildcardSyntax(String term) {
|
||||||
|
@ -864,8 +869,14 @@ public class WildcardFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
|
public Query termQueryCaseInsensitive(Object value, QueryShardContext context) {
|
||||||
return wildcardQuery(escapeWildcardSyntax(value) + "*", method, context);
|
String searchTerm = BytesRefs.toString(value);
|
||||||
|
return wildcardQuery(escapeWildcardSyntax(searchTerm), MultiTermQuery.CONSTANT_SCORE_REWRITE, true, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
|
||||||
|
return wildcardQuery(escapeWildcardSyntax(value) + "*", method, caseInsensitive, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -263,18 +263,21 @@ public class WildcardFieldMapperTests extends ESTestCase {
|
||||||
switch (randomInt(4)) {
|
switch (randomInt(4)) {
|
||||||
case 0:
|
case 0:
|
||||||
pattern = getRandomWildcardPattern();
|
pattern = getRandomWildcardPattern();
|
||||||
wildcardFieldQuery = wildcardFieldType.fieldType().wildcardQuery(pattern, null, MOCK_QSC);
|
boolean caseInsensitive = randomBoolean();
|
||||||
keywordFieldQuery = keywordFieldType.fieldType().wildcardQuery(pattern, null, MOCK_QSC);
|
wildcardFieldQuery = wildcardFieldType.fieldType().wildcardQuery(pattern, null, caseInsensitive, MOCK_QSC);
|
||||||
|
keywordFieldQuery = keywordFieldType.fieldType().wildcardQuery(pattern, null, caseInsensitive, MOCK_QSC);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
pattern = getRandomRegexPattern(values);
|
pattern = getRandomRegexPattern(values);
|
||||||
wildcardFieldQuery = wildcardFieldType.fieldType().regexpQuery(pattern, RegExp.ALL, 0, 20000, null, MOCK_QSC);
|
int matchFlags = randomBoolean()? 0 : RegExp.ASCII_CASE_INSENSITIVE;
|
||||||
keywordFieldQuery = keywordFieldType.fieldType().regexpQuery(pattern, RegExp.ALL, 0,20000, null, MOCK_QSC);
|
wildcardFieldQuery = wildcardFieldType.fieldType().regexpQuery(pattern, RegExp.ALL, matchFlags, 20000, null, MOCK_QSC);
|
||||||
|
keywordFieldQuery = keywordFieldType.fieldType().regexpQuery(pattern, RegExp.ALL, matchFlags,20000, null, MOCK_QSC);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
pattern = randomABString(5);
|
pattern = randomABString(5);
|
||||||
wildcardFieldQuery = wildcardFieldType.fieldType().prefixQuery(pattern, null, MOCK_QSC);
|
boolean caseInsensitivePrefix = randomBoolean();
|
||||||
keywordFieldQuery = keywordFieldType.fieldType().prefixQuery(pattern, null, MOCK_QSC);
|
wildcardFieldQuery = wildcardFieldType.fieldType().prefixQuery(pattern, null, caseInsensitivePrefix, MOCK_QSC);
|
||||||
|
keywordFieldQuery = keywordFieldType.fieldType().prefixQuery(pattern, null, caseInsensitivePrefix, MOCK_QSC);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
int edits = randomInt(2);
|
int edits = randomInt(2);
|
||||||
|
|
Loading…
Reference in New Issue