Skip to content

Commit 4cbb21f

Browse files
committed
Support 'string'-style queries on metadata fields when reasonable. (#34089)
* Make sure 'ignored' and 'routing' field types inherit from StringFieldType. * Add tests for prefix and regexp queries. * Support prefix and regexp queries on _index fields.
1 parent 9454c6a commit 4cbb21f

File tree

6 files changed

+148
-8
lines changed

6 files changed

+148
-8
lines changed

server/src/main/java/org/elasticsearch/index/mapper/IgnoredFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext c
8585
}
8686
}
8787

88-
public static final class IgnoredFieldType extends TermBasedFieldType {
88+
public static final class IgnoredFieldType extends StringFieldType {
8989

9090
public IgnoredFieldType() {
9191
}

server/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.io.IOException;
4040
import java.util.List;
4141
import java.util.Map;
42+
import java.util.regex.Pattern;
4243

4344

4445
public class IndexFieldMapper extends MetadataFieldMapper {
@@ -155,14 +156,43 @@ public Query termsQuery(List values, QueryShardContext context) {
155156
+ " vs. " + values);
156157
}
157158

159+
@Override
160+
public Query prefixQuery(String value,
161+
@Nullable MultiTermQuery.RewriteMethod method,
162+
QueryShardContext context) {
163+
String indexName = context.getFullyQualifiedIndex().getName();
164+
if (indexName.startsWith(value)) {
165+
return Queries.newMatchAllQuery();
166+
} else {
167+
return Queries.newMatchNoDocsQuery("The index [" + indexName +
168+
"] doesn't match the provided prefix [" + value + "].");
169+
}
170+
}
171+
172+
@Override
173+
public Query regexpQuery(String value, int flags, int maxDeterminizedStates,
174+
MultiTermQuery.RewriteMethod method, QueryShardContext context) {
175+
String indexName = context.getFullyQualifiedIndex().getName();
176+
Pattern pattern = Regex.compile(value, Regex.flagsToString(flags));
177+
178+
if (pattern.matcher(indexName).matches()) {
179+
return Queries.newMatchAllQuery();
180+
} else {
181+
return Queries.newMatchNoDocsQuery("The index [" + indexName +
182+
"] doesn't match the provided pattern [" + value + "].");
183+
}
184+
}
185+
158186
@Override
159187
public Query wildcardQuery(String value,
160188
@Nullable MultiTermQuery.RewriteMethod method,
161189
QueryShardContext context) {
162-
if (isSameIndex(value, context.getFullyQualifiedIndex().getName())) {
190+
String indexName = context.getFullyQualifiedIndex().getName();
191+
if (isSameIndex(value, indexName)) {
163192
return Queries.newMatchAllQuery();
164193
} else {
165-
return Queries.newMatchNoDocsQuery("Index didn't match. Index queried: " + context.index().getName() + " vs. " + value);
194+
return Queries.newMatchNoDocsQuery("The index [" + indexName +
195+
"] doesn't match the provided pattern [" + value + "].");
166196
}
167197
}
168198

server/src/main/java/org/elasticsearch/index/mapper/RoutingFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext c
107107
}
108108
}
109109

110-
static final class RoutingFieldType extends TermBasedFieldType {
110+
static final class RoutingFieldType extends StringFieldType {
111111

112112
RoutingFieldType() {
113113
}

server/src/test/java/org/elasticsearch/index/mapper/IgnoredFieldTypeTests.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,45 @@
1919

2020
package org.elasticsearch.index.mapper;
2121

22+
import org.apache.lucene.index.IndexOptions;
23+
import org.apache.lucene.index.Term;
24+
import org.apache.lucene.search.PrefixQuery;
25+
import org.apache.lucene.search.Query;
26+
import org.apache.lucene.search.RegexpQuery;
27+
import org.apache.lucene.search.WildcardQuery;
28+
import org.apache.lucene.util.BytesRef;
29+
2230
public class IgnoredFieldTypeTests extends FieldTypeTestCase {
2331

2432
@Override
2533
protected MappedFieldType createDefaultFieldType() {
2634
return new IgnoredFieldMapper.IgnoredFieldType();
2735
}
2836

37+
public void testPrefixQuery() {
38+
MappedFieldType ft = createDefaultFieldType();
39+
ft.setName("field");
40+
ft.setIndexOptions(IndexOptions.DOCS);
41+
42+
Query expected = new PrefixQuery(new Term("field", new BytesRef("foo*")));
43+
assertEquals(expected, ft.prefixQuery("foo*", null, null));
44+
}
45+
46+
public void testRegexpQuery() {
47+
MappedFieldType ft = createDefaultFieldType();
48+
ft.setName("field");
49+
ft.setIndexOptions(IndexOptions.DOCS);
50+
51+
Query expected = new RegexpQuery(new Term("field", new BytesRef("foo?")));
52+
assertEquals(expected, ft.regexpQuery("foo?", 0, 10, null, null));
53+
}
54+
55+
public void testWildcardQuery() {
56+
MappedFieldType ft = createDefaultFieldType();
57+
ft.setName("field");
58+
ft.setIndexOptions(IndexOptions.DOCS);
59+
60+
Query expected = new WildcardQuery(new Term("field", new BytesRef("foo*")));
61+
assertEquals(expected, ft.wildcardQuery("foo*", null, null));
62+
}
2963
}

server/src/test/java/org/elasticsearch/index/mapper/IndexFieldTypeTests.java

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,56 @@
1818
*/
1919
package org.elasticsearch.index.mapper;
2020

21-
import org.elasticsearch.index.mapper.IndexFieldMapper;
22-
import org.elasticsearch.index.mapper.MappedFieldType;
21+
import org.apache.lucene.index.IndexOptions;
22+
import org.apache.lucene.search.MatchAllDocsQuery;
23+
import org.apache.lucene.search.MatchNoDocsQuery;
24+
import org.elasticsearch.index.Index;
25+
import org.elasticsearch.index.query.QueryShardContext;
26+
27+
import static org.mockito.Mockito.mock;
28+
import static org.mockito.Mockito.when;
2329

2430
public class IndexFieldTypeTests extends FieldTypeTestCase {
31+
2532
@Override
2633
protected MappedFieldType createDefaultFieldType() {
2734
return new IndexFieldMapper.IndexFieldType();
2835
}
36+
37+
public void testPrefixQuery() {
38+
MappedFieldType ft = createDefaultFieldType();
39+
ft.setName("field");
40+
ft.setIndexOptions(IndexOptions.DOCS);
41+
42+
assertEquals(new MatchAllDocsQuery(), ft.prefixQuery("ind", null, createContext()));
43+
assertEquals(new MatchNoDocsQuery(), ft.prefixQuery("other_ind", null, createContext()));
44+
}
45+
46+
public void testRegexpQuery() {
47+
MappedFieldType ft = createDefaultFieldType();
48+
ft.setName("field");
49+
ft.setIndexOptions(IndexOptions.DOCS);
50+
51+
assertEquals(new MatchAllDocsQuery(), ft.regexpQuery("ind.x", 0, 10, null, createContext()));
52+
assertEquals(new MatchNoDocsQuery(), ft.regexpQuery("ind?x", 0, 10, null, createContext()));
53+
}
54+
55+
public void testWildcardQuery() {
56+
MappedFieldType ft = createDefaultFieldType();
57+
ft.setName("field");
58+
ft.setIndexOptions(IndexOptions.DOCS);
59+
60+
assertEquals(new MatchAllDocsQuery(), ft.wildcardQuery("ind*x", null, createContext()));
61+
assertEquals(new MatchNoDocsQuery(), ft.wildcardQuery("other_ind*x", null, createContext()));
62+
}
63+
64+
private QueryShardContext createContext() {
65+
QueryShardContext context = mock(QueryShardContext.class);
66+
67+
Index index = new Index("index", "123");
68+
when(context.getFullyQualifiedIndex()).thenReturn(index);
69+
when(context.index()).thenReturn(index);
70+
71+
return context;
72+
}
2973
}

server/src/test/java/org/elasticsearch/index/mapper/RoutingFieldTypeTests.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,44 @@
1818
*/
1919
package org.elasticsearch.index.mapper;
2020

21-
import org.elasticsearch.index.mapper.MappedFieldType;
22-
import org.elasticsearch.index.mapper.RoutingFieldMapper;
21+
import org.apache.lucene.index.IndexOptions;
22+
import org.apache.lucene.index.Term;
23+
import org.apache.lucene.search.PrefixQuery;
24+
import org.apache.lucene.search.Query;
25+
import org.apache.lucene.search.RegexpQuery;
26+
import org.apache.lucene.search.WildcardQuery;
27+
import org.apache.lucene.util.BytesRef;
2328

2429
public class RoutingFieldTypeTests extends FieldTypeTestCase {
2530
@Override
2631
protected MappedFieldType createDefaultFieldType() {
2732
return new RoutingFieldMapper.RoutingFieldType();
2833
}
34+
35+
public void testPrefixQuery() {
36+
MappedFieldType ft = createDefaultFieldType();
37+
ft.setName("field");
38+
ft.setIndexOptions(IndexOptions.DOCS);
39+
40+
Query expected = new PrefixQuery(new Term("field", new BytesRef("foo*")));
41+
assertEquals(expected, ft.prefixQuery("foo*", null, null));
42+
}
43+
44+
public void testRegexpQuery() {
45+
MappedFieldType ft = createDefaultFieldType();
46+
ft.setName("field");
47+
ft.setIndexOptions(IndexOptions.DOCS);
48+
49+
Query expected = new RegexpQuery(new Term("field", new BytesRef("foo?")));
50+
assertEquals(expected, ft.regexpQuery("foo?", 0, 10, null, null));
51+
}
52+
53+
public void testWildcardQuery() {
54+
MappedFieldType ft = createDefaultFieldType();
55+
ft.setName("field");
56+
ft.setIndexOptions(IndexOptions.DOCS);
57+
58+
Query expected = new WildcardQuery(new Term("field", new BytesRef("foo*")));
59+
assertEquals(expected, ft.wildcardQuery("foo*", null, null));
60+
}
2961
}

0 commit comments

Comments
 (0)