diff --git a/src/main/java/org/elasticsearch/index/query/SpanNotQueryBuilder.java b/src/main/java/org/elasticsearch/index/query/SpanNotQueryBuilder.java index ce9d53fe04c..cb8d1f929eb 100644 --- a/src/main/java/org/elasticsearch/index/query/SpanNotQueryBuilder.java +++ b/src/main/java/org/elasticsearch/index/query/SpanNotQueryBuilder.java @@ -33,6 +33,12 @@ public class SpanNotQueryBuilder extends BaseQueryBuilder implements SpanQueryBu private SpanQueryBuilder exclude; + private int dist = -1; + + private int pre = -1; + + private int post = -1; + private float boost = -1; private String queryName; @@ -47,6 +53,21 @@ public class SpanNotQueryBuilder extends BaseQueryBuilder implements SpanQueryBu return this; } + public SpanNotQueryBuilder dist(int dist) { + this.dist = dist; + return this; + } + + public SpanNotQueryBuilder pre(int pre) { + this.pre = pre; + return this; + } + + public SpanNotQueryBuilder post(int post) { + this.post = post; + return this; + } + public SpanNotQueryBuilder boost(float boost) { this.boost = boost; return this; @@ -68,11 +89,25 @@ public class SpanNotQueryBuilder extends BaseQueryBuilder implements SpanQueryBu if (exclude == null) { throw new ElasticsearchIllegalArgumentException("Must specify exclude when using spanNot query"); } + + if ((dist != -1 && (pre != -1 || post != -1)) || (pre != -1 && post == -1) || (pre == -1 && post != -1)) { + throw new ElasticSearchIllegalArgumentException("spanNot can either use [dist] or [pre] & [post] (or none)"); + } + builder.startObject(SpanNotQueryParser.NAME); builder.field("include"); include.toXContent(builder, params); builder.field("exclude"); exclude.toXContent(builder, params); + if (dist != -1) { + builder.field("dist", dist); + } + if (pre != -1) { + builder.field("pre", pre); + } + if (post != -1) { + builder.field("post", post); + } if (boost != -1) { builder.field("boost", boost); } diff --git a/src/main/java/org/elasticsearch/index/query/SpanNotQueryParser.java b/src/main/java/org/elasticsearch/index/query/SpanNotQueryParser.java index 269973e272f..5deb945d458 100644 --- a/src/main/java/org/elasticsearch/index/query/SpanNotQueryParser.java +++ b/src/main/java/org/elasticsearch/index/query/SpanNotQueryParser.java @@ -52,6 +52,11 @@ public class SpanNotQueryParser implements QueryParser { SpanQuery include = null; SpanQuery exclude = null; + + int dist = -1; + int pre = -1; + int post = -1; + String queryName = null; String currentFieldName = null; @@ -76,7 +81,13 @@ public class SpanNotQueryParser implements QueryParser { 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(); @@ -91,8 +102,19 @@ public class SpanNotQueryParser implements QueryParser { if (exclude == null) { throw new QueryParsingException(parseContext.index(), "spanNot must have [exclude] span query clause"); } + if ((dist != -1 && (pre != -1 || post != -1)) || (pre != -1 && post == -1) || (pre == -1 && post != -1)) { + throw new QueryParsingException(parseContext.index(), "spanNot can either use [dist] or [pre] & [post] (or none)"); + } + + SpanNotQuery query; + if (pre != -1 && post != -1) { + query = new SpanNotQuery(include, exclude, pre, post); + } else if (dist != -1) { + 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); diff --git a/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java b/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java index 126a20abab8..00c7488d233 100644 --- a/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java +++ b/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java @@ -1526,6 +1526,48 @@ public class SimpleQueryTests extends ElasticsearchIntegrationTest { 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")