Skip to content

Commit 4345a82

Browse files
committed
Query DSL: Ids Filter / Query - allow to execute it with no type defined / several types, closes elastic#969.
1 parent 163e32b commit 4345a82

File tree

9 files changed

+110
-41
lines changed

9 files changed

+110
-41
lines changed

modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/MapperService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import java.io.Reader;
5555
import java.net.MalformedURLException;
5656
import java.net.URL;
57+
import java.util.Collection;
5758
import java.util.Map;
5859
import java.util.Set;
5960

@@ -234,6 +235,10 @@ public boolean hasMapping(String mappingType) {
234235
return mappers.containsKey(mappingType);
235236
}
236237

238+
public Collection<String> types() {
239+
return mappers.keySet();
240+
}
241+
237242
public DocumentMapper documentMapper(String type) {
238243
return mappers.get(type);
239244
}

modules/elasticsearch/src/main/java/org/elasticsearch/index/query/xcontent/FilterBuilders.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
package org.elasticsearch.index.query.xcontent;
2121

22+
import org.elasticsearch.common.Nullable;
23+
2224
/**
2325
* A static factory for simple "import static" usage.
2426
*
@@ -34,12 +36,12 @@ public static MatchAllFilterBuilder matchAllFilter() {
3436
}
3537

3638
/**
37-
* Creates a new ids filter with the provided doc/mapping type.
39+
* Creates a new ids filter with the provided doc/mapping types.
3840
*
39-
* @param type The type
41+
* @param types The types to match the ids against.
4042
*/
41-
public static IdsFilterBuilder idsFilter(String type) {
42-
return new IdsFilterBuilder(type);
43+
public static IdsFilterBuilder idsFilter(@Nullable String... types) {
44+
return new IdsFilterBuilder(types);
4345
}
4446

4547
/**

modules/elasticsearch/src/main/java/org/elasticsearch/index/query/xcontent/IdsFilterBuilder.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
*/
3232
public class IdsFilterBuilder extends BaseFilterBuilder {
3333

34-
private String type;
34+
private final List<String> types;
3535

3636
private List<String> values = new ArrayList<String>();
3737

@@ -40,8 +40,8 @@ public class IdsFilterBuilder extends BaseFilterBuilder {
4040
/**
4141
* Create an ids filter based on the type.
4242
*/
43-
public IdsFilterBuilder(String type) {
44-
this.type = type;
43+
public IdsFilterBuilder(String... types) {
44+
this.types = types == null ? null : Arrays.asList(types);
4545
}
4646

4747
/**
@@ -69,7 +69,17 @@ public IdsFilterBuilder filterName(String filterName) {
6969

7070
@Override public void doXContent(XContentBuilder builder, Params params) throws IOException {
7171
builder.startObject(IdsFilterParser.NAME);
72-
builder.field("type", type);
72+
if (types != null) {
73+
if (types.size() == 1) {
74+
builder.field("type", types.get(0));
75+
} else {
76+
builder.startArray("types");
77+
for (Object type : types) {
78+
builder.value(type);
79+
}
80+
builder.endArray();
81+
}
82+
}
7383
builder.startArray("values");
7484
for (Object value : values) {
7585
builder.value(value);

modules/elasticsearch/src/main/java/org/elasticsearch/index/query/xcontent/IdsFilterParser.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
package org.elasticsearch.index.query.xcontent;
2121

2222
import org.apache.lucene.search.Filter;
23+
import org.elasticsearch.common.collect.ImmutableList;
24+
import org.elasticsearch.common.collect.Iterables;
2325
import org.elasticsearch.common.inject.Inject;
2426
import org.elasticsearch.common.settings.Settings;
2527
import org.elasticsearch.common.xcontent.XContentParser;
@@ -31,6 +33,7 @@
3133

3234
import java.io.IOException;
3335
import java.util.ArrayList;
36+
import java.util.Collection;
3437
import java.util.List;
3538

3639
public class IdsFilterParser extends AbstractIndexComponent implements XContentFilterParser {
@@ -49,7 +52,7 @@ public class IdsFilterParser extends AbstractIndexComponent implements XContentF
4952
XContentParser parser = parseContext.parser();
5053

5154
List<String> ids = new ArrayList<String>();
52-
String type = null;
55+
Collection<String> types = null;
5356
String filterName = null;
5457
String currentFieldName = null;
5558
XContentParser.Token token;
@@ -65,24 +68,36 @@ public class IdsFilterParser extends AbstractIndexComponent implements XContentF
6568
}
6669
ids.add(value);
6770
}
71+
} else if ("types".equals(currentFieldName) || "type".equals(currentFieldName)) {
72+
types = new ArrayList<String>();
73+
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
74+
String value = parser.textOrNull();
75+
if (value == null) {
76+
throw new QueryParsingException(index, "No type specified for term filter");
77+
}
78+
types.add(value);
79+
}
6880
}
6981
} else if (token.isValue()) {
7082
if ("type".equals(currentFieldName) || "_type".equals(currentFieldName)) {
71-
type = parser.text();
83+
types = ImmutableList.of(parser.text());
7284
} else if ("_name".equals(currentFieldName)) {
7385
filterName = parser.text();
7486
}
7587
}
7688
}
7789

78-
if (type == null) {
79-
throw new QueryParsingException(index, "[ids] filter, no type provided");
80-
}
8190
if (ids.size() == 0) {
8291
throw new QueryParsingException(index, "[ids] filter, no ids values provided");
8392
}
8493

85-
UidFilter filter = new UidFilter(type, ids, parseContext.indexCache().bloomCache());
94+
if (types == null || types.isEmpty()) {
95+
types = parseContext.mapperService().types();
96+
} else if (types.size() == 1 && Iterables.getFirst(types, null).equals("_all")) {
97+
types = parseContext.mapperService().types();
98+
}
99+
100+
UidFilter filter = new UidFilter(types, ids, parseContext.indexCache().bloomCache());
86101
if (filterName != null) {
87102
parseContext.addNamedFilter(filterName, filter);
88103
}

modules/elasticsearch/src/main/java/org/elasticsearch/index/query/xcontent/IdsQueryBuilder.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@
3131
*/
3232
public class IdsQueryBuilder extends BaseQueryBuilder {
3333

34-
private String type;
34+
private final List<String> types;
3535

3636
private List<String> values = new ArrayList<String>();
3737

3838
private float boost = -1;
3939

40-
public IdsQueryBuilder(String type) {
41-
this.type = type;
40+
public IdsQueryBuilder(String... types) {
41+
this.types = types == null ? null : Arrays.asList(types);
4242
}
4343

4444
/**
@@ -67,7 +67,17 @@ public IdsQueryBuilder boost(float boost) {
6767

6868
@Override protected void doXContent(XContentBuilder builder, Params params) throws IOException {
6969
builder.startObject(IdsQueryParser.NAME);
70-
builder.field("type", type);
70+
if (types != null) {
71+
if (types.size() == 1) {
72+
builder.field("type", types.get(0));
73+
} else {
74+
builder.startArray("types");
75+
for (Object type : types) {
76+
builder.value(type);
77+
}
78+
builder.endArray();
79+
}
80+
}
7181
builder.startArray("values");
7282
for (Object value : values) {
7383
builder.value(value);

modules/elasticsearch/src/main/java/org/elasticsearch/index/query/xcontent/IdsQueryParser.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
import org.apache.lucene.search.ConstantScoreQuery;
2323
import org.apache.lucene.search.Query;
24+
import org.elasticsearch.common.collect.ImmutableList;
25+
import org.elasticsearch.common.collect.Iterables;
2426
import org.elasticsearch.common.inject.Inject;
2527
import org.elasticsearch.common.settings.Settings;
2628
import org.elasticsearch.common.xcontent.XContentParser;
@@ -32,6 +34,7 @@
3234

3335
import java.io.IOException;
3436
import java.util.ArrayList;
37+
import java.util.Collection;
3538
import java.util.List;
3639

3740
/**
@@ -53,7 +56,7 @@ public class IdsQueryParser extends AbstractIndexComponent implements XContentQu
5356
XContentParser parser = parseContext.parser();
5457

5558
List<String> ids = new ArrayList<String>();
56-
String type = null;
59+
Collection<String> types = null;
5760
String currentFieldName = null;
5861
float boost = 1.0f;
5962
XContentParser.Token token;
@@ -69,24 +72,36 @@ public class IdsQueryParser extends AbstractIndexComponent implements XContentQu
6972
}
7073
ids.add(value);
7174
}
75+
} else if ("types".equals(currentFieldName) || "type".equals(currentFieldName)) {
76+
types = new ArrayList<String>();
77+
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
78+
String value = parser.textOrNull();
79+
if (value == null) {
80+
throw new QueryParsingException(index, "No type specified for term filter");
81+
}
82+
types.add(value);
83+
}
7284
}
7385
} else if (token.isValue()) {
7486
if ("type".equals(currentFieldName) || "_type".equals(currentFieldName)) {
75-
type = parser.text();
87+
types = ImmutableList.of(parser.text());
7688
} else if ("boost".equals(currentFieldName)) {
7789
boost = parser.floatValue();
7890
}
7991
}
8092
}
8193

82-
if (type == null) {
83-
throw new QueryParsingException(index, "[ids] query, no type provided");
84-
}
8594
if (ids.size() == 0) {
8695
throw new QueryParsingException(index, "[ids] query, no ids values provided");
8796
}
8897

89-
UidFilter filter = new UidFilter(type, ids, parseContext.indexCache().bloomCache());
98+
if (types == null || types.isEmpty()) {
99+
types = parseContext.mapperService().types();
100+
} else if (types.size() == 1 && Iterables.getFirst(types, null).equals("_all")) {
101+
types = parseContext.mapperService().types();
102+
}
103+
104+
UidFilter filter = new UidFilter(types, ids, parseContext.indexCache().bloomCache());
90105
// no need for constant score filter, since we don't cache the filter, and it always takes deletes into account
91106
ConstantScoreQuery query = new ConstantScoreQuery(filter);
92107
query.setBoost(boost);

modules/elasticsearch/src/main/java/org/elasticsearch/index/query/xcontent/QueryBuilders.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
package org.elasticsearch.index.query.xcontent;
2121

22+
import org.elasticsearch.common.Nullable;
23+
2224
/**
2325
* A static factory for simple "import static" usage.
2426
*
@@ -73,12 +75,12 @@ public static DisMaxQueryBuilder disMaxQuery() {
7375
}
7476

7577
/**
76-
* Constructs a query that will match only specific ids within a type.
78+
* Constructs a query that will match only specific ids within types.
7779
*
78-
* @param type The mapping/doc type
80+
* @param types The mapping/doc type
7981
*/
80-
public static IdsQueryBuilder idsQuery(String type) {
81-
return new IdsQueryBuilder(type);
82+
public static IdsQueryBuilder idsQuery(@Nullable String... types) {
83+
return new IdsQueryBuilder(types);
8284
}
8385

8486
/**

modules/elasticsearch/src/main/java/org/elasticsearch/index/search/UidFilter.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,24 @@
3333
import org.elasticsearch.index.mapper.UidFieldMapper;
3434

3535
import java.io.IOException;
36-
import java.util.Arrays;
36+
import java.util.ArrayList;
37+
import java.util.Collection;
3738
import java.util.List;
3839

3940
public class UidFilter extends Filter {
4041

41-
private final Term[] uids;
42+
private final List<Term> uids;
4243

4344
private final BloomCache bloomCache;
4445

45-
public UidFilter(String type, List<String> ids, BloomCache bloomCache) {
46+
public UidFilter(Collection<String> types, List<String> ids, BloomCache bloomCache) {
4647
this.bloomCache = bloomCache;
47-
uids = new Term[ids.size()];
48-
for (int i = 0; i < ids.size(); i++) {
49-
uids[i] = new Term(UidFieldMapper.NAME, Uid.createUid(type, ids.get(i)));
48+
this.uids = new ArrayList<Term>(types.size() * ids.size());
49+
for (String type : types) {
50+
for (String id : ids) {
51+
uids.add(new Term(UidFieldMapper.NAME, Uid.createUid(type, id)));
52+
}
5053
}
51-
Arrays.sort(uids);
5254
}
5355

5456
// TODO Optimizations
@@ -86,15 +88,11 @@ public UidFilter(String type, List<String> ids, BloomCache bloomCache) {
8688
@Override public boolean equals(Object o) {
8789
if (this == o) return true;
8890
if (o == null || getClass() != o.getClass()) return false;
89-
9091
UidFilter uidFilter = (UidFilter) o;
91-
92-
if (!Arrays.equals(uids, uidFilter.uids)) return false;
93-
94-
return true;
92+
return !uids.equals(uidFilter.uids);
9593
}
9694

9795
@Override public int hashCode() {
98-
return uids != null ? Arrays.hashCode(uids) : 0;
96+
return uids.hashCode();
9997
}
10098
}

modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/query/SimpleQueryTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,23 @@ private void idsFilterTests(String index) throws Exception {
174174
assertThat(searchResponse.hits().getAt(0).id(), anyOf(equalTo("1"), equalTo("3")));
175175
assertThat(searchResponse.hits().getAt(1).id(), anyOf(equalTo("1"), equalTo("3")));
176176

177+
// no type
178+
searchResponse = client.prepareSearch().setQuery(constantScoreQuery(idsFilter().ids("1", "3"))).execute().actionGet();
179+
assertThat(searchResponse.hits().totalHits(), equalTo(2l));
180+
assertThat(searchResponse.hits().getAt(0).id(), anyOf(equalTo("1"), equalTo("3")));
181+
assertThat(searchResponse.hits().getAt(1).id(), anyOf(equalTo("1"), equalTo("3")));
182+
177183
searchResponse = client.prepareSearch().setQuery(idsQuery("type1").ids("1", "3")).execute().actionGet();
178184
assertThat(searchResponse.hits().totalHits(), equalTo(2l));
179185
assertThat(searchResponse.hits().getAt(0).id(), anyOf(equalTo("1"), equalTo("3")));
180186
assertThat(searchResponse.hits().getAt(1).id(), anyOf(equalTo("1"), equalTo("3")));
181187

188+
// no type
189+
searchResponse = client.prepareSearch().setQuery(idsQuery().ids("1", "3")).execute().actionGet();
190+
assertThat(searchResponse.hits().totalHits(), equalTo(2l));
191+
assertThat(searchResponse.hits().getAt(0).id(), anyOf(equalTo("1"), equalTo("3")));
192+
assertThat(searchResponse.hits().getAt(1).id(), anyOf(equalTo("1"), equalTo("3")));
193+
182194
searchResponse = client.prepareSearch().setQuery(idsQuery("type1").ids("7", "10")).execute().actionGet();
183195
assertThat(searchResponse.hits().totalHits(), equalTo(0l));
184196
}

0 commit comments

Comments
 (0)