/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.query;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.spans.SpanNotQuery;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.test.AbstractQueryTestCase;
import java.io.IOException;
import static org.elasticsearch.index.query.QueryBuilders.spanNearQuery;
import static org.elasticsearch.index.query.QueryBuilders.spanTermQuery;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
public class SpanNotQueryBuilderTests extends AbstractQueryTestCase<SpanNotQueryBuilder> {
@Override
protected SpanNotQueryBuilder doCreateTestQueryBuilder() {
SpanTermQueryBuilder[] spanTermQueries = new SpanTermQueryBuilderTests().createSpanTermQueryBuilders(2);
SpanNotQueryBuilder queryBuilder = new SpanNotQueryBuilder(spanTermQueries[0], spanTermQueries[1]);
if (randomBoolean()) {
// also test negative values, they should implicitly be changed to 0
queryBuilder.dist(randomIntBetween(-2, 10));
} else {
if (randomBoolean()) {
queryBuilder.pre(randomIntBetween(-2, 10));
}
if (randomBoolean()) {
queryBuilder.post(randomIntBetween(-2, 10));
}
}
return queryBuilder;
}
@Override
protected void doAssertLuceneQuery(SpanNotQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException {
assertThat(query, instanceOf(SpanNotQuery.class));
SpanNotQuery spanNotQuery = (SpanNotQuery) query;
assertThat(spanNotQuery.getExclude(), equalTo(queryBuilder.excludeQuery().toQuery(context.getQueryShardContext())));
assertThat(spanNotQuery.getInclude(), equalTo(queryBuilder.includeQuery().toQuery(context.getQueryShardContext())));
}
public void testIllegalArgument() {
SpanTermQueryBuilder spanTermQuery = new SpanTermQueryBuilder("field", "value");
expectThrows(IllegalArgumentException.class, () -> new SpanNotQueryBuilder(null, spanTermQuery));
expectThrows(IllegalArgumentException.class, () -> new SpanNotQueryBuilder(spanTermQuery, null));
}
public void testDist() {
SpanNotQueryBuilder builder = new SpanNotQueryBuilder(new SpanTermQueryBuilder("name1", "value1"), new SpanTermQueryBuilder("name2", "value2"));
assertThat(builder.pre(), equalTo(0));
assertThat(builder.post(), equalTo(0));
builder.dist(-4);
assertThat(builder.pre(), equalTo(0));
assertThat(builder.post(), equalTo(0));
builder.dist(4);
assertThat(builder.pre(), equalTo(4));
assertThat(builder.post(), equalTo(4));
}
public void testPrePost() {
SpanNotQueryBuilder builder = new SpanNotQueryBuilder(new SpanTermQueryBuilder("name1", "value1"), new SpanTermQueryBuilder("name2", "value2"));
assertThat(builder.pre(), equalTo(0));
assertThat(builder.post(), equalTo(0));
builder.pre(-4).post(-4);
assertThat(builder.pre(), equalTo(0));
assertThat(builder.post(), equalTo(0));
builder.pre(1).post(2);
assertThat(builder.pre(), equalTo(1));
assertThat(builder.post(), equalTo(2));
}
/**
* test correct parsing of `dist` parameter, this should create builder with pre/post set to same value
*/
public void testParseDist() throws IOException {
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject(SpanNotQueryBuilder.NAME);
builder.field("exclude");
spanTermQuery("description", "jumped").toXContent(builder, null);
builder.field("include");
spanNearQuery(QueryBuilders.spanTermQuery("description", "quick"), 1)
.addClause(QueryBuilders.spanTermQuery("description", "fox")).toXContent(builder, null);
builder.field("dist", 3);
builder.endObject();
builder.endObject();
SpanNotQueryBuilder query = (SpanNotQueryBuilder)parseQuery(builder.string());
assertThat(query.pre(), equalTo(3));
assertThat(query.post(), equalTo(3));
assertNotNull(query.includeQuery());
assertNotNull(query.excludeQuery());
}
/**
* test exceptions for three types of broken json, missing include / exclude and both dist and pre/post specified
*/
public void testParserExceptions() throws IOException {
{
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject(SpanNotQueryBuilder.NAME);
builder.field("exclude");
spanTermQuery("description", "jumped").toXContent(builder, null);
builder.field("dist", 2);
builder.endObject();
builder.endObject();
ParsingException e = expectThrows(ParsingException.class, () -> parseQuery(builder.string()));
assertThat(e.getDetailedMessage(), containsString("spanNot must have [include]"));
}
{
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject(SpanNotQueryBuilder.NAME);
builder.field("include");
spanNearQuery(QueryBuilders.spanTermQuery("description", "quick"), 1)
.addClause(QueryBuilders.spanTermQuery("description", "fox")).toXContent(builder, null);
builder.field("dist", 2);
builder.endObject();
builder.endObject();
ParsingException e = expectThrows(ParsingException.class, () -> parseQuery(builder.string()));
assertThat(e.getDetailedMessage(), containsString("spanNot must have [exclude]"));
}
{
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject(SpanNotQueryBuilder.NAME);
builder.field("include");
spanNearQuery(QueryBuilders.spanTermQuery("description", "quick"), 1)
.addClause(QueryBuilders.spanTermQuery("description", "fox")).toXContent(builder, null);
builder.field("exclude");
spanTermQuery("description", "jumped").toXContent(builder, null);
builder.field("dist", 2);
builder.field("pre", 2);
builder.endObject();
builder.endObject();
ParsingException e = expectThrows(ParsingException.class, () -> parseQuery(builder.string()));
assertThat(e.getDetailedMessage(), containsString("spanNot can either use [dist] or [pre] & [post] (or none)"));
}
}
public void testFromJson() throws IOException {
String json =
"{\n" +
" \"span_not\" : {\n" +
" \"include\" : {\n" +
" \"span_term\" : {\n" +
" \"field1\" : {\n" +
" \"value\" : \"hoya\",\n" +
" \"boost\" : 1.0\n" +
" }\n" +
" }\n" +
" },\n" +
" \"exclude\" : {\n" +
" \"span_near\" : {\n" +
" \"clauses\" : [ {\n" +
" \"span_term\" : {\n" +
" \"field1\" : {\n" +
" \"value\" : \"la\",\n" +
" \"boost\" : 1.0\n" +
" }\n" +
" }\n" +
" }, {\n" +
" \"span_term\" : {\n" +
" \"field1\" : {\n" +
" \"value\" : \"hoya\",\n" +
" \"boost\" : 1.0\n" +
" }\n" +
" }\n" +
" } ],\n" +
" \"slop\" : 0,\n" +
" \"in_order\" : true,\n" +
" \"boost\" : 1.0\n" +
" }\n" +
" },\n" +
" \"pre\" : 0,\n" +
" \"post\" : 0,\n" +
" \"boost\" : 1.0\n" +
" }\n" +
"}";
SpanNotQueryBuilder parsed = (SpanNotQueryBuilder) parseQuery(json);
checkGeneratedJson(json, parsed);
assertEquals(json, "hoya", ((SpanTermQueryBuilder) parsed.includeQuery()).value());
assertEquals(json, 2, ((SpanNearQueryBuilder) parsed.excludeQuery()).clauses().size());
}
}