/*
* 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.search;
import org.apache.lucene.index.MultiReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.test.ESSingleNodeTestCase;
import java.io.IOException;
public class NestedHelperTests extends ESSingleNodeTestCase {
IndexService indexService;
MapperService mapperService;
@Override
public void setUp() throws Exception {
super.setUp();
XContentBuilder mapping = XContentFactory.jsonBuilder().startObject()
.startObject("type")
.startObject("properties")
.startObject("foo")
.field("type", "keyword")
.endObject()
.startObject("foo2")
.field("type", "long")
.endObject()
.startObject("nested1")
.field("type", "nested")
.startObject("properties")
.startObject("foo")
.field("type", "keyword")
.endObject()
.startObject("foo2")
.field("type", "long")
.endObject()
.endObject()
.endObject()
.startObject("nested2")
.field("type", "nested")
.field("include_in_parent", true)
.startObject("properties")
.startObject("foo")
.field("type", "keyword")
.endObject()
.startObject("foo2")
.field("type", "long")
.endObject()
.endObject()
.endObject()
.startObject("nested3")
.field("type", "nested")
.field("include_in_root", true)
.startObject("properties")
.startObject("foo")
.field("type", "keyword")
.endObject()
.startObject("foo2")
.field("type", "long")
.endObject()
.endObject()
.endObject()
.endObject()
.endObject().endObject();
indexService = createIndex("index", Settings.EMPTY, "type", mapping);
mapperService = indexService.mapperService();
}
public void testMatchAll() {
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(new MatchAllDocsQuery()));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(new MatchAllDocsQuery(), "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(new MatchAllDocsQuery(), "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(new MatchAllDocsQuery(), "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(new MatchAllDocsQuery(), "nested_missing"));
}
public void testMatchNo() {
assertFalse(new NestedHelper(mapperService).mightMatchNestedDocs(new MatchNoDocsQuery()));
assertFalse(new NestedHelper(mapperService).mightMatchNonNestedDocs(new MatchNoDocsQuery(), "nested1"));
assertFalse(new NestedHelper(mapperService).mightMatchNonNestedDocs(new MatchNoDocsQuery(), "nested2"));
assertFalse(new NestedHelper(mapperService).mightMatchNonNestedDocs(new MatchNoDocsQuery(), "nested3"));
assertFalse(new NestedHelper(mapperService).mightMatchNonNestedDocs(new MatchNoDocsQuery(), "nested_missing"));
}
public void testTermQuery() {
Query termQuery = mapperService.fullName("foo").termQuery("bar", null);
assertFalse(new NestedHelper(mapperService).mightMatchNestedDocs(termQuery));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested_missing"));
termQuery = mapperService.fullName("nested1.foo").termQuery("bar", null);
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(termQuery));
assertFalse(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested_missing"));
termQuery = mapperService.fullName("nested2.foo").termQuery("bar", null);
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(termQuery));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested_missing"));
termQuery = mapperService.fullName("nested3.foo").termQuery("bar", null);
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(termQuery));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(termQuery, "nested_missing"));
}
public void testRangeQuery() {
Query rangeQuery = mapperService.fullName("foo2").rangeQuery(2, 5, true, true, null);
assertFalse(new NestedHelper(mapperService).mightMatchNestedDocs(rangeQuery));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested_missing"));
rangeQuery = mapperService.fullName("nested1.foo2").rangeQuery(2, 5, true, true, null);
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(rangeQuery));
assertFalse(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested_missing"));
rangeQuery = mapperService.fullName("nested2.foo2").rangeQuery(2, 5, true, true, null);
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(rangeQuery));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested_missing"));
rangeQuery = mapperService.fullName("nested3.foo2").rangeQuery(2, 5, true, true, null);
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(rangeQuery));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested_missing"));
}
public void testDisjunction() {
BooleanQuery bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("foo", "bar")), Occur.SHOULD)
.add(new TermQuery(new Term("foo", "baz")), Occur.SHOULD)
.build();
assertFalse(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested1"));
bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested1.foo", "bar")), Occur.SHOULD)
.add(new TermQuery(new Term("nested1.foo", "baz")), Occur.SHOULD)
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertFalse(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested1"));
bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested2.foo", "bar")), Occur.SHOULD)
.add(new TermQuery(new Term("nested2.foo", "baz")), Occur.SHOULD)
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested2"));
bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested3.foo", "bar")), Occur.SHOULD)
.add(new TermQuery(new Term("nested3.foo", "baz")), Occur.SHOULD)
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested3"));
bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("foo", "bar")), Occur.SHOULD)
.add(new MatchAllDocsQuery(), Occur.SHOULD)
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested1"));
bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested1.foo", "bar")), Occur.SHOULD)
.add(new MatchAllDocsQuery(), Occur.SHOULD)
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested1"));
bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested2.foo", "bar")), Occur.SHOULD)
.add(new MatchAllDocsQuery(), Occur.SHOULD)
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested2"));
bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested3.foo", "bar")), Occur.SHOULD)
.add(new MatchAllDocsQuery(), Occur.SHOULD)
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested3"));
}
private static Occur requiredOccur() {
return random().nextBoolean() ? Occur.MUST : Occur.FILTER;
}
public void testConjunction() {
BooleanQuery bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("foo", "bar")), requiredOccur())
.add(new MatchAllDocsQuery(), requiredOccur())
.build();
assertFalse(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested1"));
bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested1.foo", "bar")), requiredOccur())
.add(new MatchAllDocsQuery(), requiredOccur())
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertFalse(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested1"));
bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested2.foo", "bar")), requiredOccur())
.add(new MatchAllDocsQuery(), requiredOccur())
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested2"));
bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested3.foo", "bar")), requiredOccur())
.add(new MatchAllDocsQuery(), requiredOccur())
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested3"));
bq = new BooleanQuery.Builder()
.add(new MatchAllDocsQuery(), requiredOccur())
.add(new MatchAllDocsQuery(), requiredOccur())
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested1"));
bq = new BooleanQuery.Builder()
.add(new MatchAllDocsQuery(), requiredOccur())
.add(new MatchAllDocsQuery(), requiredOccur())
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested1"));
bq = new BooleanQuery.Builder()
.add(new MatchAllDocsQuery(), requiredOccur())
.add(new MatchAllDocsQuery(), requiredOccur())
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested2"));
bq = new BooleanQuery.Builder()
.add(new MatchAllDocsQuery(), requiredOccur())
.add(new MatchAllDocsQuery(), requiredOccur())
.build();
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(bq));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(bq, "nested3"));
}
public void testNested() throws IOException {
QueryShardContext context = indexService.newQueryShardContext(0, new MultiReader(), () -> 0);
NestedQueryBuilder queryBuilder = new NestedQueryBuilder("nested1", new MatchAllQueryBuilder(), ScoreMode.Avg);
ESToParentBlockJoinQuery query = (ESToParentBlockJoinQuery) queryBuilder.toQuery(context);
Query expectedChildQuery = new BooleanQuery.Builder()
.add(new MatchAllDocsQuery(), Occur.MUST)
// we automatically add a filter since the inner query might match non-nested docs
.add(new TermQuery(new Term("_type", "__nested1")), Occur.FILTER)
.build();
assertEquals(expectedChildQuery, query.getChildQuery());
assertFalse(new NestedHelper(mapperService).mightMatchNestedDocs(query));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested_missing"));
queryBuilder = new NestedQueryBuilder("nested1", new TermQueryBuilder("nested1.foo", "bar"), ScoreMode.Avg);
query = (ESToParentBlockJoinQuery) queryBuilder.toQuery(context);
// this time we do not add a filter since the inner query only matches inner docs
expectedChildQuery = new TermQuery(new Term("nested1.foo", "bar"));
assertEquals(expectedChildQuery, query.getChildQuery());
assertFalse(new NestedHelper(mapperService).mightMatchNestedDocs(query));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested_missing"));
queryBuilder = new NestedQueryBuilder("nested2", new TermQueryBuilder("nested2.foo", "bar"), ScoreMode.Avg);
query = (ESToParentBlockJoinQuery) queryBuilder.toQuery(context);
// we need to add the filter again because of include_in_parent
expectedChildQuery = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested2.foo", "bar")), Occur.MUST)
.add(new TermQuery(new Term("_type", "__nested2")), Occur.FILTER)
.build();
assertEquals(expectedChildQuery, query.getChildQuery());
assertFalse(new NestedHelper(mapperService).mightMatchNestedDocs(query));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested_missing"));
queryBuilder = new NestedQueryBuilder("nested3", new TermQueryBuilder("nested3.foo", "bar"), ScoreMode.Avg);
query = (ESToParentBlockJoinQuery) queryBuilder.toQuery(context);
// we need to add the filter again because of include_in_root
expectedChildQuery = new BooleanQuery.Builder()
.add(new TermQuery(new Term("nested3.foo", "bar")), Occur.MUST)
.add(new TermQuery(new Term("_type", "__nested3")), Occur.FILTER)
.build();
assertEquals(expectedChildQuery, query.getChildQuery());
assertFalse(new NestedHelper(mapperService).mightMatchNestedDocs(query));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(query, "nested_missing"));
}
}