rename json query to wrapper query, and optimize it to not parse it twice, once on creation, and once on parsing to build lucene queries

This commit is contained in:
kimchy 2011-07-13 03:38:36 +03:00
parent cfc45b0ab9
commit c2584baf86
6 changed files with 70 additions and 61 deletions

View File

@ -438,6 +438,12 @@ public final class XContentBuilder {
return this;
}
public XContentBuilder field(String name, byte[] value, int offset, int length) throws IOException {
field(name);
generator.writeBinary(value, offset, length);
return this;
}
public XContentBuilder field(String name, Map<String, Object> value) throws IOException {
field(name);
value(value);
@ -486,24 +492,6 @@ public final class XContentBuilder {
return this;
}
public XContentBuilder field(String name, Object... value) throws IOException {
startArray(name);
for (Object o : value) {
value(o);
}
endArray();
return this;
}
public XContentBuilder field(XContentBuilderString name, Object... value) throws IOException {
startArray(name);
for (Object o : value) {
value(o);
}
endArray();
return this;
}
public XContentBuilder field(String name, int... value) throws IOException {
startArray(name);
for (Object o : value) {
@ -905,6 +893,14 @@ public final class XContentBuilder {
return this;
}
public XContentBuilder value(byte[] value, int offset, int length) throws IOException {
if (value == null) {
return nullValue();
}
generator.writeBinary(value, offset, length);
return this;
}
public XContentBuilder map(Map<String, Object> map) throws IOException {
if (map == null) {
return nullValue();

View File

@ -611,8 +611,18 @@ public abstract class QueryBuilders {
return new PrefixFilterBuilder(name, prefix);
}
public static JSONQueryBuilder json(String jsonString) {
return new JSONQueryBuilder(jsonString);
/**
* A Query builder which allows building a query thanks to a JSON string or binary data.
*/
public static WrapperQueryBuilder wrapperQuery(String source) {
return new WrapperQueryBuilder(source);
}
/**
* A Query builder which allows building a query thanks to a JSON string or binary data.
*/
public static WrapperQueryBuilder wrapperQuery(byte[] source, int offset, int length) {
return new WrapperQueryBuilder(source, offset, length);
}
private QueryBuilders() {

View File

@ -25,18 +25,13 @@ package org.elasticsearch.index.query;
* Time: 11:30
*/
import org.apache.lucene.util.UnicodeUtil;
import org.elasticsearch.common.jackson.JsonParser;
import org.elasticsearch.common.base.Charsets;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.common.xcontent.json.JsonXContentParser;
import java.io.IOException;
/**
* A Query builder which allows building a query thanks to a JSON string. This is useful when you want
* A Query builder which allows building a query thanks to a JSON string or binary data. This is useful when you want
* to use the Java Builder API but still have JSON query strings at hand that you want to combine with other
* query builders.
*
@ -44,31 +39,37 @@ import java.io.IOException;
* <pre>
* {@code
* BoolQueryBuilder bool = new BoolQueryBuilder();
* bool.must(new JSONQueryBuilder("{\"term\": {\"field\":\"value\"}}");
* bool.must(new WrapperQueryBuilder("{\"term\": {\"field\":\"value\"}}");
* bool.must(new TermQueryBuilder("field2","value2");
* }
* </pre>
*
* @author Cedric Champeau
*/
public class JSONQueryBuilder extends BaseQueryBuilder {
public class WrapperQueryBuilder extends BaseQueryBuilder {
private final String jsonQuery;
private final byte[] source;
private final int offset;
private final int length;
/**
* Builds a JSONQueryBuilder using the provided JSON query string.
* @param jsonQuery
*/
public JSONQueryBuilder(String jsonQuery) {
this.jsonQuery = jsonQuery;
public WrapperQueryBuilder(String source) {
this.source = source.getBytes(Charsets.UTF_8);
this.offset = 0;
this.length = source.length();
}
public WrapperQueryBuilder(byte[] source, int offset, int length) {
this.source = source;
this.offset = offset;
this.length = length;
}
@Override protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(JSONQueryParser.NAME);
XContentParser parser = JsonXContent.jsonXContent.createParser(jsonQuery);
parser.nextToken();
builder.field("value");
builder.copyCurrentStructure(parser);
builder.startObject(WrapperQueryParser.NAME);
builder.field("query", source, offset, length);
builder.endObject();
}
}

View File

@ -21,39 +21,41 @@ package org.elasticsearch.index.query;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.search.internal.SearchContext;
import java.io.IOException;
/**
* Query parser for JSON Queries.
*
* @author Cedric Champeau
*/
public class JSONQueryParser implements QueryParser {
public class WrapperQueryParser implements QueryParser {
public static final String NAME = "json";
public static final String NAME = "wrapper";
@Inject public JSONQueryParser() {
@Inject public WrapperQueryParser() {
}
@Override public String[] names() {
return new String[] {NAME};
return new String[]{NAME};
}
@Override public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
System.out.println("parseContext = " + parseContext);
XContentParser parser = parseContext.parser();
XContentParser.Token token;
Query query = null;
String currentFieldName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token == XContentParser.Token.START_OBJECT && "value".equals(currentFieldName)) {
query = parseContext.parseInnerQuery();
XContentParser.Token token = parser.nextToken();
assert token == XContentParser.Token.FIELD_NAME;
String fieldName = parser.currentName();
assert fieldName.equals("query");
parser.nextToken();
byte[] querySource = parser.binaryValue();
XContentParser qSourceParser = XContentFactory.xContent(querySource).createParser(querySource);
try {
return SearchContext.current().queryParserService().parse(qSourceParser).query();
} finally {
qSourceParser.close();
}
}
return query;
}
}

View File

@ -67,7 +67,7 @@ public class IndicesQueriesRegistry {
addQueryParser(queryParsers, new MoreLikeThisFieldQueryParser());
addQueryParser(queryParsers, new FuzzyLikeThisQueryParser());
addQueryParser(queryParsers, new FuzzyLikeThisFieldQueryParser());
addQueryParser(queryParsers, new JSONQueryParser());
addQueryParser(queryParsers, new WrapperQueryParser());
this.queryParsers = ImmutableMap.copyOf(queryParsers);
Map<String, FilterParser> filterParsers = Maps.newHashMap();

View File

@ -23,8 +23,8 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.JSONQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.WrapperQueryBuilder;
import org.elasticsearch.test.integration.AbstractNodesTests;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@ -291,15 +291,15 @@ public class SimpleQueryTests extends AbstractNodesTests {
client.prepareIndex("test", "type1", "1").setSource("field1", "value1_1", "field2", "value2_1").setRefresh(true).execute().actionGet();
JSONQueryBuilder json = new JSONQueryBuilder("{ \"term\" : { \"field1\" : \"value1_1\" } }");
SearchResponse searchResponse = client.prepareSearch().setQuery(json).execute().actionGet();
WrapperQueryBuilder wrapper = new WrapperQueryBuilder("{ \"term\" : { \"field1\" : \"value1_1\" } }");
SearchResponse searchResponse = client.prepareSearch().setQuery(wrapper).execute().actionGet();
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
BoolQueryBuilder bool = new BoolQueryBuilder();
bool.must(json);
bool.must(wrapper);
bool.must(new TermQueryBuilder("field2", "value2_1"));
searchResponse = client.prepareSearch().setQuery(json).execute().actionGet();
searchResponse = client.prepareSearch().setQuery(wrapper).execute().actionGet();
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
}