Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,19 @@
*/
public class SpanNotQueryBuilder extends BaseQueryBuilder implements SpanQueryBuilder, BoostableQueryBuilder<SpanNotQueryBuilder> {

public static final int NOT_SET = -1;

private SpanQueryBuilder include;

private SpanQueryBuilder exclude;

private float boost = -1;
private int dist = NOT_SET;

private int pre = NOT_SET;

private int post = NOT_SET;

private float boost = NOT_SET;

private String queryName;

Expand All @@ -47,13 +55,30 @@ public SpanNotQueryBuilder exclude(SpanQueryBuilder exclude) {
return this;
}

public SpanNotQueryBuilder dist(int dist) {
this.dist = dist;
return this;
}

public SpanNotQueryBuilder pre(int pre) {
this.pre = (pre >=0) ? pre : 0;
return this;
}

public SpanNotQueryBuilder post(int post) {
this.post = (post >= 0) ? post : 0;
return this;
}

public SpanNotQueryBuilder boost(float boost) {
this.boost = boost;
return this;
}

/**
* Sets the query name for the filter that can be used when searching for matched_filters per hit.
* @param queryName The query name
* @return this
*/
public SpanNotQueryBuilder queryName(String queryName) {
this.queryName = queryName;
Expand All @@ -68,12 +93,33 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
if (exclude == null) {
throw new ElasticsearchIllegalArgumentException("Must specify exclude when using spanNot query");
}

if (dist != NOT_SET && (pre != NOT_SET || post != NOT_SET)) {
throw new ElasticsearchIllegalArgumentException("spanNot can either use [dist] or [pre] & [post] (or none)");
}

// set appropriate defaults
if (pre != NOT_SET && post == NOT_SET) {
post = 0;
} else if (pre == NOT_SET && post != NOT_SET){
pre = 0;
}

builder.startObject(SpanNotQueryParser.NAME);
builder.field("include");
include.toXContent(builder, params);
builder.field("exclude");
exclude.toXContent(builder, params);
if (boost != -1) {
if (dist != NOT_SET) {
builder.field("dist", dist);
}
if (pre != NOT_SET) {
builder.field("pre", pre);
}
if (post != NOT_SET) {
builder.field("post", post);
}
if (boost != NOT_SET) {
builder.field("boost", boost);
}
if (queryName != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public class SpanNotQueryParser implements QueryParser {

public static final String NAME = "span_not";

public static final int NOT_SET = -1;

@Inject
public SpanNotQueryParser() {
}
Expand All @@ -52,6 +54,11 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars

SpanQuery include = null;
SpanQuery exclude = null;

int dist = NOT_SET;
int pre = NOT_SET;
int post = NOT_SET;

String queryName = null;

String currentFieldName = null;
Expand All @@ -76,7 +83,13 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
throw new QueryParsingException(parseContext.index(), "[span_not] query does not support [" + currentFieldName + "]");
}
} else {
if ("boost".equals(currentFieldName)) {
if ("dist".equals(currentFieldName)) {
dist = parser.intValue();
} else if ("pre".equals(currentFieldName)) {
pre = parser.intValue();
} else if ("post".equals(currentFieldName)) {
post = parser.intValue();
} else if ("boost".equals(currentFieldName)) {
boost = parser.floatValue();
} else if ("_name".equals(currentFieldName)) {
queryName = parser.text();
Expand All @@ -91,8 +104,19 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
if (exclude == null) {
throw new QueryParsingException(parseContext.index(), "spanNot must have [exclude] span query clause");
}
if (dist != NOT_SET && (pre != NOT_SET || post != NOT_SET)) {
throw new QueryParsingException(parseContext.index(), "spanNot can either use [dist] or [pre] & [post] (or none)");
}

SpanNotQuery query;
if (pre != NOT_SET && post != NOT_SET) {
query = new SpanNotQuery(include, exclude, pre, post);
} else if (dist != NOT_SET) {
query = new SpanNotQuery(include, exclude, dist);
} else {
query = new SpanNotQuery(include, exclude);
}

SpanNotQuery query = new SpanNotQuery(include, exclude);
query.setBoost(boost);
if (queryName != null) {
parseContext.addNamedQuery(queryName, query);
Expand Down
42 changes: 42 additions & 0 deletions src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -1526,6 +1526,48 @@ public void testSpanMultiTermQuery() throws ElasticsearchException, IOException
assertHitCount(response, 3);
}

@Test
public void testSpanNot() throws ElasticsearchException, IOException, ExecutionException, InterruptedException {
createIndex("test");
ensureGreen();

client().prepareIndex("test", "test", "1").setSource("description", "the quick brown fox jumped over the lazy dog").get();
client().prepareIndex("test", "test", "2").setSource("description", "the quick black fox leaped over the sleeping dog").get();
refresh();

SearchResponse searchResponse = client().prepareSearch("test")
.setQuery(spanNotQuery().include(spanNearQuery()
.clause(QueryBuilders.spanTermQuery("description", "quick"))
.clause(QueryBuilders.spanTermQuery("description", "fox")).slop(1)).exclude(spanTermQuery("description", "brown"))).get();
assertHitCount(searchResponse, 1l);

searchResponse = client().prepareSearch("test")
.setQuery(spanNotQuery().include(spanNearQuery()
.clause(QueryBuilders.spanTermQuery("description", "quick"))
.clause(QueryBuilders.spanTermQuery("description", "fox")).slop(1)).exclude(spanTermQuery("description", "sleeping")).dist(5)).get();
assertHitCount(searchResponse, 1l);

searchResponse = client().prepareSearch("test")
.setQuery(spanNotQuery().include(spanNearQuery()
.clause(QueryBuilders.spanTermQuery("description", "quick"))
.clause(QueryBuilders.spanTermQuery("description", "fox")).slop(1)).exclude(spanTermQuery("description", "jumped")).pre(1).post(1)).get();
assertHitCount(searchResponse, 1l);

SearchRequestBuilder builder = client().prepareSearch("test")
.setQuery(spanNotQuery().include(spanNearQuery()
.clause(QueryBuilders.spanTermQuery("description", "quick"))
.clause(QueryBuilders.spanTermQuery("description", "fox")).slop(1)).exclude(spanTermQuery("description", "jumped")).dist(2).pre(2));
boolean caught = false;
try {
builder.execute();
} catch (ElasticsearchException e) {
assertTrue("ElasticsearchIllegalArgumentException should have been caught", e.getDetailedMessage().endsWith("spanNot can either use [dist] or [pre] & [post] (or none)"));
caught = true;
} finally {
assertTrue("ElasticsearchIllegalArgumentException should have been caught", caught);
}
}

@Test
public void testSimpleDFSQuery() throws ElasticsearchException, IOException {
assertAcked(prepareCreate("test")
Expand Down