|
@@ -18,24 +18,46 @@ import org.apache.lucene.search.TermInSetQuery;
|
|
|
import org.apache.lucene.store.Directory;
|
|
|
import org.apache.lucene.util.BytesRef;
|
|
|
import org.elasticsearch.common.CheckedConsumer;
|
|
|
+import org.elasticsearch.common.settings.Settings;
|
|
|
+import org.elasticsearch.index.mapper.IpFieldMapper;
|
|
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
|
|
import org.elasticsearch.index.mapper.NumberFieldMapper;
|
|
|
import org.elasticsearch.index.mapper.TextFieldMapper;
|
|
|
+import org.elasticsearch.script.MockScriptEngine;
|
|
|
+import org.elasticsearch.script.Script;
|
|
|
+import org.elasticsearch.script.ScriptEngine;
|
|
|
+import org.elasticsearch.script.ScriptModule;
|
|
|
+import org.elasticsearch.script.ScriptService;
|
|
|
+import org.elasticsearch.script.ScriptType;
|
|
|
import org.elasticsearch.search.aggregations.AggregationBuilder;
|
|
|
import org.elasticsearch.search.aggregations.AggregatorTestCase;
|
|
|
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
|
|
|
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
|
|
|
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregator;
|
|
|
+import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
|
|
|
import org.elasticsearch.search.aggregations.support.ValueType;
|
|
|
+import org.elasticsearch.search.aggregations.support.ValuesSourceType;
|
|
|
+import org.elasticsearch.search.lookup.LeafDocLookup;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
import java.util.function.Consumer;
|
|
|
+import java.util.function.Function;
|
|
|
|
|
|
+import static java.util.Collections.emptyMap;
|
|
|
+import static java.util.Collections.emptySet;
|
|
|
import static java.util.Collections.singleton;
|
|
|
+import static java.util.Collections.singletonList;
|
|
|
+import static java.util.Collections.singletonMap;
|
|
|
+import static java.util.stream.Collectors.toList;
|
|
|
|
|
|
public class StringStatsAggregatorTests extends AggregatorTestCase {
|
|
|
|
|
|
+ private static final String VALUE_SCRIPT_NAME = "value_script";
|
|
|
+ private static final String FIELD_SCRIPT_NAME = "field_script";
|
|
|
+
|
|
|
private void testCase(Query query,
|
|
|
CheckedConsumer<RandomIndexWriter, IOException> buildIndex,
|
|
|
Consumer<InternalStringStats> verify) throws IOException {
|
|
@@ -119,6 +141,32 @@ public class StringStatsAggregatorTests extends AggregatorTestCase {
|
|
|
}, null);
|
|
|
}
|
|
|
|
|
|
+ public void testMissing() throws IOException {
|
|
|
+ final TextFieldMapper.TextFieldType fieldType = new TextFieldMapper.TextFieldType();
|
|
|
+ fieldType.setName("text");
|
|
|
+ fieldType.setFielddata(true);
|
|
|
+
|
|
|
+ final StringStatsAggregationBuilder aggregationBuilder = new StringStatsAggregationBuilder("_name")
|
|
|
+ .field(fieldType.name())
|
|
|
+ .missing("b");
|
|
|
+
|
|
|
+ testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> {
|
|
|
+ iw.addDocument(singleton(new TextField(fieldType.name(), "a", Field.Store.NO)));
|
|
|
+ iw.addDocument(emptySet());
|
|
|
+ iw.addDocument(singleton(new TextField(fieldType.name(), "a", Field.Store.NO)));
|
|
|
+ iw.addDocument(emptySet());
|
|
|
+ }, stats -> {
|
|
|
+ assertEquals(4, stats.getCount());
|
|
|
+ assertEquals(1, stats.getMaxLength());
|
|
|
+ assertEquals(1, stats.getMinLength());
|
|
|
+ assertEquals(1.0, stats.getAvgLength(), 0);
|
|
|
+ assertEquals(2, stats.getDistribution().size());
|
|
|
+ assertEquals(0.5, stats.getDistribution().get("a"), 0);
|
|
|
+ assertEquals(0.5, stats.getDistribution().get("b"), 0);
|
|
|
+ assertEquals(1.0, stats.getEntropy(), 0);
|
|
|
+ }, fieldType);
|
|
|
+ }
|
|
|
+
|
|
|
public void testSingleValuedField() throws IOException {
|
|
|
testCase(new MatchAllDocsQuery(), iw -> {
|
|
|
for(int i=0; i < 10; i++) {
|
|
@@ -258,4 +306,144 @@ public class StringStatsAggregatorTests extends AggregatorTestCase {
|
|
|
directory.close();
|
|
|
}
|
|
|
|
|
|
+ public void testValueScriptSingleValuedField() throws IOException {
|
|
|
+ final TextFieldMapper.TextFieldType fieldType = new TextFieldMapper.TextFieldType();
|
|
|
+ fieldType.setName("text");
|
|
|
+ fieldType.setFielddata(true);
|
|
|
+
|
|
|
+ final StringStatsAggregationBuilder aggregationBuilder = new StringStatsAggregationBuilder("_name")
|
|
|
+ .field(fieldType.name())
|
|
|
+ .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, VALUE_SCRIPT_NAME, emptyMap()));
|
|
|
+
|
|
|
+ testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> {
|
|
|
+ iw.addDocument(singleton(new TextField(fieldType.name(), "b", Field.Store.NO)));
|
|
|
+ iw.addDocument(singleton(new TextField(fieldType.name(), "b", Field.Store.NO)));
|
|
|
+ }, stats -> {
|
|
|
+ assertEquals(2, stats.getCount());
|
|
|
+ assertEquals(2, stats.getMaxLength());
|
|
|
+ assertEquals(2, stats.getMinLength());
|
|
|
+ assertEquals(2.0, stats.getAvgLength(), 0);
|
|
|
+ assertEquals(2, stats.getDistribution().size());
|
|
|
+ assertEquals(0.5, stats.getDistribution().get("a"), 0);
|
|
|
+ assertEquals(0.5, stats.getDistribution().get("b"), 0);
|
|
|
+ assertEquals(1.0, stats.getEntropy(), 0);
|
|
|
+ }, fieldType);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testValueScriptMultiValuedField() throws IOException {
|
|
|
+ final TextFieldMapper.TextFieldType fieldType = new TextFieldMapper.TextFieldType();
|
|
|
+ fieldType.setName("text");
|
|
|
+ fieldType.setFielddata(true);
|
|
|
+
|
|
|
+ final StringStatsAggregationBuilder aggregationBuilder = new StringStatsAggregationBuilder("_name")
|
|
|
+ .field(fieldType.name())
|
|
|
+ .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, VALUE_SCRIPT_NAME, emptyMap()));
|
|
|
+
|
|
|
+ testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> {
|
|
|
+ iw.addDocument(Set.of(
|
|
|
+ new TextField(fieldType.name(), "b", Field.Store.NO),
|
|
|
+ new TextField(fieldType.name(), "c", Field.Store.NO)
|
|
|
+ ));
|
|
|
+ iw.addDocument(Set.of(
|
|
|
+ new TextField(fieldType.name(), "b", Field.Store.NO),
|
|
|
+ new TextField(fieldType.name(), "c", Field.Store.NO)
|
|
|
+ ));
|
|
|
+ }, stats -> {
|
|
|
+ assertEquals(4, stats.getCount());
|
|
|
+ assertEquals(2, stats.getMaxLength());
|
|
|
+ assertEquals(2, stats.getMinLength());
|
|
|
+ assertEquals(2.0, stats.getAvgLength(), 0);
|
|
|
+ assertEquals(3, stats.getDistribution().size());
|
|
|
+ assertEquals(0.5, stats.getDistribution().get("a"), 0);
|
|
|
+ assertEquals(0.25, stats.getDistribution().get("b"), 0);
|
|
|
+ assertEquals(0.25, stats.getDistribution().get("c"), 0);
|
|
|
+ assertEquals(1.5, stats.getEntropy(), 0);
|
|
|
+ }, fieldType);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testFieldScriptSingleValuedField() throws IOException {
|
|
|
+ final TextFieldMapper.TextFieldType fieldType = new TextFieldMapper.TextFieldType();
|
|
|
+ fieldType.setName("text");
|
|
|
+ fieldType.setFielddata(true);
|
|
|
+
|
|
|
+ final StringStatsAggregationBuilder aggregationBuilder = new StringStatsAggregationBuilder("_name")
|
|
|
+ .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, FIELD_SCRIPT_NAME, singletonMap("field", fieldType.name())));
|
|
|
+
|
|
|
+ testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> {
|
|
|
+ iw.addDocument(singleton(new TextField(fieldType.name(), "b", Field.Store.NO)));
|
|
|
+ iw.addDocument(singleton(new TextField(fieldType.name(), "b", Field.Store.NO)));
|
|
|
+ }, stats -> {
|
|
|
+ assertEquals(2, stats.getCount());
|
|
|
+ assertEquals(2, stats.getMaxLength());
|
|
|
+ assertEquals(2, stats.getMinLength());
|
|
|
+ assertEquals(2.0, stats.getAvgLength(), 0);
|
|
|
+ assertEquals(2, stats.getDistribution().size());
|
|
|
+ assertEquals(0.5, stats.getDistribution().get("a"), 0);
|
|
|
+ assertEquals(0.5, stats.getDistribution().get("b"), 0);
|
|
|
+ assertEquals(1.0, stats.getEntropy(), 0);
|
|
|
+ }, fieldType);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testFieldScriptMultiValuedField() throws IOException {
|
|
|
+ final TextFieldMapper.TextFieldType fieldType = new TextFieldMapper.TextFieldType();
|
|
|
+ fieldType.setName("text");
|
|
|
+ fieldType.setFielddata(true);
|
|
|
+
|
|
|
+ final StringStatsAggregationBuilder aggregationBuilder = new StringStatsAggregationBuilder("_name")
|
|
|
+ .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, FIELD_SCRIPT_NAME, singletonMap("field", fieldType.name())));
|
|
|
+
|
|
|
+ testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> {
|
|
|
+ iw.addDocument(Set.of(
|
|
|
+ new TextField(fieldType.name(), "b", Field.Store.NO),
|
|
|
+ new TextField(fieldType.name(), "c", Field.Store.NO)
|
|
|
+ ));
|
|
|
+ iw.addDocument(Set.of(
|
|
|
+ new TextField(fieldType.name(), "b", Field.Store.NO),
|
|
|
+ new TextField(fieldType.name(), "c", Field.Store.NO)
|
|
|
+ ));
|
|
|
+ }, stats -> {
|
|
|
+ assertEquals(4, stats.getCount());
|
|
|
+ assertEquals(2, stats.getMaxLength());
|
|
|
+ assertEquals(2, stats.getMinLength());
|
|
|
+ assertEquals(2.0, stats.getAvgLength(), 0);
|
|
|
+ assertEquals(3, stats.getDistribution().size());
|
|
|
+ assertEquals(0.5, stats.getDistribution().get("a"), 0);
|
|
|
+ assertEquals(0.25, stats.getDistribution().get("b"), 0);
|
|
|
+ assertEquals(0.25, stats.getDistribution().get("c"), 0);
|
|
|
+ assertEquals(1.5, stats.getEntropy(), 0);
|
|
|
+ }, fieldType);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected AggregationBuilder createAggBuilderForTypeTest(MappedFieldType fieldType, String fieldName) {
|
|
|
+ return new StringStatsAggregationBuilder("_name")
|
|
|
+ .field(fieldName);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected List<ValuesSourceType> getSupportedValuesSourceTypes() {
|
|
|
+ return singletonList(CoreValuesSourceType.BYTES);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected List<String> unsupportedMappedFieldTypes() {
|
|
|
+ return singletonList(IpFieldMapper.CONTENT_TYPE);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected ScriptService getMockScriptService() {
|
|
|
+ final Map<String, Function<Map<String, Object>, Object>> scripts = Map.of(
|
|
|
+ VALUE_SCRIPT_NAME, vars -> "a" + vars.get("_value"),
|
|
|
+ FIELD_SCRIPT_NAME, vars -> {
|
|
|
+ final String fieldName = (String) vars.get("field");
|
|
|
+ final LeafDocLookup lookup = (LeafDocLookup) vars.get("doc");
|
|
|
+ return lookup.get(fieldName).stream()
|
|
|
+ .map(value -> "a" + value)
|
|
|
+ .collect(toList());
|
|
|
+ }
|
|
|
+ );
|
|
|
+ final MockScriptEngine engine = new MockScriptEngine(MockScriptEngine.NAME, scripts, emptyMap());
|
|
|
+ final Map<String, ScriptEngine> engines = singletonMap(engine.getType(), engine);
|
|
|
+ return new ScriptService(Settings.EMPTY, engines, ScriptModule.CORE_CONTEXTS);
|
|
|
+ }
|
|
|
}
|