/*
* 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.search.aggregations.support;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.LongBitSet;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.fielddata.AbstractSortedSetDocValues;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.bucket.terms.support.IncludeExclude;
import org.elasticsearch.search.aggregations.bucket.terms.support.IncludeExclude.OrdinalsFilter;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.Collections;
import java.util.TreeSet;
public class IncludeExcludeTests extends ESTestCase {
public void testEmptyTermsWithOrds() throws IOException {
IncludeExclude inexcl = new IncludeExclude(
new TreeSet<>(Collections.singleton(new BytesRef("foo"))),
null);
OrdinalsFilter filter = inexcl.convertToOrdinalsFilter(DocValueFormat.RAW);
LongBitSet acceptedOrds = filter.acceptedGlobalOrdinals(DocValues.emptySortedSet());
assertEquals(0, acceptedOrds.length());
inexcl = new IncludeExclude(
null,
new TreeSet<>(Collections.singleton(new BytesRef("foo"))));
filter = inexcl.convertToOrdinalsFilter(DocValueFormat.RAW);
acceptedOrds = filter.acceptedGlobalOrdinals(DocValues.emptySortedSet());
assertEquals(0, acceptedOrds.length());
}
public void testSingleTermWithOrds() throws IOException {
SortedSetDocValues ords = new AbstractSortedSetDocValues() {
boolean consumed = true;
@Override
public boolean advanceExact(int docID) {
consumed = false;
return true;
}
@Override
public long nextOrd() {
if (consumed) {
return SortedSetDocValues.NO_MORE_ORDS;
} else {
consumed = true;
return 0;
}
}
@Override
public BytesRef lookupOrd(long ord) {
assertEquals(0, ord);
return new BytesRef("foo");
}
@Override
public long getValueCount() {
return 1;
}
};
IncludeExclude inexcl = new IncludeExclude(
new TreeSet<>(Collections.singleton(new BytesRef("foo"))),
null);
OrdinalsFilter filter = inexcl.convertToOrdinalsFilter(DocValueFormat.RAW);
LongBitSet acceptedOrds = filter.acceptedGlobalOrdinals(ords);
assertEquals(1, acceptedOrds.length());
assertTrue(acceptedOrds.get(0));
inexcl = new IncludeExclude(
new TreeSet<>(Collections.singleton(new BytesRef("bar"))),
null);
filter = inexcl.convertToOrdinalsFilter(DocValueFormat.RAW);
acceptedOrds = filter.acceptedGlobalOrdinals(ords);
assertEquals(1, acceptedOrds.length());
assertFalse(acceptedOrds.get(0));
inexcl = new IncludeExclude(
new TreeSet<>(Collections.singleton(new BytesRef("foo"))),
new TreeSet<>(Collections.singleton(new BytesRef("foo"))));
filter = inexcl.convertToOrdinalsFilter(DocValueFormat.RAW);
acceptedOrds = filter.acceptedGlobalOrdinals(ords);
assertEquals(1, acceptedOrds.length());
assertFalse(acceptedOrds.get(0));
inexcl = new IncludeExclude(
null, // means everything included
new TreeSet<>(Collections.singleton(new BytesRef("foo"))));
filter = inexcl.convertToOrdinalsFilter(DocValueFormat.RAW);
acceptedOrds = filter.acceptedGlobalOrdinals(ords);
assertEquals(1, acceptedOrds.length());
assertFalse(acceptedOrds.get(0));
}
public void testPartitionedEquals() throws IOException {
IncludeExclude serialized = serialize(new IncludeExclude(3, 20), IncludeExclude.INCLUDE_FIELD);
assertFalse(serialized.isRegexBased());
assertTrue(serialized.isPartitionBased());
IncludeExclude same = new IncludeExclude(3, 20);
assertEquals(serialized, same);
assertEquals(serialized.hashCode(), same.hashCode());
IncludeExclude differentParam1 = new IncludeExclude(4, 20);
assertFalse(serialized.equals(differentParam1));
assertTrue(serialized.hashCode() != differentParam1.hashCode());
IncludeExclude differentParam2 = new IncludeExclude(3, 21);
assertFalse(serialized.equals(differentParam2));
assertTrue(serialized.hashCode() != differentParam2.hashCode());
}
public void testExactIncludeValuesEquals() throws IOException {
String[] incValues = { "a", "b" };
String[] differentIncValues = { "a", "c" };
IncludeExclude serialized = serialize(new IncludeExclude(incValues, null), IncludeExclude.INCLUDE_FIELD);
assertFalse(serialized.isPartitionBased());
assertFalse(serialized.isRegexBased());
IncludeExclude same = new IncludeExclude(incValues, null);
assertEquals(serialized, same);
assertEquals(serialized.hashCode(), same.hashCode());
IncludeExclude different = new IncludeExclude(differentIncValues, null);
assertFalse(serialized.equals(different));
assertTrue(serialized.hashCode() != different.hashCode());
}
public void testExactExcludeValuesEquals() throws IOException {
String[] excValues = { "a", "b" };
String[] differentExcValues = { "a", "c" };
IncludeExclude serialized = serialize(new IncludeExclude(null, excValues), IncludeExclude.EXCLUDE_FIELD);
assertFalse(serialized.isPartitionBased());
assertFalse(serialized.isRegexBased());
IncludeExclude same = new IncludeExclude(null, excValues);
assertEquals(serialized, same);
assertEquals(serialized.hashCode(), same.hashCode());
IncludeExclude different = new IncludeExclude(null, differentExcValues);
assertFalse(serialized.equals(different));
assertTrue(serialized.hashCode() != different.hashCode());
}
public void testRegexInclude() throws IOException {
String incRegex = "foo.*";
String differentRegex = "bar.*";
IncludeExclude serialized = serialize(new IncludeExclude(incRegex, null), IncludeExclude.INCLUDE_FIELD);
assertFalse(serialized.isPartitionBased());
assertTrue(serialized.isRegexBased());
IncludeExclude same = new IncludeExclude(incRegex, null);
assertEquals(serialized, same);
assertEquals(serialized.hashCode(), same.hashCode());
IncludeExclude different = new IncludeExclude(differentRegex, null);
assertFalse(serialized.equals(different));
assertTrue(serialized.hashCode() != different.hashCode());
}
public void testRegexExclude() throws IOException {
String excRegex = "foo.*";
String differentRegex = "bar.*";
IncludeExclude serialized = serialize(new IncludeExclude(null, excRegex), IncludeExclude.EXCLUDE_FIELD);
assertFalse(serialized.isPartitionBased());
assertTrue(serialized.isRegexBased());
IncludeExclude same = new IncludeExclude(null, excRegex);
assertEquals(serialized, same);
assertEquals(serialized.hashCode(), same.hashCode());
IncludeExclude different = new IncludeExclude(null, differentRegex);
assertFalse(serialized.equals(different));
assertTrue(serialized.hashCode() != different.hashCode());
}
// Serializes/deserializes an IncludeExclude statement with a single clause
private IncludeExclude serialize(IncludeExclude incExc, ParseField field) throws IOException {
XContentBuilder builder = XContentFactory.contentBuilder(randomFrom(XContentType.values()));
if (randomBoolean()) {
builder.prettyPrint();
}
builder.startObject();
incExc.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endObject();
XContentParser parser = createParser(builder);
XContentParser.Token token = parser.nextToken();
assertEquals(token, XContentParser.Token.START_OBJECT);
token = parser.nextToken();
assertEquals(token, XContentParser.Token.FIELD_NAME);
assertEquals(field.getPreferredName(), parser.currentName());
token = parser.nextToken();
QueryParseContext parseContext = new QueryParseContext(parser);
if (field.getPreferredName().equalsIgnoreCase("include")) {
return IncludeExclude.parseInclude(parser, parseContext);
} else if (field.getPreferredName().equalsIgnoreCase("exclude")) {
return IncludeExclude.parseExclude(parser, parseContext);
} else {
throw new IllegalArgumentException(
"Unexpected field name serialized in test: " + field.getPreferredName());
}
}
public void testRegexIncludeAndExclude() throws IOException {
String incRegex = "foo.*";
String excRegex = "football";
String differentExcRegex = "foosball";
IncludeExclude serialized = serializeMixedRegex(new IncludeExclude(incRegex, excRegex));
assertFalse(serialized.isPartitionBased());
assertTrue(serialized.isRegexBased());
IncludeExclude same = new IncludeExclude(incRegex, excRegex);
assertEquals(serialized, same);
assertEquals(serialized.hashCode(), same.hashCode());
IncludeExclude different = new IncludeExclude(incRegex, differentExcRegex);
assertFalse(serialized.equals(different));
assertTrue(serialized.hashCode() != different.hashCode());
}
// Serializes/deserializes the IncludeExclude statement with include AND
// exclude clauses
private IncludeExclude serializeMixedRegex(IncludeExclude incExc) throws IOException {
XContentBuilder builder = XContentFactory.contentBuilder(randomFrom(XContentType.values()));
if (randomBoolean()) {
builder.prettyPrint();
}
builder.startObject();
incExc.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endObject();
XContentParser parser = createParser(builder);
QueryParseContext parseContext = new QueryParseContext(parser);
XContentParser.Token token = parser.nextToken();
assertEquals(token, XContentParser.Token.START_OBJECT);
IncludeExclude inc = null;
IncludeExclude exc = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
assertEquals(XContentParser.Token.FIELD_NAME, token);
if (IncludeExclude.INCLUDE_FIELD.match(parser.currentName())) {
token = parser.nextToken();
inc = IncludeExclude.parseInclude(parser, parseContext);
} else if (IncludeExclude.EXCLUDE_FIELD.match(parser.currentName())) {
token = parser.nextToken();
exc = IncludeExclude.parseExclude(parser, parseContext);
} else {
throw new IllegalArgumentException("Unexpected field name serialized in test: " + parser.currentName());
}
}
assertNotNull(inc);
assertNotNull(exc);
// Include and Exclude clauses are parsed independently and then merged
return IncludeExclude.merge(inc, exc);
}
}