Skip to content

Commit 359cfd0

Browse files
committed
Refactors ScriptQueryBuilder and Parser
Relates to elastic#10217 Closes elastic#12115 This PR is against the query-refactoring branch.
1 parent 7281f01 commit 359cfd0

File tree

3 files changed

+197
-101
lines changed

3 files changed

+197
-101
lines changed

core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java

Lines changed: 128 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,44 @@
1919

2020
package org.elasticsearch.index.query;
2121

22+
import org.apache.lucene.index.LeafReaderContext;
23+
import org.apache.lucene.search.IndexSearcher;
24+
import org.apache.lucene.search.Query;
25+
import org.apache.lucene.search.RandomAccessWeight;
26+
import org.apache.lucene.search.Weight;
27+
import org.apache.lucene.util.Bits;
28+
import org.elasticsearch.common.Strings;
29+
import org.elasticsearch.common.io.stream.StreamInput;
30+
import org.elasticsearch.common.io.stream.StreamOutput;
2231
import org.elasticsearch.common.xcontent.XContentBuilder;
23-
import org.elasticsearch.script.Script;
32+
import org.elasticsearch.script.*;
2433
import org.elasticsearch.script.Script.ScriptField;
34+
import org.elasticsearch.search.lookup.SearchLookup;
2535

2636
import java.io.IOException;
37+
import java.util.Objects;
2738

2839
public class ScriptQueryBuilder extends AbstractQueryBuilder<ScriptQueryBuilder> {
2940

3041
public static final String NAME = "script";
3142

32-
static final ScriptQueryBuilder PROTOTYPE = new ScriptQueryBuilder((Script) null);
33-
34-
private Script script;
43+
static final ScriptQueryBuilder PROTOTYPE = new ScriptQueryBuilder(null);
3544

45+
private final Script script;
46+
3647
public ScriptQueryBuilder(Script script) {
3748
this.script = script;
3849
}
3950

51+
public Script script() {
52+
return this.script;
53+
}
54+
55+
@Override
56+
public String getName() {
57+
return NAME;
58+
}
59+
4060
@Override
4161
protected void doXContent(XContentBuilder builder, Params builderParams) throws IOException {
4262
builder.startObject(NAME);
@@ -46,7 +66,109 @@ protected void doXContent(XContentBuilder builder, Params builderParams) throws
4666
}
4767

4868
@Override
49-
public String getName() {
50-
return NAME;
69+
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
70+
return new ScriptQuery(script, parseContext.scriptService(), parseContext.lookup());
71+
}
72+
73+
@Override
74+
public QueryValidationException validate() {
75+
QueryValidationException validationException = null;
76+
if (this.script == null) {
77+
validationException = addValidationError("script cannot be null", validationException);
78+
}
79+
return validationException;
80+
}
81+
82+
static class ScriptQuery extends Query {
83+
84+
private final Script script;
85+
86+
private final SearchScript searchScript;
87+
88+
public ScriptQuery(Script script, ScriptService scriptService, SearchLookup searchLookup) {
89+
this.script = script;
90+
this.searchScript = scriptService.search(searchLookup, script, ScriptContext.Standard.SEARCH);
91+
}
92+
93+
@Override
94+
public String toString(String field) {
95+
StringBuilder buffer = new StringBuilder();
96+
buffer.append("ScriptFilter(");
97+
buffer.append(script);
98+
buffer.append(")");
99+
return buffer.toString();
100+
}
101+
102+
@Override
103+
public boolean equals(Object obj) {
104+
if (this == obj)
105+
return true;
106+
if (!super.equals(obj))
107+
return false;
108+
ScriptQuery other = (ScriptQuery) obj;
109+
return Objects.equals(script, other.script);
110+
}
111+
112+
@Override
113+
public int hashCode() {
114+
final int prime = 31;
115+
int result = super.hashCode();
116+
result = prime * result + Objects.hashCode(script);
117+
return result;
118+
}
119+
120+
@Override
121+
public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
122+
return new RandomAccessWeight(this) {
123+
@Override
124+
protected Bits getMatchingDocs(final LeafReaderContext context) throws IOException {
125+
final LeafSearchScript leafScript = searchScript.getLeafSearchScript(context);
126+
return new Bits() {
127+
128+
@Override
129+
public boolean get(int doc) {
130+
leafScript.setDocument(doc);
131+
Object val = leafScript.run();
132+
if (val == null) {
133+
return false;
134+
}
135+
if (val instanceof Boolean) {
136+
return (Boolean) val;
137+
}
138+
if (val instanceof Number) {
139+
return ((Number) val).longValue() != 0;
140+
}
141+
throw new IllegalArgumentException("Can't handle type [" + val + "] in script filter");
142+
}
143+
144+
@Override
145+
public int length() {
146+
return context.reader().maxDoc();
147+
}
148+
149+
};
150+
}
151+
};
152+
}
153+
}
154+
155+
@Override
156+
protected ScriptQueryBuilder doReadFrom(StreamInput in) throws IOException {
157+
return new ScriptQueryBuilder(Script.readScript(in));
158+
}
159+
160+
@Override
161+
protected void doWriteTo(StreamOutput out) throws IOException {
162+
script.writeTo(out);
163+
}
164+
165+
@Override
166+
protected int doHashCode() {
167+
return Objects.hash(script);
168+
}
169+
170+
@Override
171+
protected boolean doEquals(ScriptQueryBuilder other) {
172+
return Objects.equals(script, other.script);
51173
}
52174
}

