Query DSL: Allow to provide pattern field names when using query_string query, closes #511.

This commit is contained in:
kimchy 2010-11-13 02:26:14 +02:00
parent 6839cc6965
commit 38d77f8cf3
6 changed files with 112 additions and 18 deletions

View File

@ -29,6 +29,13 @@ import java.util.regex.Pattern;
*/
public class Regex {
/**
* Is the str a simple match pattern.
*/
public static boolean isSimpleMatchPattern(String str) {
return str.indexOf('*') != -1;
}
/**
* Match a String against the given pattern, supporting the following simple
* pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an

View File

@ -20,14 +20,13 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.analysis.Analyzer;
import org.elasticsearch.common.collect.ImmutableList;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.collect.Iterables;
import org.elasticsearch.common.collect.UnmodifiableIterator;
import org.elasticsearch.common.collect.*;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.util.concurrent.Immutable;
import org.elasticsearch.index.analysis.FieldNameAnalyzer;
import java.util.Map;
import java.util.Set;
import static org.elasticsearch.common.collect.Lists.*;
import static org.elasticsearch.common.collect.Maps.*;
@ -119,6 +118,20 @@ public class DocumentFieldMappers implements Iterable<FieldMapper> {
return fullNameFieldMappers.get(fullName);
}
public Set<String> simpleMatchToIndexNames(String pattern) {
Set<String> fields = Sets.newHashSet();
for (FieldMapper fieldMapper : fieldMappers) {
if (Regex.simpleMatch(pattern, fieldMapper.names().fullName())) {
fields.add(fieldMapper.names().indexName());
} else if (Regex.simpleMatch(pattern, fieldMapper.names().indexName())) {
fields.add(fieldMapper.names().name());
} else if (Regex.simpleMatch(pattern, fieldMapper.names().name())) {
fields.add(fieldMapper.names().indexName());
}
}
return fields;
}
/**
* Tries to find first based on {@link #fullName(String)}, then by {@link #indexName(String)}, and last
* by {@link #name(String)}.

View File

@ -26,9 +26,11 @@ import org.apache.lucene.index.Term;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.TermsFilter;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.collect.Sets;
import org.elasticsearch.common.collect.UnmodifiableIterator;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadSafe;
import org.elasticsearch.env.Environment;
@ -46,6 +48,8 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import static org.elasticsearch.common.collect.MapBuilder.*;
@ -280,6 +284,44 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
return null;
}
public Set<String> simpleMatchToIndexNames(String pattern) {
int dotIndex = pattern.indexOf('.');
if (dotIndex != -1) {
String possibleType = pattern.substring(0, dotIndex);
DocumentMapper possibleDocMapper = mappers.get(possibleType);
if (possibleDocMapper != null) {
Set<String> typedFields = Sets.newHashSet();
for (String indexName : possibleDocMapper.mappers().simpleMatchToIndexNames(pattern)) {
typedFields.add(possibleType + "." + indexName);
}
return typedFields;
}
}
Set<String> fields = Sets.newHashSet();
for (Map.Entry<String, FieldMappers> entry : fullNameFieldMappers.entrySet()) {
if (Regex.simpleMatch(pattern, entry.getKey())) {
for (FieldMapper mapper : entry.getValue()) {
fields.add(mapper.names().indexName());
}
}
}
for (Map.Entry<String, FieldMappers> entry : indexNameFieldMappers.entrySet()) {
if (Regex.simpleMatch(pattern, entry.getKey())) {
for (FieldMapper mapper : entry.getValue()) {
fields.add(mapper.names().indexName());
}
}
}
for (Map.Entry<String, FieldMappers> entry : nameFieldMappers.entrySet()) {
if (Regex.simpleMatch(pattern, entry.getKey())) {
for (FieldMapper mapper : entry.getValue()) {
fields.add(mapper.names().indexName());
}
}
}
return fields;
}
/**
* Same as {@link #smartName(String)}, except it returns just the field mappers.
*/

View File

@ -28,6 +28,7 @@ import org.elasticsearch.cache.query.parser.QueryParserCache;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.trove.ExtTObjectFloatHashMap;
import org.elasticsearch.common.xcontent.XContentParser;
@ -95,12 +96,25 @@ public class QueryStringQueryParser extends AbstractIndexComponent implements XC
if (qpSettings.fields() == null) {
qpSettings.fields(Lists.<String>newArrayList());
}
qpSettings.fields().add(fField);
if (fBoost != -1) {
if (qpSettings.boosts() == null) {
qpSettings.boosts(new ExtTObjectFloatHashMap<String>().defaultReturnValue(1.0f));
if (Regex.isSimpleMatchPattern(fField)) {
for (String field : parseContext.mapperService().simpleMatchToIndexNames(fField)) {
qpSettings.fields().add(field);
if (fBoost != -1) {
if (qpSettings.boosts() == null) {
qpSettings.boosts(new ExtTObjectFloatHashMap<String>().defaultReturnValue(1.0f));
}
qpSettings.boosts().put(field, fBoost);
}
}
} else {
qpSettings.fields().add(fField);
if (fBoost != -1) {
if (qpSettings.boosts() == null) {
qpSettings.boosts(new ExtTObjectFloatHashMap<String>().defaultReturnValue(1.0f));
}
qpSettings.boosts().put(fField, fBoost);
}
qpSettings.boosts().put(fField, fBoost);
}
}
}

View File

@ -140,6 +140,17 @@ public class SimpleIndexQueryParserTests {
assertThat(((TermQuery) bQuery.clauses().get(1).getQuery()).getTerm(), equalTo(new Term("name", "test")));
}
@Test public void testQueryStringFieldsMatch() throws Exception {
IndexQueryParser queryParser = queryParser();
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/query-fields-match.json");
Query parsedQuery = queryParser.parse(query).query();
assertThat(parsedQuery, instanceOf(BooleanQuery.class));
BooleanQuery bQuery = (BooleanQuery) parsedQuery;
assertThat(bQuery.clauses().size(), equalTo(2));
assertThat(((TermQuery) bQuery.clauses().get(0).getQuery()).getTerm(), equalTo(new Term("name.first", "test")));
assertThat(((TermQuery) bQuery.clauses().get(1).getQuery()).getTerm(), equalTo(new Term("name.last", "test")));
}
@Test public void testQueryStringFields2Builder() throws Exception {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(queryString("test").field("content").field("name").useDisMax(true)).query();
@ -400,7 +411,7 @@ public class SimpleIndexQueryParserTests {
@Test public void testPrefixFilteredQueryBuilder() throws IOException {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(filtered(termQuery("name.first", "shay"), prefixFilter("name.first", "sh"))).query();
Query parsedQuery = queryParser.parse(filteredQuery(termQuery("name.first", "shay"), prefixFilter("name.first", "sh"))).query();
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
PrefixFilter prefixFilter = (PrefixFilter) filteredQuery.getFilter();
@ -507,7 +518,7 @@ public class SimpleIndexQueryParserTests {
@Test public void testRangeFilteredQueryBuilder() throws IOException {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(filtered(termQuery("name.first", "shay"), rangeFilter("age").from(23).to(54).includeLower(true).includeUpper(false))).query();
Query parsedQuery = queryParser.parse(filteredQuery(termQuery("name.first", "shay"), rangeFilter("age").from(23).to(54).includeLower(true).includeUpper(false))).query();
// since age is automatically registered in data, we encode it as numeric
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
Filter filter = ((FilteredQuery) parsedQuery).getFilter();
@ -554,7 +565,7 @@ public class SimpleIndexQueryParserTests {
@Test public void testNumericRangeFilteredQueryBuilder() throws IOException {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(filtered(termQuery("name.first", "shay"), numericRangeFilter("age").from(23).to(54).includeLower(true).includeUpper(false))).query();
Query parsedQuery = queryParser.parse(filteredQuery(termQuery("name.first", "shay"), numericRangeFilter("age").from(23).to(54).includeLower(true).includeUpper(false))).query();
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
Filter filter = ((FilteredQuery) parsedQuery).getFilter();
assertThat(filter, instanceOf(NumericRangeFieldDataFilter.class));
@ -594,7 +605,7 @@ public class SimpleIndexQueryParserTests {
@Test public void testAndFilteredQueryBuilder() throws IOException {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(filtered(matchAllQuery(), andFilter(termFilter("name.first", "shay1"), termFilter("name.first", "shay4")))).query();
Query parsedQuery = queryParser.parse(filteredQuery(matchAllQuery(), andFilter(termFilter("name.first", "shay1"), termFilter("name.first", "shay4")))).query();
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
@ -646,7 +657,7 @@ public class SimpleIndexQueryParserTests {
@Test public void testOrFilteredQueryBuilder() throws IOException {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(filtered(matchAllQuery(), orFilter(termFilter("name.first", "shay1"), termFilter("name.first", "shay4")))).query();
Query parsedQuery = queryParser.parse(filteredQuery(matchAllQuery(), orFilter(termFilter("name.first", "shay1"), termFilter("name.first", "shay4")))).query();
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
@ -684,7 +695,7 @@ public class SimpleIndexQueryParserTests {
@Test public void testNotFilteredQueryBuilder() throws IOException {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(filtered(matchAllQuery(), notFilter(termFilter("name.first", "shay1")))).query();
Query parsedQuery = queryParser.parse(filteredQuery(matchAllQuery(), notFilter(termFilter("name.first", "shay1")))).query();
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
@ -751,7 +762,7 @@ public class SimpleIndexQueryParserTests {
@Test public void testFilteredQueryBuilder() throws IOException {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(filtered(termQuery("name.first", "shay"), termFilter("name.last", "banon"))).query();
Query parsedQuery = queryParser.parse(filteredQuery(termQuery("name.first", "shay"), termFilter("name.last", "banon"))).query();
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
assertThat(((TermQuery) filteredQuery.getQuery()).getTerm(), equalTo(new Term("name.first", "shay")));
@ -834,7 +845,7 @@ public class SimpleIndexQueryParserTests {
@Test public void testTermsFilterQueryBuilder() throws Exception {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(filtered(termQuery("name.first", "shay"), termsFilter("name.last", "banon", "kimchy"))).query();
Query parsedQuery = queryParser.parse(filteredQuery(termQuery("name.first", "shay"), termsFilter("name.last", "banon", "kimchy"))).query();
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
assertThat(filteredQuery.getFilter(), instanceOf(TermsFilter.class));
@ -1037,7 +1048,7 @@ public class SimpleIndexQueryParserTests {
@Test public void testQueryFilterBuilder() throws Exception {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(filtered(termQuery("name.first", "shay"), queryFilter(termQuery("name.last", "banon")))).query();
Query parsedQuery = queryParser.parse(filteredQuery(termQuery("name.first", "shay"), queryFilter(termQuery("name.last", "banon")))).query();
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
QueryWrapperFilter queryWrapperFilter = (QueryWrapperFilter) filteredQuery.getFilter();

View File

@ -0,0 +1,7 @@
{
query_string : {
fields : ["name.*"],
use_dis_max : false,
query: "test"
}
}