|
18 | 18 | import org.apache.lucene.store.Directory; |
19 | 19 | import org.apache.lucene.util.BytesRef; |
20 | 20 | import org.elasticsearch.common.CheckedConsumer; |
| 21 | +import org.elasticsearch.common.settings.Settings; |
| 22 | +import org.elasticsearch.index.mapper.IpFieldMapper; |
21 | 23 | import org.elasticsearch.index.mapper.MappedFieldType; |
22 | 24 | import org.elasticsearch.index.mapper.NumberFieldMapper; |
23 | 25 | import org.elasticsearch.index.mapper.TextFieldMapper; |
| 26 | +import org.elasticsearch.script.MockScriptEngine; |
| 27 | +import org.elasticsearch.script.Script; |
| 28 | +import org.elasticsearch.script.ScriptEngine; |
| 29 | +import org.elasticsearch.script.ScriptModule; |
| 30 | +import org.elasticsearch.script.ScriptService; |
| 31 | +import org.elasticsearch.script.ScriptType; |
24 | 32 | import org.elasticsearch.search.aggregations.AggregationBuilder; |
25 | 33 | import org.elasticsearch.search.aggregations.AggregatorTestCase; |
26 | 34 | import org.elasticsearch.search.aggregations.bucket.terms.Terms; |
27 | 35 | import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; |
28 | 36 | import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregator; |
| 37 | +import org.elasticsearch.search.aggregations.support.CoreValuesSourceType; |
29 | 38 | import org.elasticsearch.search.aggregations.support.ValueType; |
| 39 | +import org.elasticsearch.search.aggregations.support.ValuesSourceType; |
| 40 | +import org.elasticsearch.search.lookup.LeafDocLookup; |
30 | 41 |
|
31 | 42 | import java.io.IOException; |
32 | 43 | import java.util.List; |
| 44 | +import java.util.Map; |
| 45 | +import java.util.Set; |
33 | 46 | import java.util.function.Consumer; |
| 47 | +import java.util.function.Function; |
34 | 48 |
|
| 49 | +import static java.util.Collections.emptyMap; |
| 50 | +import static java.util.Collections.emptySet; |
35 | 51 | import static java.util.Collections.singleton; |
| 52 | +import static java.util.Collections.singletonList; |
| 53 | +import static java.util.Collections.singletonMap; |
| 54 | +import static java.util.stream.Collectors.toList; |
36 | 55 |
|
37 | 56 | public class StringStatsAggregatorTests extends AggregatorTestCase { |
38 | 57 |
|
| 58 | + private static final String VALUE_SCRIPT_NAME = "value_script"; |
| 59 | + private static final String FIELD_SCRIPT_NAME = "field_script"; |
| 60 | + |
39 | 61 | private void testCase(Query query, |
40 | 62 | CheckedConsumer<RandomIndexWriter, IOException> buildIndex, |
41 | 63 | Consumer<InternalStringStats> verify) throws IOException { |
@@ -119,6 +141,32 @@ public void testUnmappedWithMissingField() throws IOException { |
119 | 141 | }, null); |
120 | 142 | } |
121 | 143 |
|
| 144 | + public void testMissing() throws IOException { |
| 145 | + final TextFieldMapper.TextFieldType fieldType = new TextFieldMapper.TextFieldType(); |
| 146 | + fieldType.setName("text"); |
| 147 | + fieldType.setFielddata(true); |
| 148 | + |
| 149 | + final StringStatsAggregationBuilder aggregationBuilder = new StringStatsAggregationBuilder("_name") |
| 150 | + .field(fieldType.name()) |
| 151 | + .missing("b"); |
| 152 | + |
| 153 | + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { |
| 154 | + iw.addDocument(singleton(new TextField(fieldType.name(), "a", Field.Store.NO))); |
| 155 | + iw.addDocument(emptySet()); |
| 156 | + iw.addDocument(singleton(new TextField(fieldType.name(), "a", Field.Store.NO))); |
| 157 | + iw.addDocument(emptySet()); |
| 158 | + }, stats -> { |
| 159 | + assertEquals(4, stats.getCount()); |
| 160 | + assertEquals(1, stats.getMaxLength()); |
| 161 | + assertEquals(1, stats.getMinLength()); |
| 162 | + assertEquals(1.0, stats.getAvgLength(), 0); |
| 163 | + assertEquals(2, stats.getDistribution().size()); |
| 164 | + assertEquals(0.5, stats.getDistribution().get("a"), 0); |
| 165 | + assertEquals(0.5, stats.getDistribution().get("b"), 0); |
| 166 | + assertEquals(1.0, stats.getEntropy(), 0); |
| 167 | + }, fieldType); |
| 168 | + } |
| 169 | + |
122 | 170 | public void testSingleValuedField() throws IOException { |
123 | 171 | testCase(new MatchAllDocsQuery(), iw -> { |
124 | 172 | for(int i=0; i < 10; i++) { |
@@ -258,4 +306,144 @@ public void testNestedAggregation() throws IOException { |
258 | 306 | directory.close(); |
259 | 307 | } |
260 | 308 |
|
| 309 | + public void testValueScriptSingleValuedField() throws IOException { |
| 310 | + final TextFieldMapper.TextFieldType fieldType = new TextFieldMapper.TextFieldType(); |
| 311 | + fieldType.setName("text"); |
| 312 | + fieldType.setFielddata(true); |
| 313 | + |
| 314 | + final StringStatsAggregationBuilder aggregationBuilder = new StringStatsAggregationBuilder("_name") |
| 315 | + .field(fieldType.name()) |
| 316 | + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, VALUE_SCRIPT_NAME, emptyMap())); |
| 317 | + |
| 318 | + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { |
| 319 | + iw.addDocument(singleton(new TextField(fieldType.name(), "b", Field.Store.NO))); |
| 320 | + iw.addDocument(singleton(new TextField(fieldType.name(), "b", Field.Store.NO))); |
| 321 | + }, stats -> { |
| 322 | + assertEquals(2, stats.getCount()); |
| 323 | + assertEquals(2, stats.getMaxLength()); |
| 324 | + assertEquals(2, stats.getMinLength()); |
| 325 | + assertEquals(2.0, stats.getAvgLength(), 0); |
| 326 | + assertEquals(2, stats.getDistribution().size()); |
| 327 | + assertEquals(0.5, stats.getDistribution().get("a"), 0); |
| 328 | + assertEquals(0.5, stats.getDistribution().get("b"), 0); |
| 329 | + assertEquals(1.0, stats.getEntropy(), 0); |
| 330 | + }, fieldType); |
| 331 | + } |
| 332 | + |
| 333 | + public void testValueScriptMultiValuedField() throws IOException { |
| 334 | + final TextFieldMapper.TextFieldType fieldType = new TextFieldMapper.TextFieldType(); |
| 335 | + fieldType.setName("text"); |
| 336 | + fieldType.setFielddata(true); |
| 337 | + |
| 338 | + final StringStatsAggregationBuilder aggregationBuilder = new StringStatsAggregationBuilder("_name") |
| 339 | + .field(fieldType.name()) |
| 340 | + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, VALUE_SCRIPT_NAME, emptyMap())); |
| 341 | + |
| 342 | + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { |
| 343 | + iw.addDocument(Set.of( |
| 344 | + new TextField(fieldType.name(), "b", Field.Store.NO), |
| 345 | + new TextField(fieldType.name(), "c", Field.Store.NO) |
| 346 | + )); |
| 347 | + iw.addDocument(Set.of( |
| 348 | + new TextField(fieldType.name(), "b", Field.Store.NO), |
| 349 | + new TextField(fieldType.name(), "c", Field.Store.NO) |
| 350 | + )); |
| 351 | + }, stats -> { |
| 352 | + assertEquals(4, stats.getCount()); |
| 353 | + assertEquals(2, stats.getMaxLength()); |
| 354 | + assertEquals(2, stats.getMinLength()); |
| 355 | + assertEquals(2.0, stats.getAvgLength(), 0); |
| 356 | + assertEquals(3, stats.getDistribution().size()); |
| 357 | + assertEquals(0.5, stats.getDistribution().get("a"), 0); |
| 358 | + assertEquals(0.25, stats.getDistribution().get("b"), 0); |
| 359 | + assertEquals(0.25, stats.getDistribution().get("c"), 0); |
| 360 | + assertEquals(1.5, stats.getEntropy(), 0); |
| 361 | + }, fieldType); |
| 362 | + } |
| 363 | + |
| 364 | + public void testFieldScriptSingleValuedField() throws IOException { |
| 365 | + final TextFieldMapper.TextFieldType fieldType = new TextFieldMapper.TextFieldType(); |
| 366 | + fieldType.setName("text"); |
| 367 | + fieldType.setFielddata(true); |
| 368 | + |
| 369 | + final StringStatsAggregationBuilder aggregationBuilder = new StringStatsAggregationBuilder("_name") |
| 370 | + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, FIELD_SCRIPT_NAME, singletonMap("field", fieldType.name()))); |
| 371 | + |
| 372 | + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { |
| 373 | + iw.addDocument(singleton(new TextField(fieldType.name(), "b", Field.Store.NO))); |
| 374 | + iw.addDocument(singleton(new TextField(fieldType.name(), "b", Field.Store.NO))); |
| 375 | + }, stats -> { |
| 376 | + assertEquals(2, stats.getCount()); |
| 377 | + assertEquals(2, stats.getMaxLength()); |
| 378 | + assertEquals(2, stats.getMinLength()); |
| 379 | + assertEquals(2.0, stats.getAvgLength(), 0); |
| 380 | + assertEquals(2, stats.getDistribution().size()); |
| 381 | + assertEquals(0.5, stats.getDistribution().get("a"), 0); |
| 382 | + assertEquals(0.5, stats.getDistribution().get("b"), 0); |
| 383 | + assertEquals(1.0, stats.getEntropy(), 0); |
| 384 | + }, fieldType); |
| 385 | + } |
| 386 | + |
| 387 | + public void testFieldScriptMultiValuedField() throws IOException { |
| 388 | + final TextFieldMapper.TextFieldType fieldType = new TextFieldMapper.TextFieldType(); |
| 389 | + fieldType.setName("text"); |
| 390 | + fieldType.setFielddata(true); |
| 391 | + |
| 392 | + final StringStatsAggregationBuilder aggregationBuilder = new StringStatsAggregationBuilder("_name") |
| 393 | + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, FIELD_SCRIPT_NAME, singletonMap("field", fieldType.name()))); |
| 394 | + |
| 395 | + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { |
| 396 | + iw.addDocument(Set.of( |
| 397 | + new TextField(fieldType.name(), "b", Field.Store.NO), |
| 398 | + new TextField(fieldType.name(), "c", Field.Store.NO) |
| 399 | + )); |
| 400 | + iw.addDocument(Set.of( |
| 401 | + new TextField(fieldType.name(), "b", Field.Store.NO), |
| 402 | + new TextField(fieldType.name(), "c", Field.Store.NO) |
| 403 | + )); |
| 404 | + }, stats -> { |
| 405 | + assertEquals(4, stats.getCount()); |
| 406 | + assertEquals(2, stats.getMaxLength()); |
| 407 | + assertEquals(2, stats.getMinLength()); |
| 408 | + assertEquals(2.0, stats.getAvgLength(), 0); |
| 409 | + assertEquals(3, stats.getDistribution().size()); |
| 410 | + assertEquals(0.5, stats.getDistribution().get("a"), 0); |
| 411 | + assertEquals(0.25, stats.getDistribution().get("b"), 0); |
| 412 | + assertEquals(0.25, stats.getDistribution().get("c"), 0); |
| 413 | + assertEquals(1.5, stats.getEntropy(), 0); |
| 414 | + }, fieldType); |
| 415 | + } |
| 416 | + |
| 417 | + @Override |
| 418 | + protected AggregationBuilder createAggBuilderForTypeTest(MappedFieldType fieldType, String fieldName) { |
| 419 | + return new StringStatsAggregationBuilder("_name") |
| 420 | + .field(fieldName); |
| 421 | + } |
| 422 | + |
| 423 | + @Override |
| 424 | + protected List<ValuesSourceType> getSupportedValuesSourceTypes() { |
| 425 | + return singletonList(CoreValuesSourceType.BYTES); |
| 426 | + } |
| 427 | + |
| 428 | + @Override |
| 429 | + protected List<String> unsupportedMappedFieldTypes() { |
| 430 | + return singletonList(IpFieldMapper.CONTENT_TYPE); |
| 431 | + } |
| 432 | + |
| 433 | + @Override |
| 434 | + protected ScriptService getMockScriptService() { |
| 435 | + final Map<String, Function<Map<String, Object>, Object>> scripts = Map.of( |
| 436 | + VALUE_SCRIPT_NAME, vars -> "a" + vars.get("_value"), |
| 437 | + FIELD_SCRIPT_NAME, vars -> { |
| 438 | + final String fieldName = (String) vars.get("field"); |
| 439 | + final LeafDocLookup lookup = (LeafDocLookup) vars.get("doc"); |
| 440 | + return lookup.get(fieldName).stream() |
| 441 | + .map(value -> "a" + value) |
| 442 | + .collect(toList()); |
| 443 | + } |
| 444 | + ); |
| 445 | + final MockScriptEngine engine = new MockScriptEngine(MockScriptEngine.NAME, scripts, emptyMap()); |
| 446 | + final Map<String, ScriptEngine> engines = singletonMap(engine.getType(), engine); |
| 447 | + return new ScriptService(Settings.EMPTY, engines, ScriptModule.CORE_CONTEXTS); |
| 448 | + } |
261 | 449 | } |
0 commit comments