core/src/main/java/org/elasticsearch/index/query/ScriptQueryParser.java

Lines changed: 10 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,12 @@
1919

2020
package org.elasticsearch.index.query;
2121

22-
import com.google.common.base.Objects;
23-
import org.apache.lucene.index.LeafReaderContext;
24-
import org.apache.lucene.search.IndexSearcher;
25-
import org.apache.lucene.search.Query;
26-
import org.apache.lucene.search.RandomAccessWeight;
27-
import org.apache.lucene.search.Weight;
28-
import org.apache.lucene.util.Bits;
29-
import org.elasticsearch.common.ParseField;
3022
import org.elasticsearch.common.inject.Inject;
3123
import org.elasticsearch.common.xcontent.XContentParser;
32-
import org.elasticsearch.script.*;
24+
import org.elasticsearch.script.Script;
3325
import org.elasticsearch.script.Script.ScriptField;
26+
import org.elasticsearch.script.ScriptParameterParser;
3427
import org.elasticsearch.script.ScriptParameterParser.ScriptParameterValue;
35-
import org.elasticsearch.search.lookup.SearchLookup;
3628

3729
import java.io.IOException;
3830
import java.util.Map;
@@ -42,7 +34,7 @@
4234
/**
4335
*
4436
*/
45-
public class ScriptQueryParser extends BaseQueryParserTemp {
37+
public class ScriptQueryParser extends BaseQueryParser {
4638

4739
@Inject
4840
public ScriptQueryParser() {
@@ -54,20 +46,19 @@ public String[] names() {
5446
}
5547

5648
@Override
57-
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
49+
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
5850
XContentParser parser = parseContext.parser();
5951
ScriptParameterParser scriptParameterParser = new ScriptParameterParser();
60-
61-
XContentParser.Token token;
62-
52+
6353
// also, when caching, since its isCacheable is false, will result in loading all bit set...
6454
Script script = null;
6555
Map<String, Object> params = null;
6656

6757
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
6858
String queryName = null;
69-
String currentFieldName = null;
7059

60+
XContentParser.Token token;
61+
String currentFieldName = null;
7162
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
7263
if (token == XContentParser.Token.FIELD_NAME) {
7364
currentFieldName = parser.currentName();
@@ -108,85 +99,9 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
10899
throw new QueryParsingException(parseContext, "script must be provided with a [script] filter");
109100
}
110101

111-
Query query = new ScriptQuery(script, parseContext.scriptService(), parseContext.lookup());
112-
if (queryName != null) {
113-
parseContext.addNamedQuery(queryName, query);
114-
}
115-
query.setBoost(boost);
116-
return query;
117-
}
118-
119-
static class ScriptQuery extends Query {
120-
121-
private final Script script;
122-
123-
private final SearchScript searchScript;
124-
125-
public ScriptQuery(Script script, ScriptService scriptService, SearchLookup searchLookup) {
126-
this.script = script;
127-
this.searchScript = scriptService.search(searchLookup, script, ScriptContext.Standard.SEARCH);
128-
}
129-
130-
@Override
131-
public String toString(String field) {
132-
StringBuilder buffer = new StringBuilder();
133-
buffer.append("ScriptFilter(");
134-
buffer.append(script);
135-
buffer.append(")");
136-
return buffer.toString();
137-
}
138-
139-
@Override
140-
public boolean equals(Object obj) {
141-
if (this == obj)
142-
return true;
143-
if (!super.equals(obj))
144-
return false;
145-
ScriptQuery other = (ScriptQuery) obj;
146-
return Objects.equal(script, other.script);
147-
}
148-
149-
@Override
150-
public int hashCode() {
151-
final int prime = 31;
152-
int result = super.hashCode();
153-
result = prime * result + Objects.hashCode(script);
154-
return result;
155-
}
156-
157-
@Override
158-
public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
159-
return new RandomAccessWeight(this) {
160-
@Override
161-
protected Bits getMatchingDocs(final LeafReaderContext context) throws IOException {
162-
final LeafSearchScript leafScript = searchScript.getLeafSearchScript(context);
163-
return new Bits() {
164-
165-
@Override
166-
public boolean get(int doc) {
167-
leafScript.setDocument(doc);
168-
Object val = leafScript.run();
169-
if (val == null) {
170-
return false;
171-
}
172-
if (val instanceof Boolean) {
173-
return (Boolean) val;
174-
}
175-
if (val instanceof Number) {
176-
return ((Number) val).longValue() != 0;
177-
}
178-
throw new IllegalArgumentException("Can't handle type [" + val + "] in script filter");
179-
}
180-
181-
@Override
182-
public int length() {
183-
return context.reader().maxDoc();
184-
}
185-
186-
};
187-
}
188-
};
189-
}
102+
return new ScriptQueryBuilder(script)
103+
.boost(boost)
104+
.queryName(queryName);
190105
}
191106

192107
@Override
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.index.query;
21+
22+
import org.apache.lucene.search.Query;
23+
import org.elasticsearch.script.Script;
24+
import org.elasticsearch.script.ScriptService.ScriptType;
25+
import org.junit.Test;
26+
27+
import java.io.IOException;
28+
import java.util.HashMap;
29+
import java.util.Map;
30+
31+
import static org.hamcrest.Matchers.is;
32+
33+
public class ScriptQueryBuilderTest extends BaseQueryTestCase<ScriptQueryBuilder> {
34+
35+
@Override
36+
protected ScriptQueryBuilder doCreateTestQueryBuilder() {
37+
String script;
38+
Map<String, Object> params = null;
39+
if (randomBoolean()) {
40+
script = "5 * 2 > param";
41+
params = new HashMap<>();
42+
params.put("param", 1);
43+
} else {
44+
script = "5 * 2 > 2";
45+
}
46+
return new ScriptQueryBuilder(new Script(script, ScriptType.INLINE, "expression", params));
47+
}
48+
49+
@Override
50+
protected Query doCreateExpectedQuery(ScriptQueryBuilder queryBuilder, QueryParseContext context) throws IOException {
51+
return new ScriptQueryBuilder.ScriptQuery(queryBuilder.script(), context.scriptService(), context.lookup());
52+
}
53+
54+
@Test
55+
public void testValidate() {
56+
ScriptQueryBuilder scriptQueryBuilder = new ScriptQueryBuilder(null);
57+
assertThat(scriptQueryBuilder.validate().validationErrors().size(), is(1));
58+
}
59+
}

0 commit comments

Comments
 (0)