Return nothing instead of everything in MLT if no field is supported.

Today due the optimizations in the boolean query builder we adjust
a pure negative query with a 'match_all'. This is not the desired
behavior in the MLT API if all the fields in a document are unsupported.
If that happens today we return all documents but the one MLT is
executed on.

Closes #3453
This commit is contained in:
Simon Willnauer 2013-08-07 12:16:27 +02:00
parent 73c038fb48
commit 7f0115ba9a
4 changed files with 42 additions and 2 deletions

View File

@ -183,6 +183,7 @@ public class TransportMoreLikeThisAction extends TransportAction<MoreLikeThisReq
// exclude myself // exclude myself
Term uidTerm = docMapper.uidMapper().term(request.type(), request.id()); Term uidTerm = docMapper.uidMapper().term(request.type(), request.id());
boolBuilder.mustNot(termQuery(uidTerm.field(), uidTerm.text())); boolBuilder.mustNot(termQuery(uidTerm.field(), uidTerm.text()));
boolBuilder.adjustPureNegative(false);
} catch (Throwable e) { } catch (Throwable e) {
listener.onFailure(e); listener.onFailure(e);
return; return;

View File

@ -19,6 +19,7 @@
package org.elasticsearch.index.query; package org.elasticsearch.index.query;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException; import java.io.IOException;
@ -42,6 +43,8 @@ public class BoolQueryBuilder extends BaseQueryBuilder implements BoostableQuery
private String minimumShouldMatch; private String minimumShouldMatch;
private Boolean adjustPureNegative;
/** /**
* Adds a query that <b>must</b> appear in the matching documents. * Adds a query that <b>must</b> appear in the matching documents.
*/ */
@ -120,6 +123,16 @@ public class BoolQueryBuilder extends BaseQueryBuilder implements BoostableQuery
return !mustClauses.isEmpty() || !mustNotClauses.isEmpty() || !shouldClauses.isEmpty(); return !mustClauses.isEmpty() || !mustNotClauses.isEmpty() || !shouldClauses.isEmpty();
} }
/**
* If a boolean query contains only negative ("must not") clauses should the
* BooleanQuery be enhanced with a {@link MatchAllDocsQuery} in order to act
* as a pure exclude. The default is <code>true</code>.
*/
public BoolQueryBuilder adjustPureNegative(boolean adjustPureNegative) {
this.adjustPureNegative = adjustPureNegative;
return this;
}
@Override @Override
protected void doXContent(XContentBuilder builder, Params params) throws IOException { protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject("bool"); builder.startObject("bool");
@ -135,6 +148,9 @@ public class BoolQueryBuilder extends BaseQueryBuilder implements BoostableQuery
if (minimumShouldMatch != null) { if (minimumShouldMatch != null) {
builder.field("minimum_should_match", minimumShouldMatch); builder.field("minimum_should_match", minimumShouldMatch);
} }
if (adjustPureNegative != null) {
builder.field("adjust_pure_negative", adjustPureNegative);
}
builder.endObject(); builder.endObject();
} }

View File

@ -60,7 +60,7 @@ public class BoolQueryParser implements QueryParser {
String minimumShouldMatch = null; String minimumShouldMatch = null;
List<BooleanClause> clauses = newArrayList(); List<BooleanClause> clauses = newArrayList();
boolean adjustPureNegative = true;
String currentFieldName = null; String currentFieldName = null;
XContentParser.Token token; XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
@ -119,6 +119,8 @@ public class BoolQueryParser implements QueryParser {
boost = parser.floatValue(); boost = parser.floatValue();
} else if ("minimum_number_should_match".equals(currentFieldName) || "minimumNumberShouldMatch".equals(currentFieldName)) { } else if ("minimum_number_should_match".equals(currentFieldName) || "minimumNumberShouldMatch".equals(currentFieldName)) {
minimumShouldMatch = parser.textOrNull(); minimumShouldMatch = parser.textOrNull();
} else if ("adjust_pure_negative".equals(currentFieldName) || "adjustPureNegative".equals(currentFieldName)) {
adjustPureNegative = parser.booleanValue();
} else { } else {
throw new QueryParsingException(parseContext.index(), "[bool] query does not support [" + currentFieldName + "]"); throw new QueryParsingException(parseContext.index(), "[bool] query does not support [" + currentFieldName + "]");
} }
@ -135,6 +137,6 @@ public class BoolQueryParser implements QueryParser {
} }
query.setBoost(boost); query.setBoost(boost);
Queries.applyMinimumShouldMatch(query, minimumShouldMatch); Queries.applyMinimumShouldMatch(query, minimumShouldMatch);
return optimizeQuery(fixNegativeQueryIfNeeded(query)); return optimizeQuery(adjustPureNegative ? fixNegativeQueryIfNeeded(query) : query);
} }
} }

View File

@ -60,6 +60,27 @@ public class MoreLikeThisActionTests extends AbstractSharedClusterTest {
} }
@Test
public void testSimpleMoreLikeOnLongField() throws Exception {
logger.info("Creating index test");
createIndex("test");
logger.info("Running Cluster Health");
assertThat(ensureGreen(), equalTo(ClusterHealthStatus.GREEN));
logger.info("Indexing...");
client().index(indexRequest("test").type("type1").id("1").source(jsonBuilder().startObject().field("some_long", 1367484649580l).endObject())).actionGet();
client().index(indexRequest("test").type("type2").id("2").source(jsonBuilder().startObject().field("some_long", 0).endObject())).actionGet();
client().index(indexRequest("test").type("type1").id("3").source(jsonBuilder().startObject().field("some_long", -666).endObject())).actionGet();
client().admin().indices().refresh(refreshRequest()).actionGet();
logger.info("Running moreLikeThis");
SearchResponse mltResponse = client().moreLikeThis(moreLikeThisRequest("test").type("type1").id("1").minTermFreq(1).minDocFreq(1)).actionGet();
assertHitCount(mltResponse, 0l);
}
@Test @Test
public void testMoreLikeThisWithAliases() throws Exception { public void testMoreLikeThisWithAliases() throws Exception {
logger.info("Creating index test"); logger.info("Creating index test");