Skip to content

Commit

Permalink
Add Lucene query assertions.
Browse files Browse the repository at this point in the history
  • Loading branch information
Isabel Drost-Fromm committed May 22, 2015
1 parent 00ef2de commit 437b01b
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.elasticsearch.common.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
Expand Down Expand Up @@ -66,6 +67,10 @@ public SimpleQueryStringBuilder(String text) {
this.queryText = text;
}

public String text() {
return this.queryText;
}

/**
* Add a field to run the query against
*/
Expand All @@ -81,7 +86,14 @@ public SimpleQueryStringBuilder field(String field, float boost) {
this.fields.put(field, boost);
return this;
}


/**
* Returns the fields including their respective boosts to run the query against.
* */
public Map<String, Float> fields() {
return Collections.unmodifiableMap(this.fields);
}

/**
* Specify an analyzer to use for the query
*/
Expand Down Expand Up @@ -124,16 +136,28 @@ public SimpleQueryStringBuilder queryName(String queryName) {
this.queryName = queryName;
return this;
}

public String queryName() {
return queryName;
}

public SimpleQueryStringBuilder lowercaseExpandedTerms(boolean lowercaseExpandedTerms) {
this.settings.lowercaseExpandedTerms(lowercaseExpandedTerms);
return this;
}

public boolean lowercaseExpandedTerms() {
return this.settings.lowercaseExpandedTerms;
}

public SimpleQueryStringBuilder locale(Locale locale) {
this.settings.locale(locale);
return this;
}

public Locale locale() {
return this.settings.locale;
}

