Expose `simple_query_string` flags in `flags` parameter

This commit is contained in:
Lee Hinman 2013-12-27 09:54:06 -07:00
parent 602c63d2aa
commit 5463f7953f
5 changed files with 171 additions and 2 deletions

View File

@ -36,6 +36,9 @@ with default operator of `AND`, the same query is translated to
|`analyzer` |The analyzer used to analyze each term of the query when
creating composite queries.
|`flags` |Flags specifying which features of the `simple_query_string` to
enable. Defaults to `ALL`.
|=======================================================================
[float]
@ -76,3 +79,22 @@ introduced fields included). For example:
}
}
--------------------------------------------------
[float]
==== Flags
`simple_query_string` support multiple flags to specify which parsing features
should be enabled. It is specified as a `|`-delimited string with the
`flags` parameter:
[source,js]
--------------------------------------------------
{
"simple_query_string" : {
"query" : "foo | bar & baz*",
"flags" : "OR|AND|PREFIX"
}
}
--------------------------------------------------
The available flags are: `ALL`, `NONE`, `AND`, `OR`, `PREFIX`, `PHRASE`,
`PRECEDENCE`, `ESCAPE`, and `WHITESPACE`.

View File

@ -35,6 +35,7 @@ public class SimpleQueryStringBuilder extends BaseQueryBuilder {
private String analyzer;
private Operator operator;
private final String queryText;
private int flags = -1;
/**
* Operators for the default_operator
@ -84,6 +85,22 @@ public class SimpleQueryStringBuilder extends BaseQueryBuilder {
return this;
}
/**
* Specify the enabled features of the SimpleQueryString.
*/
public SimpleQueryStringBuilder flags(SimpleQueryStringFlag... flags) {
int value = 0;
if (flags.length == 0) {
value = SimpleQueryStringFlag.ALL.value;
} else {
for (SimpleQueryStringFlag flag : flags) {
value |= flag.value;
}
}
this.flags = value;
return this;
}
@Override
public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(SimpleQueryStringParser.NAME);
@ -104,6 +121,10 @@ public class SimpleQueryStringBuilder extends BaseQueryBuilder {
builder.endArray();
}
if (flags != -1) {
builder.field("flags", flags);
}
if (analyzer != null) {
builder.field("analyzer", analyzer);
}

View File

@ -0,0 +1,58 @@
package org.elasticsearch.index.query;
import org.apache.lucene.queryparser.XSimpleQueryParser;
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.Strings;
import java.util.Locale;
/**
* Flags for the XSimpleQueryString parser
*/
public enum SimpleQueryStringFlag {
ALL(-1),
NONE(0),
AND(XSimpleQueryParser.AND_OPERATOR),
NOT(XSimpleQueryParser.NOT_OPERATOR),
OR(XSimpleQueryParser.OR_OPERATOR),
PREFIX(XSimpleQueryParser.PREFIX_OPERATOR),
PRECEDENCE(XSimpleQueryParser.PRECEDENCE_OPERATORS),
ESCAPE(XSimpleQueryParser.ESCAPE_OPERATOR),
WHITESPACE(XSimpleQueryParser.WHITESPACE_OPERATOR);
final int value;
private SimpleQueryStringFlag(int value) {
this.value = value;
}
public int value() {
return value;
}
static int resolveFlags(String flags) {
if (!Strings.hasLength(flags)) {
return ALL.value();
}
int magic = NONE.value();
for (String s : Strings.delimitedListToStringArray(flags, "|")) {
if (s.isEmpty()) {
continue;
}
try {
SimpleQueryStringFlag flag = SimpleQueryStringFlag.valueOf(s.toUpperCase(Locale.ROOT));
switch (flag) {
case NONE:
return 0;
case ALL:
return -1;
default:
magic |= flag.value();
}
} catch (IllegalArgumentException iae) {
throw new ElasticSearchIllegalArgumentException("Unknown " + SimpleQueryStringParser.NAME + " flag [" + s + "]");
}
}
return magic;
}
}

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@ -86,6 +87,7 @@ public class SimpleQueryStringParser implements QueryParser {
Map<String, Float> fieldsAndWeights = null;
BooleanClause.Occur defaultOperator = null;
Analyzer analyzer = null;
int flags = -1;
XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
@ -146,6 +148,17 @@ public class SimpleQueryStringParser implements QueryParser {
throw new QueryParsingException(parseContext.index(),
"[" + NAME + "] default operator [" + op + "] is not allowed");
}
} else if ("flags".equals(currentFieldName)) {
if (parser.hasTextCharacters()) {
// Possible options are:
// ALL, NONE, AND, OR, PREFIX, PHRASE, PRECEDENCE, ESCAPE, WHITESPACE
flags = SimpleQueryStringFlag.resolveFlags(parser.text());
} else {
flags = parser.intValue();
if (flags < 0) {
flags = SimpleQueryStringFlag.ALL.value();
}
}
} else {
throw new QueryParsingException(parseContext.index(), "[" + NAME + "] unsupported field [" + parser.currentName() + "]");
}
@ -174,9 +187,9 @@ public class SimpleQueryStringParser implements QueryParser {
XSimpleQueryParser sqp;
if (fieldsAndWeights != null) {
sqp = new XSimpleQueryParser(analyzer, fieldsAndWeights);
sqp = new XSimpleQueryParser(analyzer, fieldsAndWeights, flags);
} else {
sqp = new XSimpleQueryParser(analyzer, field);
sqp = new XSimpleQueryParser(analyzer, Collections.singletonMap(field, 1.0F), flags);
}
if (defaultOperator != null) {

View File

@ -1955,4 +1955,59 @@ public class SimpleQueryTests extends ElasticsearchIntegrationTest {
assertFirstHit(searchResponse, hasId("5"));
assertSearchHits(searchResponse, "5", "6");
}
@Test
public void testSimpleQueryStringFlags() {
assertAcked(client().admin().indices().prepareCreate("test").setSettings(SETTING_NUMBER_OF_SHARDS, 1));
client().prepareIndex("test", "type1", "1").setSource("body", "foo").get();
client().prepareIndex("test", "type1", "2").setSource("body", "bar").get();
client().prepareIndex("test", "type1", "3").setSource("body", "foo bar").get();
client().prepareIndex("test", "type1", "4").setSource("body", "quux baz eggplant").get();
client().prepareIndex("test", "type1", "5").setSource("body", "quux baz spaghetti").get();
client().prepareIndex("test", "type1", "6").setSource("otherbody", "spaghetti").get();
refresh();
SearchResponse searchResponse = client().prepareSearch().setQuery(
simpleQueryString("foo bar").flags(SimpleQueryStringFlag.ALL)).get();
assertHitCount(searchResponse, 3l);
assertSearchHits(searchResponse, "1", "2", "3");
searchResponse = client().prepareSearch().setQuery(
simpleQueryString("foo | bar")
.defaultOperator(SimpleQueryStringBuilder.Operator.AND)
.flags(SimpleQueryStringFlag.OR)).get();
assertHitCount(searchResponse, 3l);
assertSearchHits(searchResponse, "1", "2", "3");
searchResponse = client().prepareSearch().setQuery(
simpleQueryString("foo | bar")
.defaultOperator(SimpleQueryStringBuilder.Operator.AND)
.flags(SimpleQueryStringFlag.NONE)).get();
assertHitCount(searchResponse, 1l);
assertFirstHit(searchResponse, hasId("3"));
searchResponse = client().prepareSearch().setQuery(
simpleQueryString("baz | egg*")
.defaultOperator(SimpleQueryStringBuilder.Operator.AND)
.flags(SimpleQueryStringFlag.NONE)).get();
assertHitCount(searchResponse, 0l);
searchResponse = client().prepareSearch().setSource("{\n" +
" \"query\": {\n" +
" \"simple_query_string\": {\n" +
" \"query\": \"foo|bar\",\n" +
" \"default_operator\": \"AND\"," +
" \"flags\": \"NONE\"\n" +
" }\n" +
" }\n" +
"}").get();
assertHitCount(searchResponse, 1l);
searchResponse = client().prepareSearch().setQuery(
simpleQueryString("baz | egg*")
.defaultOperator(SimpleQueryStringBuilder.Operator.AND)
.flags(SimpleQueryStringFlag.WHITESPACE, SimpleQueryStringFlag.PREFIX)).get();
assertHitCount(searchResponse, 1l);
assertFirstHit(searchResponse, hasId("4"));
}
}