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.
This commit is contained in:
Julie Tibshirani 2018-09-27 20:59:03 -07:00 committed by GitHub
parent 33a264a408
commit 9cd4f70a67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 148 additions and 8 deletions

View File

@ -85,7 +85,7 @@ public final class IgnoredFieldMapper extends MetadataFieldMapper {
} }
} }
public static final class IgnoredFieldType extends TermBasedFieldType { public static final class IgnoredFieldType extends StringFieldType {
public IgnoredFieldType() { public IgnoredFieldType() {
} }

View File

@ -38,6 +38,7 @@ import org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern;
public class IndexFieldMapper extends MetadataFieldMapper { public class IndexFieldMapper extends MetadataFieldMapper {
@ -151,14 +152,43 @@ public class IndexFieldMapper extends MetadataFieldMapper {
+ " vs. " + values); + " vs. " + values);
} }
@Override
public Query prefixQuery(String value,
@Nullable MultiTermQuery.RewriteMethod method,
QueryShardContext context) {
String indexName = context.getFullyQualifiedIndex().getName();
if (indexName.startsWith(value)) {
return Queries.newMatchAllQuery();
} else {
return Queries.newMatchNoDocsQuery("The index [" + indexName +
"] doesn't match the provided prefix [" + value + "].");
}
}
@Override
public Query regexpQuery(String value, int flags, int maxDeterminizedStates,
MultiTermQuery.RewriteMethod method, QueryShardContext context) {
String indexName = context.getFullyQualifiedIndex().getName();
Pattern pattern = Regex.compile(value, Regex.flagsToString(flags));
if (pattern.matcher(indexName).matches()) {
return Queries.newMatchAllQuery();
} else {
return Queries.newMatchNoDocsQuery("The index [" + indexName +
"] doesn't match the provided pattern [" + value + "].");
}
}
@Override @Override
public Query wildcardQuery(String value, public Query wildcardQuery(String value,
@Nullable MultiTermQuery.RewriteMethod method, @Nullable MultiTermQuery.RewriteMethod method,
QueryShardContext context) { QueryShardContext context) {
if (isSameIndex(value, context.getFullyQualifiedIndex().getName())) { String indexName = context.getFullyQualifiedIndex().getName();
if (isSameIndex(value, indexName)) {
return Queries.newMatchAllQuery(); return Queries.newMatchAllQuery();
} else { } else {
return Queries.newMatchNoDocsQuery("Index didn't match. Index queried: " + context.index().getName() + " vs. " + value); return Queries.newMatchNoDocsQuery("The index [" + indexName +
"] doesn't match the provided pattern [" + value + "].");
} }
} }

View File

@ -108,7 +108,7 @@ public class RoutingFieldMapper extends MetadataFieldMapper {
} }
} }
static final class RoutingFieldType extends TermBasedFieldType { static final class RoutingFieldType extends StringFieldType {
RoutingFieldType() { RoutingFieldType() {
} }

View File

@ -19,6 +19,14 @@
package org.elasticsearch.index.mapper; package org.elasticsearch.index.mapper;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.util.BytesRef;
public class IgnoredFieldTypeTests extends FieldTypeTestCase { public class IgnoredFieldTypeTests extends FieldTypeTestCase {
@Override @Override
@ -26,4 +34,30 @@ public class IgnoredFieldTypeTests extends FieldTypeTestCase {
return new IgnoredFieldMapper.IgnoredFieldType(); return new IgnoredFieldMapper.IgnoredFieldType();
} }
public void testPrefixQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
Query expected = new PrefixQuery(new Term("field", new BytesRef("foo*")));
assertEquals(expected, ft.prefixQuery("foo*", null, null));
}
public void testRegexpQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
Query expected = new RegexpQuery(new Term("field", new BytesRef("foo?")));
assertEquals(expected, ft.regexpQuery("foo?", 0, 10, null, null));
}
public void testWildcardQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
Query expected = new WildcardQuery(new Term("field", new BytesRef("foo*")));
assertEquals(expected, ft.wildcardQuery("foo*", null, null));
}
} }

View File

@ -18,12 +18,56 @@
*/ */
package org.elasticsearch.index.mapper; package org.elasticsearch.index.mapper;
import org.elasticsearch.index.mapper.IndexFieldMapper; import org.apache.lucene.index.IndexOptions;
import org.elasticsearch.index.mapper.MappedFieldType; import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.query.QueryShardContext;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class IndexFieldTypeTests extends FieldTypeTestCase { public class IndexFieldTypeTests extends FieldTypeTestCase {
@Override @Override
protected MappedFieldType createDefaultFieldType() { protected MappedFieldType createDefaultFieldType() {
return new IndexFieldMapper.IndexFieldType(); return new IndexFieldMapper.IndexFieldType();
} }
public void testPrefixQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new MatchAllDocsQuery(), ft.prefixQuery("ind", null, createContext()));
assertEquals(new MatchNoDocsQuery(), ft.prefixQuery("other_ind", null, createContext()));
}
public void testRegexpQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new MatchAllDocsQuery(), ft.regexpQuery("ind.x", 0, 10, null, createContext()));
assertEquals(new MatchNoDocsQuery(), ft.regexpQuery("ind?x", 0, 10, null, createContext()));
}
public void testWildcardQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new MatchAllDocsQuery(), ft.wildcardQuery("ind*x", null, createContext()));
assertEquals(new MatchNoDocsQuery(), ft.wildcardQuery("other_ind*x", null, createContext()));
}
private QueryShardContext createContext() {
QueryShardContext context = mock(QueryShardContext.class);
Index index = new Index("index", "123");
when(context.getFullyQualifiedIndex()).thenReturn(index);
when(context.index()).thenReturn(index);
return context;
}
} }

View File

@ -18,12 +18,44 @@
*/ */
package org.elasticsearch.index.mapper; package org.elasticsearch.index.mapper;
import org.elasticsearch.index.mapper.MappedFieldType; import org.apache.lucene.index.IndexOptions;
import org.elasticsearch.index.mapper.RoutingFieldMapper; import org.apache.lucene.index.Term;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.util.BytesRef;
public class RoutingFieldTypeTests extends FieldTypeTestCase { public class RoutingFieldTypeTests extends FieldTypeTestCase {
@Override @Override
protected MappedFieldType createDefaultFieldType() { protected MappedFieldType createDefaultFieldType() {
return new RoutingFieldMapper.RoutingFieldType(); return new RoutingFieldMapper.RoutingFieldType();
} }
public void testPrefixQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
Query expected = new PrefixQuery(new Term("field", new BytesRef("foo*")));
assertEquals(expected, ft.prefixQuery("foo*", null, null));
}
public void testRegexpQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
Query expected = new RegexpQuery(new Term("field", new BytesRef("foo?")));
assertEquals(expected, ft.regexpQuery("foo?", 0, 10, null, null));
}
public void testWildcardQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
Query expected = new WildcardQuery(new Term("field", new BytesRef("foo*")));
assertEquals(expected, ft.wildcardQuery("foo*", null, null));
}
} }