public SimpleQueryStringBuilder lenient(boolean lenient) {
this.settings.lenient(lenient);
Expand All @@ -149,16 +173,25 @@ public SimpleQueryStringBuilder minimumShouldMatch(String minimumShouldMatch) {
this.minimumShouldMatch = minimumShouldMatch;
return this;
}

public String minimumShouldMatch() {
return minimumShouldMatch;
}

@Override
public Query toQuery(QueryParseContext parseContext) {
// Query text is required
if (queryText == null) {
throw new QueryParsingException(parseContext, "[" + parserName() + "] query text missing");
}
// Use the default field (_all) if no fields specified
if (fields.isEmpty()) {
String field = parseContext.defaultField();
fields.put(field, 1.0F);
}

Analyzer luceneAnalyzer;
// Use standard analyzer by default if none specified
Analyzer luceneAnalyzer;
if (analyzer == null) {
luceneAnalyzer = parseContext.mapperService().searchAnalyzer();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.elasticsearch.index.query.SimpleQueryStringBuilder.Operator;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
Expand Down Expand Up @@ -88,7 +87,7 @@ public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOExcept
String queryName = null;
String field = null;
String minimumShouldMatch = null;
Map<String, Float> fieldsAndWeights = null;
Map<String, Float> fieldsAndWeights = new HashMap<>();
Operator defaultOperator = null;
String analyzerName = null;
int flags = -1;
Expand Down Expand Up @@ -117,10 +116,6 @@ public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOExcept
fField = parser.text();
}

if (fieldsAndWeights == null) {
fieldsAndWeights = new HashMap<>();
}

if (Regex.isSimpleMatchPattern(fField)) {
for (String fieldName : parseContext.mapperService().simpleMatchToIndexNames(fField)) {
fieldsAndWeights.put(fieldName, fBoost);
Expand Down Expand Up @@ -190,15 +185,6 @@ public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOExcept
field = currentFieldName;
}

// Use the default field (_all) if no fields specified
if (fieldsAndWeights == null) {
field = parseContext.defaultField();
}

if (fieldsAndWeights == null) {
fieldsAndWeights = Collections.singletonMap(field, 1.0F);
}

// TODO after switching to writable this should move to a constructor
SimpleQueryStringBuilder qb = new SimpleQueryStringBuilder(queryBody);
qb.queryName(queryName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@

package org.elasticsearch.index.query;

import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.index.query.SimpleQueryStringBuilder.Operator;
import org.junit.Test;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import static org.hamcrest.Matchers.*;

public class SimpleQueryStringBuilderTest extends BaseQueryTestCase<SimpleQueryStringBuilder> {

@Override
Expand All @@ -36,7 +43,7 @@ protected SimpleQueryStringBuilder createTestQueryBuilder() {
if (randomBoolean()) qb.lenient(randomBoolean());
if (randomBoolean()) qb.lowercaseExpandedTerms(randomBoolean());
if (randomBoolean()) qb.locale(randomLocale(getRandom()));
if (randomBoolean()) qb.minimumShouldMatch(randomFrom(new String[]{"1", "10%", "0.1"}));
if (randomBoolean()) qb.minimumShouldMatch(randomFrom(new String[]{"1", "-1", "75%", "-25%", "2<75%", "2<-25%"}));
if (randomBoolean()) qb.analyzer("simple");
if (randomBoolean()) qb.defaultOperator(randomFrom(Operator.AND, Operator.OR));

Expand All @@ -49,17 +56,98 @@ protected SimpleQueryStringBuilder createTestQueryBuilder() {
qb.flags(flags.toArray(new SimpleQueryStringFlag[flags.size()]));
}

if (randomBoolean()) {
qb.field(randomAsciiOfLength(8));
} else {
qb.field(randomAsciiOfLength(8), 2.0f / randomIntBetween(1, 20));
int fieldCount = randomIntBetween(0, 10);
for (int i = 0; i < fieldCount; i++) {
if (randomBoolean()) {
qb.field(randomAsciiOfLength(8));
} else {
qb.field(randomAsciiOfLength(8), 2.0f / randomIntBetween(1, 20));
}
}
return qb;
}

// Check operator handling, and default field handling.
@Test
public void testDefaultOperatorHandling() {
SimpleQueryStringBuilder qb = new SimpleQueryStringBuilder("The quick brown fox.");
BooleanQuery boolQuery = (BooleanQuery) qb.toQuery(createContext());
assertThat(shouldClauses(boolQuery), is(4));

qb.defaultOperator(Operator.AND);
boolQuery = (BooleanQuery) qb.toQuery(createContext());
assertThat(shouldClauses(boolQuery), is(0));

qb.defaultOperator(Operator.OR);
boolQuery = (BooleanQuery) qb.toQuery(createContext());
assertThat(shouldClauses(boolQuery), is(4));
}

/*
* This assumes that Lucene query parsing is being checked already, adding checks only for our parsing extensions.
*
* Also this relies on {@link SimpleQueryStringTests} to test most of the actual functionality of query parsing.
*/
@Override
protected void assertLuceneQuery(SimpleQueryStringBuilder queryBuilder, Query query, QueryParseContext context) throws IOException {
// Huge TODO
if (queryBuilder.queryName() != null) {
Query namedQuery = context.copyNamedFilters().get(queryBuilder.queryName());
assertThat(namedQuery, equalTo(query));
}

if (query instanceof BooleanQuery) {
assertThat(queryBuilder.fields().size(), greaterThan(1));

BooleanQuery boolQuery = (BooleanQuery) query;
if (queryBuilder.lowercaseExpandedTerms()) {
for (BooleanClause clause : boolQuery.clauses()) {
if (clause.getQuery() instanceof TermQuery) {
TermQuery inner = (TermQuery) clause.getQuery();
assertThat(inner.getTerm().bytes().toString(), is(inner.getTerm().bytes().toString().toLowerCase()));
}
}
}

if (queryBuilder.minimumShouldMatch() != null) {
if ("1".equals(queryBuilder.minimumShouldMatch())) {
assertThat(boolQuery.getMinimumNumberShouldMatch(), greaterThan(0));
} else if ("-1".equals(queryBuilder.minimumShouldMatch())) {
assertThat(boolQuery.getMinimumNumberShouldMatch(), greaterThan(0));
} else if ("75%".equals(queryBuilder.minimumShouldMatch())) {
assertThat(boolQuery.getMinimumNumberShouldMatch(), greaterThan(0));
} else if ("-25%".equals(queryBuilder.minimumShouldMatch())) {
assertThat(boolQuery.getMinimumNumberShouldMatch(), greaterThan(0));
} else if ("2<75%".equals(queryBuilder.minimumShouldMatch())) {
if (shouldClauses(boolQuery) > 2) {
assertThat(boolQuery.getMinimumNumberShouldMatch(), greaterThan(0));
}
} else if ("2<-25%".equals(queryBuilder.minimumShouldMatch())) {
if (shouldClauses(boolQuery) > 2) {
assertThat(boolQuery.getMinimumNumberShouldMatch(), greaterThan(0));
}
}
}
} else if (query instanceof TermQuery) {
TermQuery termQuery = (TermQuery) query;
assertThat(termQuery.getTerm().field(), is(queryBuilder.fields().keySet().iterator().next()));

if (queryBuilder.lowercaseExpandedTerms()) {
assertThat(termQuery.getTerm().bytes().toString(), is(termQuery.getTerm().bytes().toString().toLowerCase()));
}

} else if (! (query instanceof MatchNoDocsQuery)){
fail("Encountered lucene query type we do not have a validation implementation for in our SimpleQueryStringBuilderTest");
}
}

private int shouldClauses(BooleanQuery query) {
int result = 0;
for (BooleanClause c : query.clauses()) {
if (c.getOccur() == BooleanClause.Occur.SHOULD) {
result++;
}
}
return result;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import com.carrotsearch.randomizedtesting.rules.TestRuleAdapter;
import com.google.common.base.Predicate;

import org.apache.commons.lang3.EnumUtils;
import org.apache.lucene.uninverting.UninvertingReader;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.LuceneTestCase.SuppressCodecs;
Expand All @@ -53,7 +52,6 @@
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.index.query.SimpleQueryStringFlag;
import org.elasticsearch.test.cache.recycler.MockBigArrays;
import org.elasticsearch.test.cache.recycler.MockPageCacheRecycler;
import org.elasticsearch.test.junit.listeners.LoggingListener;
Expand Down

0 comments on commit 437b01b

Please sign in to comment.