|
@@ -18,14 +18,18 @@
|
|
|
*/
|
|
|
package org.elasticsearch.search.aggregations.metrics.tophits;
|
|
|
|
|
|
+import org.apache.lucene.analysis.core.KeywordAnalyzer;
|
|
|
import org.apache.lucene.document.Document;
|
|
|
import org.apache.lucene.document.Field;
|
|
|
import org.apache.lucene.document.SortedSetDocValuesField;
|
|
|
import org.apache.lucene.index.DirectoryReader;
|
|
|
import org.apache.lucene.index.IndexReader;
|
|
|
import org.apache.lucene.index.RandomIndexWriter;
|
|
|
+import org.apache.lucene.queryparser.classic.QueryParser;
|
|
|
import org.apache.lucene.search.IndexSearcher;
|
|
|
import org.apache.lucene.search.MatchAllDocsQuery;
|
|
|
+import org.apache.lucene.search.MatchNoDocsQuery;
|
|
|
+import org.apache.lucene.search.Query;
|
|
|
import org.apache.lucene.store.Directory;
|
|
|
import org.apache.lucene.util.BytesRef;
|
|
|
import org.elasticsearch.index.mapper.KeywordFieldMapper;
|
|
@@ -33,55 +37,114 @@ import org.elasticsearch.index.mapper.MappedFieldType;
|
|
|
import org.elasticsearch.index.mapper.Uid;
|
|
|
import org.elasticsearch.index.mapper.UidFieldMapper;
|
|
|
import org.elasticsearch.search.SearchHits;
|
|
|
+import org.elasticsearch.search.aggregations.Aggregation;
|
|
|
+import org.elasticsearch.search.aggregations.AggregationBuilder;
|
|
|
import org.elasticsearch.search.aggregations.AggregatorTestCase;
|
|
|
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
|
|
|
import org.elasticsearch.search.sort.SortOrder;
|
|
|
|
|
|
+import java.io.IOException;
|
|
|
+
|
|
|
+import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
|
|
|
+import static org.elasticsearch.search.aggregations.AggregationBuilders.topHits;
|
|
|
+
|
|
|
public class TopHitsAggregatorTests extends AggregatorTestCase {
|
|
|
+ public void testTopLevel() throws Exception {
|
|
|
+ Aggregation result;
|
|
|
+ if (randomBoolean()) {
|
|
|
+ result = testCase(new MatchAllDocsQuery(), topHits("_name").sort("string", SortOrder.DESC));
|
|
|
+ } else {
|
|
|
+ Query query = new QueryParser("string", new KeywordAnalyzer()).parse("d^1000 c^100 b^10 a^1");
|
|
|
+ result = testCase(query, topHits("_name"));
|
|
|
+ }
|
|
|
+ SearchHits searchHits = ((TopHits) result).getHits();
|
|
|
+ assertEquals(3L, searchHits.getTotalHits());
|
|
|
+ assertEquals("3", searchHits.getAt(0).getId());
|
|
|
+ assertEquals("type", searchHits.getAt(0).getType());
|
|
|
+ assertEquals("2", searchHits.getAt(1).getId());
|
|
|
+ assertEquals("type", searchHits.getAt(1).getType());
|
|
|
+ assertEquals("1", searchHits.getAt(2).getId());
|
|
|
+ assertEquals("type", searchHits.getAt(2).getType());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testNoResults() throws Exception {
|
|
|
+ TopHits result = (TopHits) testCase(new MatchNoDocsQuery(), topHits("_name").sort("string", SortOrder.DESC));
|
|
|
+ SearchHits searchHits = ((TopHits) result).getHits();
|
|
|
+ assertEquals(0L, searchHits.getTotalHits());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Tests {@code top_hits} inside of {@code terms}. While not strictly a unit test this is a fairly common way to run {@code top_hits}
|
|
|
+ * and serves as a good example of running {@code top_hits} inside of another aggregation.
|
|
|
+ */
|
|
|
+ public void testInsideTerms() throws Exception {
|
|
|
+ Aggregation result;
|
|
|
+ if (randomBoolean()) {
|
|
|
+ result = testCase(new MatchAllDocsQuery(),
|
|
|
+ terms("term").field("string")
|
|
|
+ .subAggregation(topHits("top").sort("string", SortOrder.DESC)));
|
|
|
+ } else {
|
|
|
+ Query query = new QueryParser("string", new KeywordAnalyzer()).parse("d^1000 c^100 b^10 a^1");
|
|
|
+ result = testCase(query,
|
|
|
+ terms("term").field("string")
|
|
|
+ .subAggregation(topHits("top")));
|
|
|
+ }
|
|
|
+ Terms terms = (Terms) result;
|
|
|
+
|
|
|
+ // The "a" bucket
|
|
|
+ TopHits hits = (TopHits) terms.getBucketByKey("a").getAggregations().get("top");
|
|
|
+ SearchHits searchHits = (hits).getHits();
|
|
|
+ assertEquals(2L, searchHits.getTotalHits());
|
|
|
+ assertEquals("2", searchHits.getAt(0).getId());
|
|
|
+ assertEquals("1", searchHits.getAt(1).getId());
|
|
|
+
|
|
|
+ // The "b" bucket
|
|
|
+ searchHits = ((TopHits) terms.getBucketByKey("b").getAggregations().get("top")).getHits();
|
|
|
+ assertEquals(2L, searchHits.getTotalHits());
|
|
|
+ assertEquals("3", searchHits.getAt(0).getId());
|
|
|
+ assertEquals("1", searchHits.getAt(1).getId());
|
|
|
|
|
|
- public void testTermsAggregator() throws Exception {
|
|
|
+ // The "c" bucket
|
|
|
+ searchHits = ((TopHits) terms.getBucketByKey("c").getAggregations().get("top")).getHits();
|
|
|
+ assertEquals(1L, searchHits.getTotalHits());
|
|
|
+ assertEquals("2", searchHits.getAt(0).getId());
|
|
|
+
|
|
|
+ // The "d" bucket
|
|
|
+ searchHits = ((TopHits) terms.getBucketByKey("d").getAggregations().get("top")).getHits();
|
|
|
+ assertEquals(1L, searchHits.getTotalHits());
|
|
|
+ assertEquals("3", searchHits.getAt(0).getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ private static final MappedFieldType STRING_FIELD_TYPE = new KeywordFieldMapper.KeywordFieldType();
|
|
|
+ static {
|
|
|
+ STRING_FIELD_TYPE.setName("string");
|
|
|
+ STRING_FIELD_TYPE.setHasDocValues(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Aggregation testCase(Query query, AggregationBuilder builder) throws IOException {
|
|
|
Directory directory = newDirectory();
|
|
|
- RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory);
|
|
|
- Document document = new Document();
|
|
|
- document.add(new Field(UidFieldMapper.NAME, Uid.createUid("type", "1"), UidFieldMapper.Defaults.FIELD_TYPE));
|
|
|
- document.add(new SortedSetDocValuesField("string", new BytesRef("a")));
|
|
|
- document.add(new SortedSetDocValuesField("string", new BytesRef("b")));
|
|
|
- indexWriter.addDocument(document);
|
|
|
- document = new Document();
|
|
|
- document.add(new Field(UidFieldMapper.NAME, Uid.createUid("type", "2"), UidFieldMapper.Defaults.FIELD_TYPE));
|
|
|
- document.add(new SortedSetDocValuesField("string", new BytesRef("c")));
|
|
|
- document.add(new SortedSetDocValuesField("string", new BytesRef("a")));
|
|
|
- indexWriter.addDocument(document);
|
|
|
- document = new Document();
|
|
|
- document.add(new Field(UidFieldMapper.NAME, Uid.createUid("type", "3"), UidFieldMapper.Defaults.FIELD_TYPE));
|
|
|
- document.add(new SortedSetDocValuesField("string", new BytesRef("b")));
|
|
|
- document.add(new SortedSetDocValuesField("string", new BytesRef("d")));
|
|
|
- indexWriter.addDocument(document);
|
|
|
- indexWriter.close();
|
|
|
+ RandomIndexWriter iw = new RandomIndexWriter(random(), directory);
|
|
|
+ iw.addDocument(document("1", "a", "b"));
|
|
|
+ iw.addDocument(document("2", "c", "a"));
|
|
|
+ iw.addDocument(document("3", "b", "d"));
|
|
|
+ iw.close();
|
|
|
|
|
|
IndexReader indexReader = DirectoryReader.open(directory);
|
|
|
IndexSearcher indexSearcher = newSearcher(indexReader, true, true);
|
|
|
|
|
|
- MappedFieldType fieldType = new KeywordFieldMapper.KeywordFieldType();
|
|
|
- fieldType.setName("string");
|
|
|
- fieldType.setHasDocValues(true );
|
|
|
- TopHitsAggregationBuilder aggregationBuilder = new TopHitsAggregationBuilder("_name");
|
|
|
- aggregationBuilder.sort("string", SortOrder.DESC);
|
|
|
- try (TopHitsAggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType)){
|
|
|
- aggregator.preCollection();
|
|
|
- indexSearcher.search(new MatchAllDocsQuery(), aggregator);
|
|
|
- aggregator.postCollection();
|
|
|
- TopHits topHits = (TopHits) aggregator.buildAggregation(0L);
|
|
|
- SearchHits searchHits = topHits.getHits();
|
|
|
- assertEquals(3L, searchHits.getTotalHits());
|
|
|
- assertEquals("3", searchHits.getAt(0).getId());
|
|
|
- assertEquals("type", searchHits.getAt(0).getType());
|
|
|
- assertEquals("2", searchHits.getAt(1).getId());
|
|
|
- assertEquals("type", searchHits.getAt(1).getType());
|
|
|
- assertEquals("1", searchHits.getAt(2).getId());
|
|
|
- assertEquals("type", searchHits.getAt(2).getType());
|
|
|
- }
|
|
|
+ Aggregation result = searchAndReduce(indexSearcher, query, builder, STRING_FIELD_TYPE);
|
|
|
indexReader.close();
|
|
|
directory.close();
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
+ private Document document(String id, String... stringValues) {
|
|
|
+ Document document = new Document();
|
|
|
+ document.add(new Field(UidFieldMapper.NAME, Uid.createUid("type", id), UidFieldMapper.Defaults.FIELD_TYPE));
|
|
|
+ for (String stringValue : stringValues) {
|
|
|
+ document.add(new Field("string", stringValue, STRING_FIELD_TYPE));
|
|
|
+ document.add(new SortedSetDocValuesField("string", new BytesRef(stringValue)));
|
|
|
+ }
|
|
|
+ return document;
|
|
|
+ }
|
|
|
}
|